@@ -42,6 +42,7 @@ ProcessMonitor::ProcessMonitor()
4242 mPid = static_cast <unsigned int >(::getpid ());
4343 mTimeLastRun = std::chrono::high_resolution_clock::now ();
4444 getrusage (RUSAGE_SELF , &mPreviousGetrUsage );
45+ getrusage (RUSAGE_CHILDREN , &mPreviousGetrUsageChildren );
4546#ifdef O2_MONITORING_OS_LINUX
4647 setTotalMemory ();
4748#endif
@@ -52,6 +53,7 @@ void ProcessMonitor::init()
5253{
5354 mTimeLastRun = std::chrono::high_resolution_clock::now ();
5455 getrusage (RUSAGE_SELF , &mPreviousGetrUsage );
56+ getrusage (RUSAGE_CHILDREN , &mPreviousGetrUsageChildren );
5557}
5658
5759void ProcessMonitor::enable (PmMeasurement measurement)
@@ -118,27 +120,41 @@ std::vector<Metric> ProcessMonitor::getSmaps()
118120 return {{pssTotal, metricsNames[PSS ]}, {cleanTotal, metricsNames[PRIVATE_CLEAN ]}, {dirtyTotal, metricsNames[PRIVATE_DIRTY ]}};
119121}
120122
121- std::vector<Metric> ProcessMonitor::getCpuAndContexts ()
123+ std::vector<Metric> ProcessMonitor::getCpuAndContexts (bool force )
122124{
123125 std::vector<Metric> metrics;
124126 struct rusage currentUsage;
127+ struct rusage currentUsageChildren;
125128 getrusage (RUSAGE_SELF , ¤tUsage);
129+ // CPU of reaped children (e.g. an external event generator forked by o2-sim)
130+ // is spent outside this process and is invisible to RUSAGE_SELF
131+ getrusage (RUSAGE_CHILDREN , ¤tUsageChildren);
126132 auto timeNow = std::chrono::high_resolution_clock::now ();
127133 double timePassed = std::chrono::duration_cast<std::chrono::microseconds>(timeNow - mTimeLastRun ).count ();
128- if (timePassed < 950 ) {
134+ if (timePassed < 950 && !force ) {
129135 MonLogger::Get (Severity::Warn) << " Do not invoke Process Monitor more frequent then every 1s" << MonLogger::End ();
130136 metrics.emplace_back (" processPerformance" );
131137 return metrics;
132138 }
133139
134- uint64_t cpuUsedInMicroSeconds = currentUsage.ru_utime .tv_sec * 1000000.0 + currentUsage.ru_utime .tv_usec - (mPreviousGetrUsage .ru_utime .tv_sec * 1000000.0 + mPreviousGetrUsage .ru_utime .tv_usec ) + currentUsage.ru_stime .tv_sec * 1000000.0 + currentUsage.ru_stime .tv_usec - (mPreviousGetrUsage .ru_stime .tv_sec * 1000000.0 + mPreviousGetrUsage .ru_stime .tv_usec );
140+ auto micros = [](const timeval& t) { return t.tv_sec * 1000000.0 + t.tv_usec ; };
141+ auto cpuDelta = [µs](const struct rusage & now, const struct rusage & before) {
142+ return micros (now.ru_utime ) - micros (before.ru_utime ) + micros (now.ru_stime ) - micros (before.ru_stime );
143+ };
144+ uint64_t cpuUsedInMicroSeconds = cpuDelta (currentUsage, mPreviousGetrUsage ) +
145+ cpuDelta (currentUsageChildren, mPreviousGetrUsageChildren );
135146 double fractionCpuUsed = cpuUsedInMicroSeconds / timePassed;
136147
137148 double cpuUsedPerctange = std::round (fractionCpuUsed * 100.0 * 100.0 ) / 100.0 ;
138- mCpuPerctange .push_back (cpuUsedPerctange);
139149 mCpuMicroSeconds .push_back (cpuUsedInMicroSeconds);
140150
141- metrics.emplace_back (Metric{cpuUsedPerctange, metricsNames[CPU_USED_PERCENTAGE ]});
151+ // A forced measurement may report CPU accumulated over the whole run but only
152+ // made visible at once (children become visible on reap), for which an
153+ // instantaneous rate is meaningless: report it as absolute time only.
154+ if (!force) {
155+ mCpuPerctange .push_back (cpuUsedPerctange);
156+ metrics.emplace_back (Metric{cpuUsedPerctange, metricsNames[CPU_USED_PERCENTAGE ]});
157+ }
142158 metrics.emplace_back (Metric{
143159 static_cast <uint64_t >(currentUsage.ru_nivcsw - mPreviousGetrUsage .ru_nivcsw ), metricsNames[INVOLUNTARY_CONTEXT_SWITCHES ]});
144160 metrics.emplace_back (Metric{
@@ -147,6 +163,7 @@ std::vector<Metric> ProcessMonitor::getCpuAndContexts()
147163
148164 mTimeLastRun = timeNow;
149165 mPreviousGetrUsage = currentUsage;
166+ mPreviousGetrUsageChildren = currentUsageChildren;
150167 return metrics;
151168}
152169
@@ -197,7 +214,9 @@ std::vector<Metric> ProcessMonitor::makeLastMeasurementAndGetMetrics()
197214 }
198215#endif
199216 if (mEnabledMeasurements .at (static_cast <short >(PmMeasurement::Cpu))) {
200- getCpuAndContexts ();
217+ // forced: no later call will pick up a delta discarded here
218+ auto lastCpuMetrics = getCpuAndContexts (true );
219+ std::move (lastCpuMetrics.begin (), lastCpuMetrics.end (), std::back_inserter (metrics));
201220
202221 auto avgCpuUsage = std::accumulate (mCpuPerctange .begin (), mCpuPerctange .end (), 0.0 ) /
203222 mCpuPerctange .size ();
0 commit comments