+/*
+* Histogram represents the distribution of data, it has a list of "bins".
+* Each bin represents an interval and has a count (frequency) of
+* number of values fall within its interval.
+*
+* Histogram's range is determined by the number of bins and the bin width,
+* There are 1000 bins and all bins have the same width of default 1 millisecond.
+* When a value above this range is added, Histogram's range is increased by
+* increasing the bin width (note that number of bins remains always at 1000).
+* This operation of increasing bin width is little expensive as each bin need
+* to be visited to update it's count. To reduce frequent change of bin width,
+* new bin width will be the next nearest power of 2. Example: 2, 4, 8, 16, 32,
+* 64, 128, 256, 512, 1024, 2048, 5086, ...
+*
+* So, if the required bin width is 300, then new bin width will be 512 as it is
+* the next nearest power of 2.
+*
+*/
+void change_bin_width (latency_counter_t *lc, size_t val) /* {{{ */
+{
+ int i=0;
+ /* This function is called because the new value is above histogram's range.
+ * First find the required bin width:
+ * requiredBinWidth = (value + 1) / numBins
+ * then get the next nearest power of 2
+ * newBinWidth = 2^(ceil(log2(requiredBinWidth)))
+ */
+ double required_bin_width = (double)(val + 1) / HISTOGRAM_NUM_BINS;
+ double required_bin_width_logbase2 = log(required_bin_width) / log(2.0);
+ int new_bin_width = (int)(pow(2.0, ceil( required_bin_width_logbase2)));
+ int old_bin_width = lc->bin_width;
+ lc->bin_width = new_bin_width;
+
+ /*
+ * bin width has been increased, now iterate through all bins and move the
+ * old bin's count to new bin.
+ */
+ if (lc->num > 0) // if the histogram has data then iterate else skip
+ {
+ double width_change_ratio = old_bin_width / new_bin_width;
+ for (i=0; i<HISTOGRAM_NUM_BINS; i++)
+ {
+ int new_bin = (int)(i * width_change_ratio);
+ if (i == new_bin)
+ continue;
+ lc->histogram[new_bin] += lc->histogram[i];
+ lc->histogram[i] = 0;
+ }
+ DEBUG("utils_latency: change_bin_width: fixed all bins");
+ }
+
+ DEBUG("utils_latency: change_bin_width: val-[%zu], oldBinWidth-[%d], "
+ "newBinWidth-[%d], required_bin_width-[%f], "
+ "required_bin_width_logbase2-[%f]",
+ val, old_bin_width, new_bin_width, required_bin_width,
+ required_bin_width_logbase2);
+
+} /* }}} void change_bin_width */
+