34 #include <IceUtil/Time.h>
35 #include <IceUtil/Timer.h>
52 virtual public IceUtil::TimerTask,
53 virtual public Logging,
54 virtual protected PeriodicTaskIceBase
62 typedef void (
T::*method_type)(void);
82 PeriodicTask(
T* parent, method_type periodicFn,
int periodMs,
bool assureMeanInterval =
false, std::string name =
"",
bool forceSystemTime =
true)
86 functionExecuting =
false;
87 this->assureMeanInterval = assureMeanInterval;
89 last_cpu_total_time = 0;
90 this->periodicFn = periodicFn;
91 this->parent = parent;
95 char* demangled =
nullptr;
97 demangled = abi::__cxa_demangle(
typeid(
T).name(),
nullptr,
nullptr, &
status);
106 intervalMs = periodMs;
107 interval = IceUtil::Time::milliSeconds(periodMs);
109 delayWarningTolerance = IceUtil::Time::milliSeconds(5);
111 workloadList.resize(100, 0.f);
112 setTag(
"PeriodicTask" + this->name);
114 if (customThreadList)
116 customThreadList->addPeriodicTask(
this);
123 appThreadList->addPeriodicTask(
this);
135 appThreadList->removePeriodicTask(
this);
138 if (customThreadList)
140 customThreadList->removePeriodicTask(
this);
160 this->customThreadList = threadList;
164 threadList->addPeriodicTask(
this);
172 std::unique_lock lock(dataMutex);
174 if (app && app->getForbidThreadCreation())
176 throw LocalException() <<
"Thread creation is now allowed in this application at the point in time! Use Application::getInstance()->getThreadPool() instead.";
181 cycleStart = logTime = __now();
182 startTime = logTime.toMicroSeconds();
183 timeExceeded =
false;
184 timer->schedule(
this, IceUtil::Time::milliSeconds(0));
205 delayWarningTolerance = IceUtil::Time::milliSeconds(newToleranceInMilliSeconds);
217 std::unique_lock lock(dataMutex);
219 if (
interval.toMilliSeconds() == intervalInMs)
224 intervalMs = intervalInMs;
225 interval = IceUtil::Time::milliSeconds(intervalInMs);
237 std::unique_lock lock(dataMutex);
268 std::unique_lock lock(mutexFunctionExecuting);
269 return functionExecuting;
277 const PeriodicTaskIceBase* base =
dynamic_cast<const PeriodicTaskIceBase*
>(
this);
282 void runTimerTask()
override
285 std::unique_lock lock(mutexFunctionExecuting);
286 functionExecuting =
true;
290 std::unique_lock lock(dataMutex);
293 idleDuration = __now() - cycleStart - cycleDuration;
294 cycleStart = __now();
295 lastCycleStartTime = cycleStart.toMicroSeconds();
301 (parent->*periodicFn)();
309 std::unique_lock lock2(dataMutex);
310 std::unique_lock lock(mutexFunctionExecuting);
312 cycleDuration = __now() - cycleStart;
313 lastCycleDuration = cycleDuration.toMicroSeconds();
314 __checkTimeslotUsage();
315 __getCPULoad(idleDuration);
317 functionExecuting =
false;
321 void __changeInterval()
323 std::unique_lock lock(mutexFunctionExecuting);
324 startTime = __now().toMicroSeconds();
325 executionCounter = 0;
327 if (functionExecuting)
346 if (assureMeanInterval)
348 newInterval = IceUtil::Time::microSeconds(startTime +
interval.toMicroSeconds() * executionCounter) - __now();
352 newInterval =
interval - IceUtil::Time::microSeconds(lastCycleDuration);
355 if (newInterval.toMicroSeconds() < 0)
357 newInterval = IceUtil::Time::microSeconds(0);
362 timer->schedule(
this, newInterval);
367 void __checkTimeslotUsage()
369 if (
interval + delayWarningTolerance < cycleDuration)
372 executionTime = cycleDuration.toMilliSeconds();
375 float logInterval = 10.0f;
381 <<
" [ms] instead of the requested "
383 <<
" [ms] (this message is only posted every " << logInterval <<
" seconds.)";
384 timeExceeded =
false;
392 double threadCPUUsage = -1;
396 if (clock_gettime(CLOCK_REALTIME, &st) != -1 && clock_gettime(CLOCK_THREAD_CPUTIME_ID, &usage) != -1)
398 double current_cpu_thread_time =
static_cast<double>(usage.tv_sec) +
static_cast<double>(usage.tv_nsec) / 1
'000'000
'000;
399 double current_cpu_total_time = static_cast<double>(st.tv_sec) + static_cast<double>(st.tv_nsec) / 1'000
'000'000;
401 if (last_cpu_total_time != 0)
403 threadCPUUsage = (current_cpu_thread_time - last_cpu_thread_time) / (current_cpu_total_time - last_cpu_total_time);
406 last_cpu_total_time = current_cpu_total_time;
407 last_cpu_thread_time = current_cpu_thread_time;
412 threadCPUUsage =
static_cast<double>(lastCycleDuration) / (lastCycleDuration + idleDuration.toMicroSeconds());
415 if (threadCPUUsage > 0)
417 workloadList.push_back(threadCPUUsage);
419 if (workloadList.size() > 100.f * 1.5f)
421 workloadList.erase(workloadList.begin(), workloadList.begin() + 50);
430 if (timer->getUseSystemTime())
432 return IceUtil::Time::now();
442 method_type periodicFn;
450 IceUtil::Int64 executionTime;
451 IceUtil::Int64 executionCounter;
457 double last_cpu_total_time;
458 double last_cpu_thread_time;
462 bool assureMeanInterval;
464 mutable std::mutex mutexFunctionExecuting;
465 bool functionExecuting;
466 mutable std::mutex dataMutex;