SST 12.1.0
Structural Simulation Toolkit
stathistogram.h
1// Copyright 2009-2022 NTESS. Under the terms
2// of Contract DE-NA0003525 with NTESS, the U.S.
3// Government retains certain rights in this software.
4//
5// Copyright (c) 2009-2022, NTESS
6// All rights reserved.
7//
8// This file is part of the SST software package. For license
9// information, see the LICENSE file in the top level directory of the
10// distribution.
11
12#ifndef SST_CORE_STATAPI_STATHISTOGRAM_H
13#define SST_CORE_STATAPI_STATHISTOGRAM_H
14
15#include "sst/core/sst_types.h"
16#include "sst/core/statapi/statbase.h"
17#include "sst/core/statapi/statoutput.h"
18#include "sst/core/warnmacros.h"
19
20namespace SST {
21namespace Statistics {
22
23// NOTE: When calling base class members in classes derived from
24// a templated base class. The user must use "this->" in
25// order to call base class members (to avoid a compiler
26// error) because they are "nondependant named" and the
27// templated base class is a "dependant named". The
28// compiler will not look in dependant named base classes
29// when looking up independent names.
30// See: http://www.parashift.com/c++-faq-lite/nondependent-name-lookup-members.html
31
32/**
33 \class HistogramStatistic
34 Holder of data grouped into pre-determined width bins.
35 \tparam BinDataType is the type of the data held in each bin (i.e. what data type described the width of the bin)
36*/
37#define CountType uint64_t
38#define NumBinsType uint32_t
39
40template <class BinDataType>
41class HistogramStatistic : public Statistic<BinDataType>
42{
43public:
44 SST_ELI_DECLARE_STATISTIC_TEMPLATE(
46 "sst",
47 "HistogramStatistic",
48 SST_ELI_ELEMENT_VERSION(1, 0, 0),
49 "Track distribution of statistic across bins",
50 "SST::Statistic<T>")
51
53 BaseComponent* comp, const std::string& statName, const std::string& statSubId, Params& statParams) :
54 Statistic<BinDataType>(comp, statName, statSubId, statParams)
55 {
56 // Identify what keys are Allowed in the parameters
57 Params::KeySet_t allowedKeySet;
58 allowedKeySet.insert("minvalue");
59 allowedKeySet.insert("binwidth");
60 allowedKeySet.insert("numbins");
61 allowedKeySet.insert("dumpbinsonoutput");
62 allowedKeySet.insert("includeoutofbounds");
63 statParams.pushAllowedKeys(allowedKeySet);
64
65 // Process the Parameters
66 m_minValue = statParams.find<BinDataType>("minvalue", 0);
67 m_binWidth = statParams.find<NumBinsType>("binwidth", 5000);
68 m_numBins = statParams.find<NumBinsType>("numbins", 100);
69 m_dumpBinsOnOutput = statParams.find<bool>("dumpbinsonoutput", true);
70 m_includeOutOfBounds = statParams.find<bool>("includeoutofbounds", true);
71
72 // Initialize other properties
73 m_totalSummed = 0;
74 m_totalSummedSqr = 0;
75 m_OOBMinCount = 0;
76 m_OOBMaxCount = 0;
77 m_itemsBinnedCount = 0;
78 this->setCollectionCount(0);
79
80 // Set the Name of this Statistic
81 this->setStatisticTypeName("Histogram");
82 }
83
85
86protected:
87 /**
88 Adds a new value to the histogram. The correct bin is identified and then incremented. If no bin can be found
89 to hold the value then a new bin is created.
90 */
91 void addData_impl_Ntimes(uint64_t N, BinDataType value) override
92 {
93 // Check to see if the value is above or below the min/max values
94 if ( value < getBinsMinValue() ) {
95 m_OOBMinCount += N;
96 return;
97 }
98 if ( value > getBinsMaxValue() ) {
99 m_OOBMaxCount += N;
100 return;
101 }
102
103 // This value is to be binned...
104 // Add the "in limits" value to the total summation's
105 m_totalSummed += N * value;
106 m_totalSummedSqr += N * (value * value);
107
108 // Increment the Binned count (note this <= to the Statistics added Item Count)
109 m_itemsBinnedCount++;
110
111 // Figure out what the starting bin is and find it in the map
112 // To support signed and unsigned values along with floating point types,
113 // the calculation to find the bin_start value must be done in floating point
114 // then converted to BinDataType
115 double calc1 = (double)value / (double)m_binWidth;
116 double calc2 = floor(calc1); // Find the floor of the value
117 double calc3 = m_binWidth * calc2;
118 BinDataType bin_start = (BinDataType)calc3;
119 // printf("DEBUG: value = %d, junk1 = %f, calc2 = %f, calc3 = %f : bin_start = %d, item count = %ld, \n",
120 // value, calc1, calc2, calc3, bin_start, getStatCollectionCount());
121
122 HistoMapItr_t bin_itr = m_binsMap.find(bin_start);
123
124 // Was the bin found?
125 if ( bin_itr == m_binsMap.end() ) {
126 // No, Create the bin and set a value of 1 to it
127 m_binsMap.insert(std::pair<BinDataType, CountType>(bin_start, (CountType)N));
128 }
129 else {
130 // Yes, Increment the specific bin's count
131 bin_itr->second += N;
132 }
133 }
134
135 void addData_impl(BinDataType value) override { addData_impl_Ntimes(1, value); }
136
137private:
138 /** Count how many bins are active in this histogram */
139 NumBinsType getActiveBinCount() { return m_binsMap.size(); }
140
141 /** Count how many bins are available */
142 NumBinsType getNumBins() { return m_numBins; }
143
144 /** Get the width of a bin in this histogram */
145 NumBinsType getBinWidth() { return m_binWidth; }
146
147 /**
148 Get the count of items in the bin by the start value (e.g. give me the count of items in the bin which begins at
149 value X). \return The count of items in the bin else 0.
150 */
151 CountType getBinCountByBinStart(BinDataType binStartValue)
152 {
153 // Find the Bin Start Value in the Bin Map
154 HistoMapItr_t bin_itr = m_binsMap.find(binStartValue);
155
156 // Check to see if the Start Value was found
157 if ( bin_itr == m_binsMap.end() ) {
158 // No, return no count for this bin
159 return (CountType)0;
160 }
161 else {
162 // Yes, return the bin count
163 return m_binsMap[binStartValue];
164 }
165 }
166
167 /**
168 Get the smallest start value of a bin in this histogram (i.e. the minimum value possibly represented by this
169 histogram)
170 */
171 BinDataType getBinsMinValue() { return m_minValue; }
172
173 /**
174 Get the largest possible value represented by this histogram (i.e. the highest value in any of items bins
175 rounded above to the size of the bin)
176 */
177 BinDataType getBinsMaxValue()
178 {
179 // Compute the max value based on the width * num bins offset by minvalue
180 return (m_binWidth * m_numBins) + m_minValue - 1;
181 }
182
183 /**
184 Get the total number of items collected by the statistic
185 \return The number of items that have been added to the statistic
186 */
187 uint64_t getStatCollectionCount()
188 {
189 // Get the number of items added (but not necessarily binned) to this statistic
190 return this->getCollectionCount();
191 }
192
193 /**
194 Get the total number of items contained in all bins
195 \return The number of items contained in all bins
196 */
197 CountType getItemsBinnedCount()
198 {
199 // Get the number of items added to this statistic that were binned.
200 return m_itemsBinnedCount;
201 }
202
203 /**
204 Sum up every item presented for storage in the histogram
205 \return The sum of all values added into the histogram
206 */
207 BinDataType getValuesSummed() { return m_totalSummed; }
208
209 /**
210 Sum up every squared value entered into the Histogram.
211 \return The sum of all values added after squaring into the Histogram
212 */
213 BinDataType getValuesSquaredSummed() { return m_totalSummedSqr; }
214
215 void clearStatisticData() override
216 {
217 m_totalSummed = 0;
218 m_totalSummedSqr = 0;
219 m_OOBMinCount = 0;
220 m_OOBMaxCount = 0;
221 m_itemsBinnedCount = 0;
222 m_binsMap.clear();
223 this->setCollectionCount(0);
224 }
225
226 void registerOutputFields(StatisticFieldsOutput* statOutput) override
227 {
228 // Check to see if we have registered the Startup Fields
229 m_Fields.push_back(statOutput->registerField<BinDataType>("BinsMinValue"));
230 m_Fields.push_back(statOutput->registerField<BinDataType>("BinsMaxValue"));
231 m_Fields.push_back(statOutput->registerField<NumBinsType>("BinWidth"));
232 m_Fields.push_back(statOutput->registerField<NumBinsType>("TotalNumBins"));
233 m_Fields.push_back(statOutput->registerField<BinDataType>("Sum"));
234 m_Fields.push_back(statOutput->registerField<BinDataType>("SumSQ"));
235 m_Fields.push_back(statOutput->registerField<NumBinsType>("NumActiveBins"));
236 m_Fields.push_back(statOutput->registerField<CountType>("NumItemsCollected"));
237 m_Fields.push_back(statOutput->registerField<CountType>("NumItemsBinned"));
238
239 if ( true == m_includeOutOfBounds ) {
240 m_Fields.push_back(statOutput->registerField<CountType>("NumOutOfBounds-MinValue"));
241 m_Fields.push_back(statOutput->registerField<CountType>("NumOutOfBounds-MaxValue"));
242 }
243
244 // Do we also need to dump the bin counts on output
245 if ( true == m_dumpBinsOnOutput ) {
246 BinDataType binLL;
247 BinDataType binUL;
248
249 for ( uint32_t y = 0; y < getNumBins(); y++ ) {
250 // Figure out the upper and lower values for this bin
251 binLL = (y * (uint64_t)getBinWidth()) + getBinsMinValue(); // Force full 64-bit multiply -mpf 10/8/15
252 binUL = binLL + getBinWidth() - 1;
253 // Build the string name for this bin and add it as a field
254 std::stringstream ss;
255 ss << "Bin" << y << ":" << binLL << "-" << binUL;
256 m_Fields.push_back(statOutput->registerField<CountType>(ss.str().c_str()));
257 }
258 }
259 }
260
261 void outputStatisticFields(StatisticFieldsOutput* statOutput, bool UNUSED(EndOfSimFlag)) override
262 {
263 uint32_t x = 0;
264 statOutput->outputField(m_Fields[x++], getBinsMinValue());
265 statOutput->outputField(m_Fields[x++], getBinsMaxValue());
266 statOutput->outputField(m_Fields[x++], getBinWidth());
267 statOutput->outputField(m_Fields[x++], getNumBins());
268 statOutput->outputField(m_Fields[x++], getValuesSummed());
269 statOutput->outputField(m_Fields[x++], getValuesSquaredSummed());
270 statOutput->outputField(m_Fields[x++], getActiveBinCount());
271 statOutput->outputField(m_Fields[x++], getStatCollectionCount());
272 statOutput->outputField(m_Fields[x++], getItemsBinnedCount());
273
274 if ( true == m_includeOutOfBounds ) {
275 statOutput->outputField(m_Fields[x++], m_OOBMinCount);
276 statOutput->outputField(m_Fields[x++], m_OOBMaxCount);
277 }
278
279 // Do we also need to dump the bin counts on output
280 if ( true == m_dumpBinsOnOutput ) {
281 BinDataType currentBinValue = getBinsMinValue();
282 for ( uint32_t y = 0; y < getNumBins(); y++ ) {
283 statOutput->outputField(m_Fields[x++], getBinCountByBinStart(currentBinValue));
284 // Increment the currentBinValue to get the next bin
285 currentBinValue += getBinWidth();
286 }
287 }
288 }
289
290 bool isStatModeSupported(StatisticBase::StatMode_t mode) const override
291 {
292 switch ( mode ) {
293 case StatisticBase::STAT_MODE_COUNT:
294 case StatisticBase::STAT_MODE_PERIODIC:
295 case StatisticBase::STAT_MODE_DUMP_AT_END:
296 return true;
297 default:
298 return false;
299 }
300 return false;
301 }
302
303private:
304 // Bin Map Definition
305 typedef std::map<BinDataType, CountType> HistoMap_t;
306
307 // Iterator over the histogram bins
308 typedef typename HistoMap_t::iterator HistoMapItr_t;
309
310 // The minimum value in the Histogram
311 BinDataType m_minValue;
312
313 // The width of each Histogram bin
314 NumBinsType m_binWidth;
315
316 // The number of bins to be supported
317 NumBinsType m_numBins;
318
319 // Out of bounds bins
320 CountType m_OOBMinCount;
321 CountType m_OOBMaxCount;
322
323 // Count of Items that have binned, (Different than item count as some
324 // items may be out of bounds and not binned)
325 CountType m_itemsBinnedCount;
326
327 // The sum of all values added into the Histogram, this is calculated and the sum of all values presented
328 // to be entered into the Histogram not with bin-width multiplied by the (max-min)/2 of the bin.
329 BinDataType m_totalSummed;
330
331 // The sum of values added to the Histogram squared. Allows calculation of derivative statistic
332 // values such as variance.
333 BinDataType m_totalSummedSqr;
334
335 // A map of the the bin starts to the bin counts
336 HistoMap_t m_binsMap;
337
338 // Support
339 std::vector<uint32_t> m_Fields;
340 bool m_dumpBinsOnOutput;
341 bool m_includeOutOfBounds;
342};
343
344} // namespace Statistics
345} // namespace SST
346
347#endif // SST_CORE_STATAPI_STATHISTOGRAM_H
Main component object for the simulation.
Definition: baseComponent.h:51
Parameter store.
Definition: params.h:56
void pushAllowedKeys(const KeySet_t &keys)
Definition: params.cc:203
std::enable_if< notstd::is_same< std::string, T >::value, T >::type find(const std::string &k, T default_value, bool &found) const
Find a Parameter value in the set, and return its value as a type T.
Definition: params.h:321
std::set< key_type, KeyCompare > KeySet_t
Definition: params.h:233
Holder of data grouped into pre-determined width bins.
Definition: stathistogram.h:42
void addData_impl_Ntimes(uint64_t N, BinDataType value) override
Adds a new value to the histogram.
Definition: stathistogram.h:91
StatMode_t
Statistic collection mode.
Definition: statbase.h:67
uint64_t getCollectionCount() const
Return the current collection count.
Definition: statbase.h:155
Forms the template defined base class for statistics gathering within SST.
Definition: statbase.h:361