SST  9.0.0
StructuralSimulationToolkit
stathistogram.h
1 // Copyright 2009-2019 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-2019, 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(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++;
98  return;
99  }
100  if (value > getBinsMaxValue()) {
101  m_OOBMaxCount++;
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 += value;
108  m_totalSummedSqr += (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) 1));
129  } else {
130  // Yes, Increment the specific bin's count
131  bin_itr->second++;
132  }
133  }
134 
135 private:
136  /** Count how many bins are active in this histogram */
137  NumBinsType getActiveBinCount()
138  {
139  return m_binsMap.size();
140  }
141 
142  /** Count how many bins are available */
143  NumBinsType getNumBins()
144  {
145  return m_numBins;
146  }
147 
148  /** Get the width of a bin in this histogram */
149  NumBinsType getBinWidth()
150  {
151  return m_binWidth;
152  }
153 
154  /**
155  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).
156  \return The count of items in the bin else 0.
157  */
158  CountType getBinCountByBinStart(BinDataType binStartValue)
159  {
160  // Find the Bin Start Value in the Bin Map
161  HistoMapItr_t bin_itr = m_binsMap.find(binStartValue);
162 
163  // Check to see if the Start Value was found
164  if(bin_itr == m_binsMap.end()) {
165  // No, return no count for this bin
166  return (CountType) 0;
167  } else {
168  // Yes, return the bin count
169  return m_binsMap[binStartValue];
170  }
171  }
172 
173  /**
174  Get the smallest start value of a bin in this histogram (i.e. the minimum value possibly represented by this histogram)
175  */
176  BinDataType getBinsMinValue()
177  {
178  return m_minValue;
179  }
180 
181  /**
182  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)
183  */
184  BinDataType getBinsMaxValue()
185  {
186  // Compute the max value based on the width * num bins offset by minvalue
187  return (m_binWidth * m_numBins) + m_minValue - 1;
188  }
189 
190  /**
191  Get the total number of items collected by the statistic
192  \return The number of items that have been added to the statistic
193  */
194  uint64_t getStatCollectionCount()
195  {
196  // Get the number of items added (but not necessarily binned) to this statistic
197  return this->getCollectionCount();
198  }
199 
200  /**
201  Get the total number of items contained in all bins
202  \return The number of items contained in all bins
203  */
204  CountType getItemsBinnedCount()
205  {
206  // Get the number of items added to this statistic that were binned.
207  return m_itemsBinnedCount;
208  }
209 
210  /**
211  Sum up every item presented for storage in the histogram
212  \return The sum of all values added into the histogram
213  */
214  BinDataType getValuesSummed()
215  {
216  return m_totalSummed;
217  }
218 
219  /**
220  Sum up every squared value entered into the Histogram.
221  \return The sum of all values added after squaring into the Histogram
222  */
223  BinDataType getValuesSquaredSummed() {
224  return m_totalSummedSqr;
225  }
226 
227  void clearStatisticData() override
228  {
229  m_totalSummed = 0;
230  m_totalSummedSqr = 0;
231  m_OOBMinCount = 0;
232  m_OOBMaxCount = 0;
233  m_itemsBinnedCount = 0;
234  m_binsMap.clear();
235  this->setCollectionCount(0);
236  }
237 
238  void registerOutputFields(StatisticOutput* statOutput) override
239  {
240  // Check to see if we have registered the Startup Fields
241  m_Fields.push_back(statOutput->registerField<BinDataType>("BinsMinValue"));
242  m_Fields.push_back(statOutput->registerField<BinDataType>("BinsMaxValue"));
243  m_Fields.push_back(statOutput->registerField<NumBinsType>("BinWidth"));
244  m_Fields.push_back(statOutput->registerField<NumBinsType>("TotalNumBins"));
245  m_Fields.push_back(statOutput->registerField<BinDataType>("Sum"));
246  m_Fields.push_back(statOutput->registerField<BinDataType>("SumSQ"));
247  m_Fields.push_back(statOutput->registerField<NumBinsType>("NumActiveBins"));
248  m_Fields.push_back(statOutput->registerField<CountType> ("NumItemsCollected"));
249  m_Fields.push_back(statOutput->registerField<CountType> ("NumItemsBinned"));
250 
251  if (true == m_includeOutOfBounds) {
252  m_Fields.push_back(statOutput->registerField<CountType>("NumOutOfBounds-MinValue"));
253  m_Fields.push_back(statOutput->registerField<CountType>("NumOutOfBounds-MaxValue"));
254  }
255 
256  // Do we also need to dump the bin counts on output
257  if (true == m_dumpBinsOnOutput) {
258  BinDataType binLL;
259  BinDataType binUL;
260 
261  for (uint32_t y = 0; y < getNumBins(); y++) {
262  // Figure out the upper and lower values for this bin
263  binLL = (y * (uint64_t)getBinWidth()) + getBinsMinValue(); // Force full 64-bit multiply -mpf 10/8/15
264  binUL = binLL + getBinWidth() - 1;
265  // Build the string name for this bin and add it as a field
266  std::stringstream ss;
267  ss << "Bin" << y << ":" << binLL << "-" << binUL;
268  m_Fields.push_back(statOutput->registerField<CountType>(ss.str().c_str()));
269  }
270  }
271  }
272 
273  void outputStatisticData(StatisticOutput* statOutput, bool UNUSED(EndOfSimFlag)) override
274  {
275  uint32_t x = 0;
276  statOutput->outputField(m_Fields[x++], getBinsMinValue());
277  statOutput->outputField(m_Fields[x++], getBinsMaxValue());
278  statOutput->outputField(m_Fields[x++], getBinWidth());
279  statOutput->outputField(m_Fields[x++], getNumBins());
280  statOutput->outputField(m_Fields[x++], getValuesSummed());
281  statOutput->outputField(m_Fields[x++], getValuesSquaredSummed());
282  statOutput->outputField(m_Fields[x++], getActiveBinCount());
283  statOutput->outputField(m_Fields[x++], getStatCollectionCount());
284  statOutput->outputField(m_Fields[x++], getItemsBinnedCount());
285 
286  if (true == m_includeOutOfBounds) {
287  statOutput->outputField(m_Fields[x++], m_OOBMinCount);
288  statOutput->outputField(m_Fields[x++], m_OOBMaxCount);
289  }
290 
291  // Do we also need to dump the bin counts on output
292  if (true == m_dumpBinsOnOutput) {
293  BinDataType currentBinValue = getBinsMinValue();
294  for (uint32_t y = 0; y < getNumBins(); y++) {
295  statOutput->outputField(m_Fields[x++], getBinCountByBinStart(currentBinValue));
296  // Increment the currentBinValue to get the next bin
297  currentBinValue += getBinWidth();
298  }
299  }
300  }
301 
302  bool isStatModeSupported(StatisticBase::StatMode_t mode) const override
303  {
304  if (mode == StatisticBase::STAT_MODE_COUNT) {
305  return true;
306  }
307  if (mode == StatisticBase::STAT_MODE_PERIODIC) {
308  return true;
309  }
310  return false;
311  }
312 
313 private:
314  // Bin Map Definition
315  typedef std::map<BinDataType, CountType> HistoMap_t;
316 
317  // Iterator over the histogram bins
318  typedef typename HistoMap_t::iterator HistoMapItr_t;
319 
320  // The minimum value in the Histogram
321  BinDataType m_minValue;
322 
323  // The width of each Histogram bin
324  NumBinsType m_binWidth;
325 
326  // The number of bins to be supported
327  NumBinsType m_numBins;
328 
329  // Out of bounds bins
330  CountType m_OOBMinCount;
331  CountType m_OOBMaxCount;
332 
333  // Count of Items that have binned, (Different than item count as some
334  // items may be out of bounds and not binned)
335  CountType m_itemsBinnedCount;
336 
337  // The sum of all values added into the Histogram, this is calculated and the sum of all values presented
338  // to be entered into the Histogram not with bin-width multiplied by the (max-min)/2 of the bin.
339  BinDataType m_totalSummed;
340 
341  // The sum of values added to the Histogram squared. Allows calculation of derivative statistic
342  // values such as variance.
343  BinDataType m_totalSummedSqr;
344 
345  // A map of the the bin starts to the bin counts
346  HistoMap_t m_binsMap;
347 
348  // Support
349  std::vector<uint32_t> m_Fields;
350  bool m_dumpBinsOnOutput;
351  bool m_includeOutOfBounds;
352 
353 };
354 
355 } //namespace Statistics
356 } //namespace SST
357 
358 #endif
void pushAllowedKeys(const KeySet_t &keys)
Definition: params.cc:179
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:238
uint64_t getCollectionCount() const
Return the current collection count.
Definition: statbase.h:149
Holder of data grouped into pre-determined width bins.
Definition: stathistogram.h:43
void addData_impl(BinDataType value) override
Adds a new value to the histogram.
Definition: stathistogram.h:93
Forms the template defined base class for statistics gathering within SST.
Definition: elementinfo.h:43
Main component object for the simulation.
Definition: baseComponent.h:52
StatMode_t
Statistic collection mode.
Definition: statbase.h:67
Parameter store.
Definition: params.h:45
std::set< key_type, KeyCompare > KeySet_t
Definition: params.h:172