SST  12.0.0
StructuralSimulationToolkit
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 
20 namespace SST {
21 namespace 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 
40 template <class BinDataType>
41 class HistogramStatistic : public Statistic<BinDataType>
42 {
43 public:
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 
84  ~HistogramStatistic() {}
85 
86 protected:
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 
137 private:
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 
303 private:
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
void pushAllowedKeys(const KeySet_t &keys)
Definition: params.cc:203
uint64_t getCollectionCount() const
Return the current collection count.
Definition: statbase.h:155
Holder of data grouped into pre-determined width bins.
Definition: stathistogram.h:41
Forms the template defined base class for statistics gathering within SST.
Definition: elementinfo.h:42
void addData_impl_Ntimes(uint64_t N, BinDataType value) override
Adds a new value to the histogram.
Definition: stathistogram.h:91
Main component object for the simulation.
Definition: baseComponent.h:49
StatMode_t
Statistic collection mode.
Definition: statbase.h:67
Parameter store.
Definition: params.h:55
std::set< key_type, KeyCompare > KeySet_t
Definition: params.h:233
std::enable_if< not std::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