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