$treeview $search $mathjax $extrastylesheet
artdaq_core
v3_06_01
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "artdaq-core/Core/MonitoredQuantity.hh" 00002 00003 #include <algorithm> 00004 #include <cmath> 00005 00006 using namespace artdaq; 00007 00008 MonitoredQuantity::MonitoredQuantity( 00009 DURATION_T expectedCalculationInterval, 00010 DURATION_T timeWindowForRecentResults) 00011 : _expectedCalculationInterval(expectedCalculationInterval) 00012 { 00013 setNewTimeWindowForRecentResults(timeWindowForRecentResults); 00014 enabled = true; 00015 } 00016 00017 void MonitoredQuantity::addSample(const double value) 00018 { 00019 if (!enabled) { return; } 00020 boost::mutex::scoped_lock sl(_accumulationMutex); 00021 if (_lastCalculationTime <= 0.0) 00022 { 00023 _lastCalculationTime = getCurrentTime(); 00024 } 00025 ++_workingSampleCount; 00026 _workingValueSum += value; 00027 _workingValueSumOfSquares += (value * value); 00028 if (value < _workingValueMin) { _workingValueMin = value; } 00029 if (value > _workingValueMax) { _workingValueMax = value; } 00030 _workingLastSampleValue = value; 00031 } 00032 00033 void MonitoredQuantity::addSample(const int value) 00034 { 00035 addSample(static_cast<double>(value)); 00036 } 00037 00038 void MonitoredQuantity::addSample(const uint32_t value) 00039 { 00040 addSample(static_cast<double>(value)); 00041 } 00042 00043 void MonitoredQuantity::addSample(const uint64_t value) 00044 { 00045 addSample(static_cast<double>(value)); 00046 } 00047 00048 bool MonitoredQuantity::calculateStatistics(TIME_POINT_T currentTime) 00049 { 00050 if (!enabled) { return false; } 00051 if (_lastCalculationTime <= 0.0) { return false; } 00052 if (currentTime - _lastCalculationTime < _expectedCalculationInterval) 00053 { 00054 return false; 00055 } 00056 // create local copies of the working values to minimize the 00057 // time that we could block a thread trying to add a sample. 00058 // Also, reset the working values. 00059 size_t latestSampleCount; 00060 double latestValueSum; 00061 double latestValueSumOfSquares; 00062 double latestValueMin; 00063 double latestValueMax; 00064 DURATION_T latestDuration; 00065 double latestLastLatchedSampleValue; 00066 { 00067 boost::mutex::scoped_lock sl(_accumulationMutex); 00068 latestSampleCount = _workingSampleCount; 00069 latestValueSum = _workingValueSum; 00070 latestValueSumOfSquares = _workingValueSumOfSquares; 00071 latestValueMin = _workingValueMin; 00072 latestValueMax = _workingValueMax; 00073 latestDuration = currentTime - _lastCalculationTime; 00074 latestLastLatchedSampleValue = _workingLastSampleValue; 00075 _lastCalculationTime = currentTime; 00076 _workingSampleCount = 0; 00077 _workingValueSum = 0.0; 00078 _workingValueSumOfSquares = 0.0; 00079 _workingValueMin = INFINITY; 00080 _workingValueMax = -INFINITY; 00081 } 00082 // lock out any interaction with the results while we update them 00083 { 00084 boost::mutex::scoped_lock sl(_resultsMutex); 00085 lastSampleValue = latestLastLatchedSampleValue; 00086 lastCalculationTime = _lastCalculationTime; 00087 // we simply add the latest results to the full set 00088 fullSampleCount += latestSampleCount; 00089 fullValueSum += latestValueSum; 00090 fullValueSumOfSquares += latestValueSumOfSquares; 00091 if (latestValueMin < fullValueMin) { fullValueMin = latestValueMin; } 00092 if (latestValueMax > fullValueMax) { fullValueMax = latestValueMax; } 00093 fullDuration += latestDuration; 00094 // for the recent results, we need to replace the contents of 00095 // the working bin and re-calculate the recent values 00096 recentBinnedSampleCounts[_workingBinId] = latestSampleCount; 00097 recentBinnedValueSums[_workingBinId] = latestValueSum; 00098 _binValueSumOfSquares[_workingBinId] = latestValueSumOfSquares; 00099 _binValueMin[_workingBinId] = latestValueMin; 00100 _binValueMax[_workingBinId] = latestValueMax; 00101 recentBinnedDurations[_workingBinId] = latestDuration; 00102 recentBinnedEndTimes[_workingBinId] = _lastCalculationTime; 00103 if (latestDuration > 0.0) 00104 { 00105 lastValueRate = latestValueSum / latestDuration; 00106 } 00107 else 00108 { 00109 lastValueRate = 0.0; 00110 } 00111 recentSampleCount = 0; 00112 recentValueSum = 0.0; 00113 recentValueSumOfSquares = 0.0; 00114 recentValueMin = INFINITY; 00115 recentValueMax = -INFINITY; 00116 recentDuration = 0.0; 00117 for (unsigned int idx = 0; idx < _binCount; ++idx) 00118 { 00119 recentSampleCount += recentBinnedSampleCounts[idx]; 00120 recentValueSum += recentBinnedValueSums[idx]; 00121 recentValueSumOfSquares += _binValueSumOfSquares[idx]; 00122 if (_binValueMin[idx] < recentValueMin) 00123 { 00124 recentValueMin = _binValueMin[idx]; 00125 } 00126 if (_binValueMax[idx] > recentValueMax) 00127 { 00128 recentValueMax = _binValueMax[idx]; 00129 } 00130 recentDuration += recentBinnedDurations[idx]; 00131 } 00132 // update the working bin ID here so that we are ready for 00133 // the next calculation request 00134 ++_workingBinId; 00135 if (_workingBinId >= _binCount) { _workingBinId = 0; } 00136 // calculate the derived full values 00137 if (fullDuration > 0.0) 00138 { 00139 fullSampleRate = static_cast<double>(fullSampleCount) / fullDuration; 00140 fullValueRate = static_cast<double>(fullValueSum) / fullDuration; 00141 } 00142 else 00143 { 00144 fullSampleRate = 0.0; 00145 fullValueRate = 0.0; 00146 } 00147 if (fullSampleCount > 0) 00148 { 00149 fullValueAverage = fullValueSum / static_cast<double>(fullSampleCount); 00150 double squareAvg = fullValueSumOfSquares / static_cast<double>(fullSampleCount); 00151 double avg = fullValueSum / static_cast<double>(fullSampleCount); 00152 double sigSquared = squareAvg - avg * avg; 00153 if (sigSquared > 0.0) 00154 { 00155 fullValueRMS = sqrt(sigSquared); 00156 } 00157 else 00158 { 00159 fullValueRMS = 0.0; 00160 } 00161 } 00162 else 00163 { 00164 fullValueAverage = 0.0; 00165 fullValueRMS = 0.0; 00166 } 00167 // calculate the derived recent values 00168 if (recentDuration > 0.0) 00169 { 00170 recentSampleRate = static_cast<double>(recentSampleCount) / recentDuration; 00171 recentValueRate = static_cast<double>(recentValueSum) / recentDuration; 00172 } 00173 else 00174 { 00175 recentSampleRate = 0.0; 00176 recentValueRate = 0.0; 00177 } 00178 if (recentSampleCount > 0) 00179 { 00180 recentValueAverage = recentValueSum / static_cast<double>(recentSampleCount); 00181 double squareAvg = recentValueSumOfSquares / 00182 static_cast<double>(recentSampleCount); 00183 double avg = recentValueSum / static_cast<double>(recentSampleCount); 00184 double sigSquared = squareAvg - avg * avg; 00185 if (sigSquared > 0.0) 00186 { 00187 recentValueRMS = sqrt(sigSquared); 00188 } 00189 else 00190 { 00191 recentValueRMS = 0.0; 00192 } 00193 } 00194 else 00195 { 00196 recentValueAverage = 0.0; 00197 recentValueRMS = 0.0; 00198 } 00199 } 00200 return true; 00201 } 00202 00203 void MonitoredQuantity::_reset_accumulators() 00204 { 00205 _lastCalculationTime = 0; 00206 _workingSampleCount = 0; 00207 _workingValueSum = 0.0; 00208 _workingValueSumOfSquares = 0.0; 00209 _workingValueMin = INFINITY; 00210 _workingValueMax = -INFINITY; 00211 _workingLastSampleValue = 0; 00212 } 00213 00214 void MonitoredQuantity::_reset_results() 00215 { 00216 _workingBinId = 0; 00217 for (unsigned int idx = 0; idx < _binCount; ++idx) 00218 { 00219 recentBinnedSampleCounts[idx] = 0; 00220 recentBinnedValueSums[idx] = 0.0; 00221 _binValueSumOfSquares[idx] = 0.0; 00222 _binValueMin[idx] = INFINITY; 00223 _binValueMax[idx] = -INFINITY; 00224 recentBinnedDurations[idx] = 0.0; 00225 recentBinnedEndTimes[idx] = 0.0; 00226 } 00227 fullSampleCount = 0; 00228 fullSampleRate = 0.0; 00229 fullValueSum = 0.0; 00230 fullValueSumOfSquares = 0.0; 00231 fullValueAverage = 0.0; 00232 fullValueRMS = 0.0; 00233 fullValueMin = INFINITY; 00234 fullValueMax = -INFINITY; 00235 fullValueRate = 0.0; 00236 fullDuration = 0.0; 00237 recentSampleCount = 0; 00238 recentSampleRate = 0.0; 00239 recentValueSum = 0.0; 00240 recentValueSumOfSquares = 0.0; 00241 recentValueAverage = 0.0; 00242 recentValueRMS = 0.0; 00243 recentValueMin = INFINITY; 00244 recentValueMax = -INFINITY; 00245 recentValueRate = 0.0; 00246 recentDuration = 0.0; 00247 lastSampleValue = 0.0; 00248 lastValueRate = 0.0; 00249 } 00250 00251 void MonitoredQuantity::reset() 00252 { 00253 { 00254 boost::mutex::scoped_lock sl(_accumulationMutex); 00255 _reset_accumulators(); 00256 } 00257 { 00258 boost::mutex::scoped_lock sl(_resultsMutex); 00259 _reset_results(); 00260 } 00261 } 00262 00263 void MonitoredQuantity::enable() 00264 { 00265 if (!enabled) 00266 { 00267 reset(); 00268 enabled = true; 00269 } 00270 } 00271 00272 void MonitoredQuantity::disable() 00273 { 00274 // It is faster to just set _enabled to false than to test and set 00275 // it conditionally. 00276 enabled = false; 00277 } 00278 00279 void MonitoredQuantity::setNewTimeWindowForRecentResults(DURATION_T interval) 00280 { 00281 // lock the results objects since we're dramatically changing the 00282 // bins used for the recent results 00283 { 00284 boost::mutex::scoped_lock sl(_resultsMutex); 00285 _intervalForRecentStats = interval; 00286 // determine how many bins we should use in our sliding window 00287 // by dividing the input time window by the expected calculation 00288 // interval and rounding to the nearest integer. 00289 // In case that the calculation interval is larger then the 00290 // interval for recent stats, keep the last one. 00291 _binCount = std::max(1U, static_cast<unsigned int>(std::lround(_intervalForRecentStats / _expectedCalculationInterval))); 00292 // create the vectors for the binned quantities 00293 recentBinnedSampleCounts.reserve(_binCount); 00294 recentBinnedValueSums.reserve(_binCount); 00295 _binValueSumOfSquares.reserve(_binCount); 00296 _binValueMin.reserve(_binCount); 00297 _binValueMax.reserve(_binCount); 00298 recentBinnedDurations.reserve(_binCount); 00299 recentBinnedEndTimes.reserve(_binCount); 00300 _reset_results(); 00301 } 00302 { 00303 boost::mutex::scoped_lock sl(_accumulationMutex); 00304 _reset_accumulators(); 00305 } 00306 // call the reset method to populate the correct initial values 00307 // for the internal sample data 00308 //reset(); 00309 } 00310 00311 bool MonitoredQuantity:: 00312 waitUntilAccumulatorsHaveBeenFlushed(DURATION_T timeout) const 00313 { 00314 timeout /= 10; 00315 { 00316 boost::mutex::scoped_lock sl(_accumulationMutex); 00317 if (_workingSampleCount == 0) { return true; } 00318 } 00319 auto sleepTime = static_cast<int64_t>(timeout * 100000.0); 00320 for (auto idx = 0; idx < 10; ++idx) 00321 { 00322 usleep(sleepTime); 00323 { 00324 boost::mutex::scoped_lock sl(_accumulationMutex); 00325 if (_workingSampleCount == 0) { return true; } 00326 } 00327 } 00328 return false; 00329 } 00330 00331 void MonitoredQuantity::getStats(MonitoredQuantityStats& s) const 00332 { 00333 boost::mutex::scoped_lock results(_resultsMutex); 00334 s.fullSampleCount = fullSampleCount; 00335 s.fullSampleRate = fullSampleRate; 00336 s.fullValueSum = fullValueSum; 00337 s.fullValueSumOfSquares = fullValueSumOfSquares; 00338 s.fullValueAverage = fullValueAverage; 00339 s.fullValueRMS = fullValueRMS; 00340 s.fullValueMin = fullValueMin; 00341 s.fullValueMax = fullValueMax; 00342 s.fullValueRate = fullValueRate; 00343 s.fullDuration = fullDuration; 00344 s.recentSampleCount = recentSampleCount; 00345 s.recentSampleRate = recentSampleRate; 00346 s.recentValueSum = recentValueSum; 00347 s.recentValueSumOfSquares = recentValueSumOfSquares; 00348 s.recentValueAverage = recentValueAverage; 00349 s.recentValueRMS = recentValueRMS; 00350 s.recentValueMin = recentValueMin; 00351 s.recentValueMax = recentValueMax; 00352 s.recentValueRate = recentValueRate; 00353 s.recentDuration = recentDuration; 00354 s.recentBinnedSampleCounts.resize(_binCount); 00355 s.recentBinnedValueSums.resize(_binCount); 00356 s.recentBinnedDurations.resize(_binCount); 00357 s.recentBinnedEndTimes.resize(_binCount); 00358 unsigned int sourceBinId = _workingBinId; 00359 for (unsigned int idx = 0; idx < _binCount; ++idx) 00360 { 00361 if (sourceBinId >= _binCount) { sourceBinId = 0; } 00362 s.recentBinnedSampleCounts[idx] = recentBinnedSampleCounts[sourceBinId]; 00363 s.recentBinnedValueSums[idx] = recentBinnedValueSums[sourceBinId]; 00364 s.recentBinnedDurations[idx] = recentBinnedDurations[sourceBinId]; 00365 s.recentBinnedEndTimes[idx] = recentBinnedEndTimes[sourceBinId]; 00366 ++sourceBinId; 00367 } 00368 s.lastSampleValue = lastSampleValue; 00369 s.lastValueRate = lastValueRate; 00370 s.lastCalculationTime = lastCalculationTime; 00371 s.enabled = enabled; 00372 } 00373 00374 MonitoredQuantity::TIME_POINT_T MonitoredQuantity::getCurrentTime() 00375 { 00376 TIME_POINT_T result = -1.0; 00377 timeval now; 00378 if (gettimeofday(&now, nullptr) == 0) 00379 { 00380 result = static_cast<TIME_POINT_T>(now.tv_sec); 00381 result += static_cast<TIME_POINT_T>(now.tv_usec) / (1000 * 1000); 00382 } 00383 return result; 00384 } 00385 00386 MonitoredQuantity::TIME_POINT_T MonitoredQuantity::getLastCalculationTime() const 00387 { 00388 boost::mutex::scoped_lock results(_resultsMutex); 00389 return lastCalculationTime; 00390 } 00391 00392 MonitoredQuantity::DURATION_T MonitoredQuantity::getFullDuration() const 00393 { 00394 boost::mutex::scoped_lock results(_resultsMutex); 00395 return fullDuration; 00396 } 00397 00398 double MonitoredQuantity::getRecentValueSum() const 00399 { 00400 boost::mutex::scoped_lock results(_resultsMutex); 00401 return recentValueSum; 00402 } 00403 00404 double MonitoredQuantity::getRecentValueAverage() const 00405 { 00406 boost::mutex::scoped_lock results(_resultsMutex); 00407 return recentValueAverage; 00408 } 00409 00410 size_t MonitoredQuantity::getFullSampleCount() const 00411 { 00412 boost::mutex::scoped_lock results(_resultsMutex); 00413 return fullSampleCount; 00414 }