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