00001 #include "artdaq-core/Core/MonitoredQuantity.hh"
00002
00003 #include <algorithm>
00004 #include <math.h>
00005
00006 using namespace artdaq;
00007
00008 MonitoredQuantity::MonitoredQuantity
00009 (
00010 DURATION_T expectedCalculationInterval,
00011 DURATION_T timeWindowForRecentResults
00012 ):
00013 _enabled(true),
00014 _expectedCalculationInterval(expectedCalculationInterval)
00015 {
00016 setNewTimeWindowForRecentResults(timeWindowForRecentResults);
00017 }
00018
00019 void MonitoredQuantity::addSample(const double value)
00020 {
00021 if (! _enabled) {return;}
00022 boost::mutex::scoped_lock sl(_accumulationMutex);
00023 if (_lastCalculationTime <= 0.0) {
00024 _lastCalculationTime = getCurrentTime();
00025 }
00026 ++_workingSampleCount;
00027 _workingValueSum += value;
00028 _workingValueSumOfSquares += (value * value);
00029 if (value < _workingValueMin) { _workingValueMin = value; }
00030 if (value > _workingValueMax) { _workingValueMax = value; }
00031 _workingLastSampleValue = value;
00032 }
00033
00034 void MonitoredQuantity::addSample(const int value)
00035 {
00036 addSample(static_cast<double>(value));
00037 }
00038
00039 void MonitoredQuantity::addSample(const uint32_t value)
00040 {
00041 addSample(static_cast<double>(value));
00042 }
00043
00044 void MonitoredQuantity::addSample(const uint64_t value)
00045 {
00046 addSample(static_cast<double>(value));
00047 }
00048
00049 bool MonitoredQuantity::calculateStatistics(TIME_POINT_T currentTime)
00050 {
00051 if (! _enabled) {return false;}
00052 if (_lastCalculationTime <= 0.0) {return false;}
00053 if (currentTime - _lastCalculationTime < _expectedCalculationInterval) {
00054 return false;
00055 }
00056
00057
00058
00059 long long 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
00083 {
00084 boost::mutex::scoped_lock sl(_resultsMutex);
00085 _lastLatchedSampleValue = latestLastLatchedSampleValue;
00086 _lastLatchedCalculationTime = _lastCalculationTime;
00087
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
00095
00096 _binSampleCount[_workingBinId] = latestSampleCount;
00097 _binValueSum[_workingBinId] = latestValueSum;
00098 _binValueSumOfSquares[_workingBinId] = latestValueSumOfSquares;
00099 _binValueMin[_workingBinId] = latestValueMin;
00100 _binValueMax[_workingBinId] = latestValueMax;
00101 _binDuration[_workingBinId] = latestDuration;
00102 _binEndTime[_workingBinId] = _lastCalculationTime;
00103 if (latestDuration > 0.0) {
00104 _lastLatchedValueRate = latestValueSum / latestDuration;
00105 }
00106 else {
00107 _lastLatchedValueRate = 0.0;
00108 }
00109 _recentSampleCount = 0;
00110 _recentValueSum = 0.0;
00111 _recentValueSumOfSquares = 0.0;
00112 _recentValueMin = INFINITY;
00113 _recentValueMax = -INFINITY;
00114 _recentDuration = 0.0;
00115 for (unsigned int idx = 0; idx < _binCount; ++idx) {
00116 _recentSampleCount += _binSampleCount[idx];
00117 _recentValueSum += _binValueSum[idx];
00118 _recentValueSumOfSquares += _binValueSumOfSquares[idx];
00119 if (_binValueMin[idx] < _recentValueMin) {
00120 _recentValueMin = _binValueMin[idx];
00121 }
00122 if (_binValueMax[idx] > _recentValueMax) {
00123 _recentValueMax = _binValueMax[idx];
00124 }
00125 _recentDuration += _binDuration[idx];
00126 }
00127
00128
00129 ++_workingBinId;
00130 if (_workingBinId >= _binCount) {_workingBinId = 0;}
00131
00132 if (_fullDuration > 0.0) {
00133 _fullSampleRate = static_cast<double>(_fullSampleCount) / _fullDuration;
00134 _fullValueRate = static_cast<double>(_fullValueSum) / _fullDuration;
00135 }
00136 else {
00137 _fullSampleRate = 0.0;
00138 _fullValueRate = 0.0;
00139 }
00140 if (_fullSampleCount > 0) {
00141 _fullValueAverage = _fullValueSum / static_cast<double>(_fullSampleCount);
00142 double squareAvg = _fullValueSumOfSquares / static_cast<double>(_fullSampleCount);
00143 double avg = _fullValueSum / static_cast<double>(_fullSampleCount);
00144 double sigSquared = squareAvg - avg * avg;
00145 if (sigSquared > 0.0) {
00146 _fullValueRMS = sqrt(sigSquared);
00147 }
00148 else {
00149 _fullValueRMS = 0.0;
00150 }
00151 }
00152 else {
00153 _fullValueAverage = 0.0;
00154 _fullValueRMS = 0.0;
00155 }
00156
00157 if (_recentDuration > 0.0) {
00158 _recentSampleRate = static_cast<double>(_recentSampleCount) / _recentDuration;
00159 _recentValueRate = static_cast<double>(_recentValueSum) / _recentDuration;
00160 }
00161 else {
00162 _recentSampleRate = 0.0;
00163 _recentValueRate = 0.0;
00164 }
00165 if (_recentSampleCount > 0) {
00166 _recentValueAverage = _recentValueSum / static_cast<double>(_recentSampleCount);
00167 double squareAvg = _recentValueSumOfSquares /
00168 static_cast<double>(_recentSampleCount);
00169 double avg = _recentValueSum / static_cast<double>(_recentSampleCount);
00170 double sigSquared = squareAvg - avg * avg;
00171 if (sigSquared > 0.0) {
00172 _recentValueRMS = sqrt(sigSquared);
00173 }
00174 else {
00175 _recentValueRMS = 0.0;
00176 }
00177 }
00178 else {
00179 _recentValueAverage = 0.0;
00180 _recentValueRMS = 0.0;
00181 }
00182 }
00183 return true;
00184 }
00185
00186 void MonitoredQuantity::_reset_accumulators()
00187 {
00188 _lastCalculationTime = 0;
00189 _workingSampleCount = 0;
00190 _workingValueSum = 0.0;
00191 _workingValueSumOfSquares = 0.0;
00192 _workingValueMin = INFINITY;
00193 _workingValueMax = -INFINITY;
00194 _workingLastSampleValue = 0;
00195 }
00196
00197 void MonitoredQuantity::_reset_results()
00198 {
00199 _workingBinId = 0;
00200 for (unsigned int idx = 0; idx < _binCount; ++idx) {
00201 _binSampleCount[idx] = 0;
00202 _binValueSum[idx] = 0.0;
00203 _binValueSumOfSquares[idx] = 0.0;
00204 _binValueMin[idx] = INFINITY;
00205 _binValueMax[idx] = -INFINITY;
00206 _binDuration[idx] = 0.0;
00207 _binEndTime[idx] = 0.0;
00208 }
00209 _fullSampleCount = 0;
00210 _fullSampleRate = 0.0;
00211 _fullValueSum = 0.0;
00212 _fullValueSumOfSquares = 0.0;
00213 _fullValueAverage = 0.0;
00214 _fullValueRMS = 0.0;
00215 _fullValueMin = INFINITY;
00216 _fullValueMax = -INFINITY;
00217 _fullValueRate = 0.0;
00218 _fullDuration = 0.0;
00219 _recentSampleCount = 0;
00220 _recentSampleRate = 0.0;
00221 _recentValueSum = 0.0;
00222 _recentValueSumOfSquares = 0.0;
00223 _recentValueAverage = 0.0;
00224 _recentValueRMS = 0.0;
00225 _recentValueMin = INFINITY;
00226 _recentValueMax = -INFINITY;
00227 _recentValueRate = 0.0;
00228 _recentDuration = 0.0;
00229 _lastLatchedSampleValue = 0.0;
00230 _lastLatchedValueRate = 0.0;
00231 }
00232
00233 void MonitoredQuantity::reset()
00234 {
00235 {
00236 boost::mutex::scoped_lock sl(_accumulationMutex);
00237 _reset_accumulators();
00238 }
00239 {
00240 boost::mutex::scoped_lock sl(_resultsMutex);
00241 _reset_results();
00242 }
00243 }
00244
00245 void MonitoredQuantity::enable()
00246 {
00247 if (! _enabled) {
00248 reset();
00249 _enabled = true;
00250 }
00251 }
00252
00253 void MonitoredQuantity::disable()
00254 {
00255
00256
00257 _enabled = false;
00258 }
00259
00260 void MonitoredQuantity::setNewTimeWindowForRecentResults(DURATION_T interval)
00261 {
00262
00263
00264 {
00265 boost::mutex::scoped_lock sl(_resultsMutex);
00266 _intervalForRecentStats = interval;
00267
00268
00269
00270
00271
00272 _binCount = std::max(1U,
00273 static_cast<unsigned int>(
00274 (_intervalForRecentStats / _expectedCalculationInterval) + 0.5
00275 )
00276 );
00277
00278 _binSampleCount.reserve(_binCount);
00279 _binValueSum.reserve(_binCount);
00280 _binValueSumOfSquares.reserve(_binCount);
00281 _binValueMin.reserve(_binCount);
00282 _binValueMax.reserve(_binCount);
00283 _binDuration.reserve(_binCount);
00284 _binEndTime.reserve(_binCount);
00285 _reset_results();
00286 }
00287 {
00288 boost::mutex::scoped_lock sl(_accumulationMutex);
00289 _reset_accumulators();
00290 }
00291
00292
00293
00294 }
00295
00296 bool MonitoredQuantity::
00297 waitUntilAccumulatorsHaveBeenFlushed(DURATION_T timeout) const
00298 {
00299 {
00300 boost::mutex::scoped_lock sl(_accumulationMutex);
00301 if (_workingSampleCount == 0) {return true;}
00302 }
00303 long sleepTime = static_cast<long>(timeout * 100000.0);
00304 for (int idx = 0; idx < 10; ++idx) {
00305 usleep(sleepTime);
00306 {
00307 boost::mutex::scoped_lock sl(_accumulationMutex);
00308 if (_workingSampleCount == 0) {return true;}
00309 }
00310 }
00311 return false;
00312 }
00313
00314 void
00315 MonitoredQuantity::getStats(Stats & s) const
00316 {
00317 boost::mutex::scoped_lock results(_resultsMutex);
00318 s.fullSampleCount = _fullSampleCount;
00319 s.fullSampleRate = _fullSampleRate;
00320 s.fullValueSum = _fullValueSum;
00321 s.fullValueSumOfSquares = _fullValueSumOfSquares;
00322 s.fullValueAverage = _fullValueAverage;
00323 s.fullValueRMS = _fullValueRMS;
00324 s.fullValueMin = _fullValueMin;
00325 s.fullValueMax = _fullValueMax;
00326 s.fullValueRate = _fullValueRate;
00327 s.fullDuration = _fullDuration;
00328 s.recentSampleCount = _recentSampleCount;
00329 s.recentSampleRate = _recentSampleRate;
00330 s.recentValueSum = _recentValueSum;
00331 s.recentValueSumOfSquares = _recentValueSumOfSquares;
00332 s.recentValueAverage = _recentValueAverage;
00333 s.recentValueRMS = _recentValueRMS;
00334 s.recentValueMin = _recentValueMin;
00335 s.recentValueMax = _recentValueMax;
00336 s.recentValueRate = _recentValueRate;
00337 s.recentDuration = _recentDuration;
00338 s.recentBinnedSampleCounts.resize(_binCount);
00339 s.recentBinnedValueSums.resize(_binCount);
00340 s.recentBinnedDurations.resize(_binCount);
00341 s.recentBinnedEndTimes.resize(_binCount);
00342 unsigned int sourceBinId = _workingBinId;
00343 for (unsigned int idx = 0; idx < _binCount; ++idx) {
00344 if (sourceBinId >= _binCount) {sourceBinId = 0;}
00345 s.recentBinnedSampleCounts[idx] = _binSampleCount[sourceBinId];
00346 s.recentBinnedValueSums[idx] = _binValueSum[sourceBinId];
00347 s.recentBinnedDurations[idx] = _binDuration[sourceBinId];
00348 s.recentBinnedEndTimes[idx] = _binEndTime[sourceBinId];
00349 ++sourceBinId;
00350 }
00351 s.lastSampleValue = _lastLatchedSampleValue;
00352 s.lastValueRate = _lastLatchedValueRate;
00353 s.lastCalculationTime = _lastLatchedCalculationTime;
00354 s.enabled = _enabled;
00355 }
00356
00357 MonitoredQuantity::TIME_POINT_T MonitoredQuantity::getCurrentTime()
00358 {
00359 TIME_POINT_T result = -1.0;
00360 timeval now;
00361 if (gettimeofday(&now, 0) == 0) {
00362 result = static_cast<TIME_POINT_T>(now.tv_sec);
00363 result += static_cast<TIME_POINT_T>(now.tv_usec) / (1000 * 1000);
00364 }
00365 return result;
00366 }
00367
00368 MonitoredQuantity::TIME_POINT_T MonitoredQuantity::lastCalculationTime() const
00369 {
00370 boost::mutex::scoped_lock results(_resultsMutex);
00371 return _lastLatchedCalculationTime;
00372 }
00373
00374 MonitoredQuantity::DURATION_T MonitoredQuantity::fullDuration() const
00375 {
00376 boost::mutex::scoped_lock results(_resultsMutex);
00377 return _fullDuration;
00378 }
00379
00380 double MonitoredQuantity::recentValueSum() const
00381 {
00382 boost::mutex::scoped_lock results(_resultsMutex);
00383 return _recentValueSum;
00384 }
00385
00386 double MonitoredQuantity::recentValueAverage() const
00387 {
00388 boost::mutex::scoped_lock results(_resultsMutex);
00389 return _recentValueAverage;
00390 }
00391
00392 long long MonitoredQuantity::fullSampleCount() const
00393 {
00394 boost::mutex::scoped_lock results(_resultsMutex);
00395 return _fullSampleCount;
00396 }