1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
// histogram.cc
/**
* Copyright (C) 2010 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iomanip>
#include <limits>
#include <sstream>
#include "histogram.h"
namespace mongo {
using std::ostringstream;
using std::setfill;
using std::setw;
Histogram::Histogram( const Options& opts )
: _initialValue( opts.initialValue )
, _numBuckets( opts.numBuckets )
, _boundaries( new uint32_t[_numBuckets] )
, _buckets( new uint64_t[_numBuckets] ) {
// TODO more sanity checks
// + not too few buckets
// + initialBucket and bucketSize fit within 32 bit ints
// _boundaries store the maximum value falling in that bucket.
if ( opts.exponential ) {
uint32_t twoPow = 1; // 2^0
for ( uint32_t i = 0; i < _numBuckets - 1; i++) {
_boundaries[i] = _initialValue + opts.bucketSize * twoPow;
twoPow *= 2; // 2^i+1
}
}
else {
_boundaries[0] = _initialValue + opts.bucketSize;
for ( uint32_t i = 1; i < _numBuckets - 1; i++ ) {
_boundaries[i] = _boundaries[ i-1 ] + opts.bucketSize;
}
}
_boundaries[ _numBuckets-1 ] = std::numeric_limits<uint32_t>::max();
for ( uint32_t i = 0; i < _numBuckets; i++ ) {
_buckets[i] = 0;
}
}
Histogram::~Histogram() {
delete [] _boundaries;
delete [] _buckets;
}
void Histogram::insert( uint32_t element ) {
if ( element < _initialValue) return;
_buckets[ _findBucket(element) ] += 1;
}
string Histogram::toHTML() const {
uint64_t max = 0;
for ( uint32_t i = 0; i < _numBuckets; i++ ) {
if ( _buckets[i] > max ) {
max = _buckets[i];
}
}
if ( max == 0 ) {
return "histogram is empty\n";
}
// normalize buckets to max
const int maxBar = 20;
ostringstream ss;
for ( uint32_t i = 0; i < _numBuckets; i++ ) {
int barSize = _buckets[i] * maxBar / max;
ss << string( barSize,'*' )
<< setfill(' ') << setw( maxBar-barSize + 12 )
<< _boundaries[i] << '\n';
}
return ss.str();
}
uint64_t Histogram::getCount( uint32_t bucket ) const {
if ( bucket >= _numBuckets ) return 0;
return _buckets[ bucket ];
}
uint32_t Histogram::getBoundary( uint32_t bucket ) const {
if ( bucket >= _numBuckets ) return 0;
return _boundaries[ bucket ];
}
uint32_t Histogram::getBucketsNum() const {
return _numBuckets;
}
uint32_t Histogram::_findBucket( uint32_t element ) const {
// TODO assert not too small a value?
uint32_t low = 0;
uint32_t high = _numBuckets - 1;
while ( low < high ) {
// low + ( (high - low) / 2 );
uint32_t mid = ( low + high ) >> 1;
if ( element > _boundaries[ mid ] ) {
low = mid + 1;
}
else {
high = mid;
}
}
return low;
}
} // namespace mongo
|