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