33 #include <IceUtil/Time.h>
34 #include <IceUtil/Timer.h>
53 virtual public IceUtil::TimerTask,
54 virtual public Logging,
55 virtual protected PeriodicTaskIceBase
63 typedef void (
T::*method_type)(void);
84 method_type periodicFn,
86 bool assureMeanInterval =
false,
87 std::string name =
"",
88 bool forceSystemTime =
true)
92 functionExecuting =
false;
93 this->assureMeanInterval = assureMeanInterval;
95 last_cpu_total_time = 0;
96 this->periodicFn = periodicFn;
97 this->parent = parent;
101 char* demangled =
nullptr;
103 demangled = abi::__cxa_demangle(
typeid(
T).name(),
nullptr,
nullptr, &
status);
112 intervalMs = periodMs;
113 interval = IceUtil::Time::milliSeconds(periodMs);
115 delayWarningTolerance = IceUtil::Time::milliSeconds(5);
117 workloadList.resize(100, 0.f);
118 setTag(
"PeriodicTask" + this->name);
120 if (customThreadList)
122 customThreadList->addPeriodicTask(
this);
129 appThreadList->addPeriodicTask(
this);
141 appThreadList->removePeriodicTask(
this);
144 if (customThreadList)
146 customThreadList->removePeriodicTask(
this);
167 this->customThreadList = threadList;
171 threadList->addPeriodicTask(
this);
181 std::unique_lock lock(dataMutex);
183 if (app && app->getForbidThreadCreation())
185 throw LocalException()
186 <<
"Thread creation is now allowed in this application at the point in time! "
187 "Use Application::getInstance()->getThreadPool() instead.";
192 cycleStart = logTime = __now();
193 startTime = logTime.toMicroSeconds();
194 timeExceeded =
false;
195 timer->schedule(
this, IceUtil::Time::milliSeconds(0));
217 delayWarningTolerance = IceUtil::Time::milliSeconds(newToleranceInMilliSeconds);
230 std::unique_lock lock(dataMutex);
232 if (
interval.toMilliSeconds() == intervalInMs)
237 intervalMs = intervalInMs;
238 interval = IceUtil::Time::milliSeconds(intervalInMs);
251 std::unique_lock lock(dataMutex);
284 std::unique_lock lock(mutexFunctionExecuting);
285 return functionExecuting;
291 const PeriodicTaskIceBase&
294 const PeriodicTaskIceBase* base =
dynamic_cast<const PeriodicTaskIceBase*
>(
this);
300 runTimerTask()
override
303 std::unique_lock lock(mutexFunctionExecuting);
304 functionExecuting =
true;
308 std::unique_lock lock(dataMutex);
311 idleDuration = __now() - cycleStart - cycleDuration;
312 cycleStart = __now();
313 lastCycleStartTime = cycleStart.toMicroSeconds();
319 (parent->*periodicFn)();
327 std::unique_lock lock2(dataMutex);
328 std::unique_lock lock(mutexFunctionExecuting);
330 cycleDuration = __now() - cycleStart;
331 lastCycleDuration = cycleDuration.toMicroSeconds();
332 __checkTimeslotUsage();
333 __getCPULoad(idleDuration);
335 functionExecuting =
false;
342 std::unique_lock lock(mutexFunctionExecuting);
343 startTime = __now().toMicroSeconds();
344 executionCounter = 0;
346 if (functionExecuting)
355 <<
" ms." << std::endl;
366 if (assureMeanInterval)
368 newInterval = IceUtil::Time::microSeconds(
369 startTime +
interval.toMicroSeconds() * executionCounter) -
374 newInterval =
interval - IceUtil::Time::microSeconds(lastCycleDuration);
377 if (newInterval.toMicroSeconds() < 0)
379 newInterval = IceUtil::Time::microSeconds(0);
384 timer->schedule(
this, newInterval);
390 __checkTimeslotUsage()
392 if (
interval + delayWarningTolerance < cycleDuration)
395 executionTime = cycleDuration.toMilliSeconds();
398 float logInterval = 10.0f;
403 <<
"' took " << executionTime <<
" [ms] instead of the requested "
405 <<
" [ms] (this message is only posted every " << logInterval
407 timeExceeded =
false;
414 double threadCPUUsage = -1;
418 if (clock_gettime(CLOCK_REALTIME, &st) != -1 &&
419 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &usage) != -1)
421 double current_cpu_thread_time =
static_cast<double>(usage.tv_sec) +
422 static_cast<double>(usage.tv_nsec) / 1
'000'000
'000;
423 double current_cpu_total_time = static_cast<double>(st.tv_sec) +
424 static_cast<double>(st.tv_nsec) / 1'000
'000'000;
426 if (last_cpu_total_time != 0)
428 threadCPUUsage = (current_cpu_thread_time - last_cpu_thread_time) /
429 (current_cpu_total_time - last_cpu_total_time);
432 last_cpu_total_time = current_cpu_total_time;
433 last_cpu_thread_time = current_cpu_thread_time;
438 threadCPUUsage =
static_cast<double>(lastCycleDuration) /
439 (lastCycleDuration + idleDuration.toMicroSeconds());
442 if (threadCPUUsage > 0)
444 workloadList.push_back(threadCPUUsage);
446 if (workloadList.size() > 100.f * 1.5f)
448 workloadList.erase(workloadList.begin(), workloadList.begin() + 50);
456 if (timer->getUseSystemTime())
458 return IceUtil::Time::now();
468 method_type periodicFn;
476 IceUtil::Int64 executionTime;
477 IceUtil::Int64 executionCounter;
483 double last_cpu_total_time;
484 double last_cpu_thread_time;
488 bool assureMeanInterval;
490 mutable std::mutex mutexFunctionExecuting;
491 bool functionExecuting;
492 mutable std::mutex dataMutex;