SST  14.1.0
StructuralSimulationToolkit
stathistogram.h
1 // Copyright 2009-2024 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-2024, 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  HistogramStatistic() : Statistic<BinDataType>() {} // For serialization ONLY
87 
89  {
91  ser& m_minValue;
92  ser& m_binWidth;
93  ser& m_numBins;
94  ser& m_OOBMinCount;
95  ser& m_OOBMaxCount;
96  ser& m_itemsBinnedCount;
97  ser& m_totalSummed;
98  ser& m_totalSummedSqr;
99  ser& m_binsMap;
100  ser& m_dumpBinsOnOutput;
101  ser& m_includeOutOfBounds;
102  // ser& m_Fields; // Rebuilt by stat output object
103  }
104 
105 protected:
106  /**
107  Adds a new value to the histogram. The correct bin is identified and then incremented. If no bin can be found
108  to hold the value then a new bin is created.
109  */
110  void addData_impl_Ntimes(uint64_t N, BinDataType value) override
111  {
112  // Check to see if the value is above or below the min/max values
113  if ( value < getBinsMinValue() ) {
114  m_OOBMinCount += N;
115  return;
116  }
117  if ( value > getBinsMaxValue() ) {
118  m_OOBMaxCount += N;
119  return;
120  }
121 
122  // This value is to be binned...
123  // Add the "in limits" value to the total summation's
124  m_totalSummed += N * value;
125  m_totalSummedSqr += N * (value * value);
126 
127  // Increment the Binned count (note this <= to the Statistics added Item Count)
128  m_itemsBinnedCount++;
129 
130  // Figure out what the starting bin is and find it in the map
131  // To support signed and unsigned values along with floating point types,
132  // the calculation to find the bin_start value must be done in floating point
133  // then converted to BinDataType
134  double calc1 = (double)value / (double)m_binWidth;
135  double calc2 = floor(calc1); // Find the floor of the value
136  double calc3 = m_binWidth * calc2;
137  BinDataType bin_start = (BinDataType)calc3;
138  // printf("DEBUG: value = %d, junk1 = %f, calc2 = %f, calc3 = %f : bin_start = %d, item count = %ld, \n",
139  // value, calc1, calc2, calc3, bin_start, getStatCollectionCount());
140 
141  HistoMapItr_t bin_itr = m_binsMap.find(bin_start);
142 
143  // Was the bin found?
144  if ( bin_itr == m_binsMap.end() ) {
145  // No, Create the bin and set a value of 1 to it
146  m_binsMap.insert(std::pair<BinDataType, CountType>(bin_start, (CountType)N));
147  }
148  else {
149  // Yes, Increment the specific bin's count
150  bin_itr->second += N;
151  }
152  }
153 
154  void addData_impl(BinDataType value) override { addData_impl_Ntimes(1, value); }
155 
156 private:
157  /** Count how many bins are active in this histogram */
158  NumBinsType getActiveBinCount() { return m_binsMap.size(); }
159 
160  /** Count how many bins are available */
161  NumBinsType getNumBins() { return m_numBins; }
162 
163  /** Get the width of a bin in this histogram */
164  NumBinsType getBinWidth() { return m_binWidth; }
165 
166  /**
167  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
168  value X). \return The count of items in the bin else 0.
169  */
170  CountType getBinCountByBinStart(BinDataType binStartValue)
171  {
172  // Find the Bin Start Value in the Bin Map
173  HistoMapItr_t bin_itr = m_binsMap.find(binStartValue);
174 
175  // Check to see if the Start Value was found
176  if ( bin_itr == m_binsMap.end() ) {
177  // No, return no count for this bin
178  return (CountType)0;
179  }
180  else {
181  // Yes, return the bin count
182  return m_binsMap[binStartValue];
183  }
184  }
185 
186  /**
187  Get the smallest start value of a bin in this histogram (i.e. the minimum value possibly represented by this
188  histogram)
189  */
190  BinDataType getBinsMinValue() { return m_minValue; }
191 
192  /**
193  Get the largest possible value represented by this histogram (i.e. the highest value in any of items bins
194  rounded above to the size of the bin)
195  */
196  BinDataType getBinsMaxValue()
197  {
198  // Compute the max value based on the width * num bins offset by minvalue
199  return (m_binWidth * m_numBins) + m_minValue - 1;
200  }
201 
202  /**
203  Get the total number of items collected by the statistic
204  \return The number of items that have been added to the statistic
205  */
206  uint64_t getStatCollectionCount()
207  {
208  // Get the number of items added (but not necessarily binned) to this statistic
209  return this->getCollectionCount();
210  }
211 
212  /**
213  Get the total number of items contained in all bins
214  \return The number of items contained in all bins
215  */
216  CountType getItemsBinnedCount()
217  {
218  // Get the number of items added to this statistic that were binned.
219  return m_itemsBinnedCount;
220  }
221 
222  /**
223  Sum up every item presented for storage in the histogram
224  \return The sum of all values added into the histogram
225  */
226  BinDataType getValuesSummed() { return m_totalSummed; }
227 
228  /**
229  Sum up every squared value entered into the Histogram.
230  \return The sum of all values added after squaring into the Histogram
231  */
232  BinDataType getValuesSquaredSummed() { return m_totalSummedSqr; }
233 
234  void clearStatisticData() override
235  {
236  m_totalSummed = 0;
237  m_totalSummedSqr = 0;
238  m_OOBMinCount = 0;
239  m_OOBMaxCount = 0;
240  m_itemsBinnedCount = 0;
241  m_binsMap.clear();
242  this->setCollectionCount(0);
243  }
244 
245  void registerOutputFields(StatisticFieldsOutput* statOutput) override
246  {
247  // Check to see if we have registered the Startup Fields
248  m_Fields.push_back(statOutput->registerField<BinDataType>("BinsMinValue"));
249  m_Fields.push_back(statOutput->registerField<BinDataType>("BinsMaxValue"));
250  m_Fields.push_back(statOutput->registerField<NumBinsType>("BinWidth"));
251  m_Fields.push_back(statOutput->registerField<NumBinsType>("TotalNumBins"));
252  m_Fields.push_back(statOutput->registerField<BinDataType>("Sum"));
253  m_Fields.push_back(statOutput->registerField<BinDataType>("SumSQ"));
254  m_Fields.push_back(statOutput->registerField<NumBinsType>("NumActiveBins"));
255  m_Fields.push_back(statOutput->registerField<CountType>("NumItemsCollected"));
256  m_Fields.push_back(statOutput->registerField<CountType>("NumItemsBinned"));
257 
258  if ( true == m_includeOutOfBounds ) {
259  m_Fields.push_back(statOutput->registerField<CountType>("NumOutOfBounds-MinValue"));
260  m_Fields.push_back(statOutput->registerField<CountType>("NumOutOfBounds-MaxValue"));
261  }
262 
263  // Do we also need to dump the bin counts on output
264  if ( true == m_dumpBinsOnOutput ) {
265  BinDataType binLL;
266  BinDataType binUL;
267 
268  for ( uint32_t y = 0; y < getNumBins(); y++ ) {
269  // Figure out the upper and lower values for this bin
270  binLL = (y * (uint64_t)getBinWidth()) + getBinsMinValue(); // Force full 64-bit multiply -mpf 10/8/15
271  binUL = binLL + getBinWidth() - 1;
272  // Build the string name for this bin and add it as a field
273  std::stringstream ss;
274  ss << "Bin" << y << ":" << binLL << "-" << binUL;
275  m_Fields.push_back(statOutput->registerField<CountType>(ss.str().c_str()));
276  }
277  }
278  }
279 
280  void outputStatisticFields(StatisticFieldsOutput* statOutput, bool UNUSED(EndOfSimFlag)) override
281  {
282  StatisticOutput::fieldHandle_t x = 0;
283  statOutput->outputField(m_Fields[x++], getBinsMinValue());
284  statOutput->outputField(m_Fields[x++], getBinsMaxValue());
285  statOutput->outputField(m_Fields[x++], getBinWidth());
286  statOutput->outputField(m_Fields[x++], getNumBins());
287  statOutput->outputField(m_Fields[x++], getValuesSummed());
288  statOutput->outputField(m_Fields[x++], getValuesSquaredSummed());
289  statOutput->outputField(m_Fields[x++], getActiveBinCount());
290  statOutput->outputField(m_Fields[x++], getStatCollectionCount());
291  statOutput->outputField(m_Fields[x++], getItemsBinnedCount());
292 
293  if ( true == m_includeOutOfBounds ) {
294  statOutput->outputField(m_Fields[x++], m_OOBMinCount);
295  statOutput->outputField(m_Fields[x++], m_OOBMaxCount);
296  }
297 
298  // Do we also need to dump the bin counts on output
299  if ( true == m_dumpBinsOnOutput ) {
300  BinDataType currentBinValue = getBinsMinValue();
301  for ( uint32_t y = 0; y < getNumBins(); y++ ) {
302  statOutput->outputField(m_Fields[x++], getBinCountByBinStart(currentBinValue));
303  // Increment the currentBinValue to get the next bin
304  currentBinValue += getBinWidth();
305  }
306  }
307  }
308 
309  bool isStatModeSupported(StatisticBase::StatMode_t mode) const override
310  {
311  switch ( mode ) {
312  case StatisticBase::STAT_MODE_COUNT:
313  case StatisticBase::STAT_MODE_PERIODIC:
314  case StatisticBase::STAT_MODE_DUMP_AT_END:
315  return true;
316  default:
317  return false;
318  }
319  return false;
320  }
321 
322 private:
323  // Bin Map Definition
324  typedef std::map<BinDataType, CountType> HistoMap_t;
325 
326  // Iterator over the histogram bins
327  typedef typename HistoMap_t::iterator HistoMapItr_t;
328 
329  // The minimum value in the Histogram
330  BinDataType m_minValue;
331 
332  // The width of each Histogram bin
333  NumBinsType m_binWidth;
334 
335  // The number of bins to be supported
336  NumBinsType m_numBins;
337 
338  // Out of bounds bins
339  CountType m_OOBMinCount;
340  CountType m_OOBMaxCount;
341 
342  // Count of Items that have binned, (Different than item count as some
343  // items may be out of bounds and not binned)
344  CountType m_itemsBinnedCount;
345 
346  // The sum of all values added into the Histogram, this is calculated and the sum of all values presented
347  // to be entered into the Histogram not with bin-width multiplied by the (max-min)/2 of the bin.
348  BinDataType m_totalSummed;
349 
350  // The sum of values added to the Histogram squared. Allows calculation of derivative statistic
351  // values such as variance.
352  BinDataType m_totalSummedSqr;
353 
354  // A map of the the bin starts to the bin counts
355  HistoMap_t m_binsMap;
356 
357  // Support
358  std::vector<StatisticOutput::fieldHandle_t> m_Fields;
359  bool m_dumpBinsOnOutput;
360  bool m_includeOutOfBounds;
361 };
362 
363 } // namespace Statistics
364 } // namespace SST
365 
366 #endif // SST_CORE_STATAPI_STATHISTOGRAM_H
This class is basically a wrapper for objects to declare the order in which their members should be s...
Definition: serializer.h:43
void pushAllowedKeys(const KeySet_t &keys)
Definition: params.cc:226
Definition: action.cc:18
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:45
void addData_impl_Ntimes(uint64_t N, BinDataType value) override
Adds a new value to the histogram.
Definition: stathistogram.h:110
void serialize_order(SST::Core::Serialization::serializer &ser) override
Serialization.
Definition: stathistogram.h:88
Main component object for the simulation.
Definition: baseComponent.h:62
StatMode_t
Statistic collection mode.
Definition: statbase.h:49
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
Parameter store.
Definition: params.h:55
std::set< key_type, KeyCompare > KeySet_t
Definition: params.h:233
virtual void serialize_order(SST::Core::Serialization::serializer &ser) override
Serialization.
Definition: statbase.h:389
uint64_t getCollectionCount() const
Return the current collection count.
Definition: statbase.h:137