Skip to content

Commit 09771ed

Browse files
committed
Refactor: Wrap hdr_histogram in its own class
Wraps the hdr_histogram data structure in its own class (HdrHistogram) thereby making it possible to use (for example to hold statistics) without needing to refer directly to the underlying C data structure. Change-Id: I4d4475cbbc41ff45250ba4940fe7b4e1cf2dd177 Reviewed-on: http://review.couchbase.org/93536 Reviewed-by: Dave Rigby <[email protected]> Tested-by: Build Bot <[email protected]>
1 parent 27780ed commit 09771ed

File tree

6 files changed

+294
-67
lines changed

6 files changed

+294
-67
lines changed

engines/ep/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ ADD_LIBRARY(ep_objs OBJECT
205205
src/flusher.cc
206206
src/globaltask.cc
207207
src/hash_table.cc
208+
src/hdrhistogram.cc
208209
src/hlc.cc
209210
src/htresizer.cc
210211
src/item.cc

engines/ep/src/hdrhistogram.cc

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2+
/*
3+
* Copyright 2018 Couchbase, Inc
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "hdrhistogram.h"
19+
20+
#include <cstdlib> // Required due to the use of free
21+
22+
// Custom deleter for the hdr_histogram struct.
23+
void HdrHistogram::HdrDeleter::operator()(struct hdr_histogram* val) {
24+
free(val);
25+
}
26+
27+
HdrHistogram::HdrHistogram(uint64_t lowestTrackableValue,
28+
uint64_t highestTrackableValue,
29+
int significantFigures) {
30+
struct hdr_histogram* hist;
31+
// We add a bias of +1 to the lowest and highest trackable value
32+
// because we add +1 to all values we store in the histogram (as this
33+
// allows us to record the value 0).
34+
hdr_init(lowestTrackableValue + 1,
35+
highestTrackableValue + 1, // Add one because all values
36+
significantFigures,
37+
&hist); // Pointer to initialise
38+
histogram.reset(hist);
39+
}
40+
41+
void HdrHistogram::addValue(uint64_t v) {
42+
// A hdr_histogram cannot store 0, therefore we add a bias of +1.
43+
int64_t vBiased = v + 1;
44+
hdr_record_value(histogram.get(), vBiased);
45+
}
46+
47+
void HdrHistogram::addValueAndCount(uint64_t v, uint64_t count) {
48+
// A hdr_histogram cannot store 0, therefore we add a bias of +1.
49+
int64_t vBiased = v + 1;
50+
hdr_record_values(histogram.get(), vBiased, count);
51+
}
52+
53+
uint64_t HdrHistogram::getValueCount() const {
54+
return histogram->total_count;
55+
}
56+
57+
void HdrHistogram::reset() {
58+
hdr_reset(histogram.get());
59+
}
60+
61+
uint64_t HdrHistogram::getValueAtPercentile(double percentage) const {
62+
// We added the bias of +1 to the input value (see
63+
// addValueToFreqHistogram). Therefore need to minus the bias
64+
// before returning the value from the histogram.
65+
uint64_t value = hdr_value_at_percentile(histogram.get(), percentage);
66+
return (value - 1);
67+
}
68+
69+
HdrHistogram::Iterator HdrHistogram::makeLinearIterator(
70+
int64_t valueUnitsPerBucket) const {
71+
HdrHistogram::Iterator iter;
72+
hdr_iter_linear_init(&iter, histogram.get(), valueUnitsPerBucket);
73+
return iter;
74+
}
75+
76+
boost::optional<std::pair<uint64_t, uint64_t>>
77+
HdrHistogram::getNextValueAndCount(Iterator& iter) const {
78+
boost::optional<std::pair<uint64_t, uint64_t>> valueAndCount;
79+
if (hdr_iter_next(&iter)) {
80+
uint64_t value = iter.value;
81+
uint64_t count = hdr_count_at_value(histogram.get(), value);
82+
// We added the bias of +1 to the input value (see
83+
// addValueToFreqHistogram). Therefore need to minus the bias
84+
// before returning value.
85+
return valueAndCount = std::make_pair(value - 1, count);
86+
} else {
87+
return valueAndCount;
88+
}
89+
}

engines/ep/src/hdrhistogram.h

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2+
/*
3+
* Copyright 2018 Couchbase, Inc
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#pragma once
19+
20+
#include <boost/optional/optional.hpp>
21+
#include <memory>
22+
#include <utility>
23+
24+
#include <hdr_histogram.h>
25+
26+
/**
27+
* A container for the c hdr_histogram data structure.
28+
*
29+
*/
30+
class HdrHistogram {
31+
// Custom deleter for the hdr_histogram struct.
32+
struct HdrDeleter {
33+
void operator()(struct hdr_histogram* val);
34+
};
35+
36+
using UniquePtr = std::unique_ptr<struct hdr_histogram, HdrDeleter>;
37+
38+
public:
39+
#ifdef WIN32
40+
/**
41+
* The following typedef is required because of an issue msvc2015 where
42+
* use of HdrHistogram::Iterator in statwriter.h causes the following
43+
* error:
44+
* C2079: 'iter' uses undefined struct 'HdrHistogram::hdr_iter'
45+
*/
46+
typedef struct hdr_iter HdrIter;
47+
using Iterator = HdrIter;
48+
#else
49+
using Iterator = struct hdr_iter;
50+
#endif
51+
52+
/**
53+
* Constructor for the histogram.
54+
* @param lowestTrackableValue smallest value that can be held in the
55+
* histogram. Note the underlying hdr_histogram cannot store 0 and
56+
* therefore the value must be greater than or equal to 1.
57+
* @param highestTrackableValue the largest values that can be held in
58+
* the histogram
59+
* @param sigificantFigures the level of precision for the histogram.
60+
* Note the underlying hdr_histogram requires the value to be
61+
* between 1 and 5 (inclusive).
62+
*/
63+
HdrHistogram(uint64_t lowestTrackableValue,
64+
uint64_t highestTrackableValue,
65+
int significantFigures);
66+
67+
/**
68+
* Adds a value to the histogram.
69+
*/
70+
void addValue(uint64_t v);
71+
72+
/**
73+
* Adds a value and associated count to the histogram.
74+
*/
75+
void addValueAndCount(uint64_t v, uint64_t count);
76+
77+
/**
78+
* Returns the number of values added to the histogram.
79+
*/
80+
uint64_t getValueCount() const;
81+
82+
/**
83+
* Clears the histogram.
84+
*/
85+
void reset();
86+
87+
/**
88+
* Returns the value held in the histogram at the percentile defined by
89+
* the input parameter percentage.
90+
*/
91+
uint64_t getValueAtPercentile(double percentage) const;
92+
93+
/**
94+
* Returns a linear iterator for the histogram
95+
* @param valueUnitsPerBucket the number of values to be grouped into
96+
* a single bucket
97+
*/
98+
Iterator makeLinearIterator(int64_t valueUnitsPerBucket) const;
99+
100+
/**
101+
* Gets the next value and corresponding count from the histogram
102+
* Returns an optional pair, comprising of:
103+
* 1) value
104+
* 2) count associated with the value
105+
* The pair is optional because iterating past the last value in the
106+
* histogram will return no result.
107+
*/
108+
boost::optional<std::pair<uint64_t, uint64_t>> getNextValueAndCount(
109+
Iterator& iter) const;
110+
111+
private:
112+
/**
113+
* unique_ptr to a hdr_histogram structure
114+
*/
115+
UniquePtr histogram;
116+
};

engines/ep/src/item_eviction.cc

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,45 +19,32 @@
1919
#include "item.h"
2020

2121
#include <gsl/gsl>
22-
#include <limits>
2322

24-
#include <hdr_histogram.h>
25-
26-
ItemEviction::ItemEviction() : requiredToUpdateInterval(learningPopulation) {
27-
struct hdr_histogram* hist;
28-
hdr_init(minFreqValue,
29-
maxFreqValue,
30-
3, // Number of significant figures
31-
&hist); // Pointer to initialise
32-
freqHistogram.reset(hist);
23+
ItemEviction::ItemEviction() {
3324
}
3425

3526
void ItemEviction::addValueToFreqHistogram(uint8_t v) {
36-
// A hdr_histogram cannot store 0. Therefore we add one so the
37-
// range moves from 0 -> 255 to 1 -> 256.
38-
int64_t vBiased = v + 1;
39-
hdr_record_value(freqHistogram.get(), vBiased);
27+
freqHistogram.addValue(v);
4028
}
4129

4230
uint64_t ItemEviction::getFreqHistogramValueCount() const {
43-
return freqHistogram->total_count;
31+
return freqHistogram.getValueCount();
4432
}
4533

4634
void ItemEviction::reset() {
47-
hdr_reset(freqHistogram.get());
35+
freqHistogram.reset();
36+
requiredToUpdateInterval = 1;
4837
}
4938

5039
uint16_t ItemEviction::getFreqThreshold(double percentage) const {
51-
// We added one to the input value (see addValueToFreqHistogram).
52-
// Therefore need to minus one before returning value from the histogram.
5340
uint16_t freq = gsl::narrow<uint16_t>(
54-
hdr_value_at_percentile(freqHistogram.get(), percentage));
55-
return (freq - 1);
41+
freqHistogram.getValueAtPercentile(percentage));
42+
return freq;
5643
}
5744

58-
uint8_t ItemEviction::convertFreqCountToNRUValue(uint8_t statCounter) {
45+
uint8_t ItemEviction::convertFreqCountToNRUValue(uint8_t probCounter) {
5946
/*
60-
* The statstical counter has a range form 0 to 255, however the
47+
* The probabilistic counter has a range form 0 to 255, however the
6148
* increments are not linear - it gets more difficult to increment the
6249
* counter as its increases value. Therefore incrementing from 0 to 1 is
6350
* much easier than incrementing from 254 to 255.
@@ -67,11 +54,11 @@ uint8_t ItemEviction::convertFreqCountToNRUValue(uint8_t statCounter) {
6754
* in the 4 NRU states. Therefore we map as follows:
6855
* 0-3 => 3 (coldest), 4-31 => 2, 32->63 => 1, 64->255 => 0 (hottest),
6956
*/
70-
if (statCounter >= 64) {
57+
if (probCounter >= 64) {
7158
return MIN_NRU_VALUE; /* 0 - the hottest */
72-
} else if (statCounter >= 32) {
59+
} else if (probCounter >= 32) {
7360
return 1;
74-
} else if (statCounter >= 4) {
61+
} else if (probCounter >= 4) {
7562
return INITIAL_NRU_VALUE; /* 2 */
7663
}
7764
return MAX_NRU_VALUE; /* 3 - the coldest */

engines/ep/src/item_eviction.h

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@
1717

1818
#pragma once
1919

20-
#include <atomic>
20+
#include "hdrhistogram.h"
21+
2122
#include <cstdlib> // Required due to the use of free
2223
#include <limits>
23-
#include <memory>
24-
25-
#include <hdr_histogram.h>
2624

2725
/**
2826
* A container for data structures that are used in the algorithm for
@@ -73,7 +71,8 @@ class ItemEviction {
7371
// Returns the number of values added to the frequency histogram.
7472
uint64_t getFreqHistogramValueCount() const;
7573

76-
// Clears the frequency histogram.
74+
// Clears the frequency histogram and sets the requiredToUpdateInterval
75+
// back to 1.
7776
void reset();
7877

7978
// StatCounter: Returns the value held in the frequency histogram at the
@@ -111,22 +110,26 @@ class ItemEviction {
111110
static const uint64_t learningPopulation = 100;
112111

113112
private:
114-
// unique_ptr to a hdr_histogram structure, used to record a
115-
// histogram of key reference frequencies. For example, if two keys
116-
// are referenced 10 times, whilst three keys are referenced 20 times,
117-
// the histogram would contain 2 at the 10 entry and 3 at the 20
118-
// entry.
119-
HdrHistogramUniquePtr freqHistogram;
120-
121113
// The minimum value that can be added to the frequency histogram
122-
const int64_t minFreqValue = 1; // hdr_histogram cannot take 0
114+
static const uint64_t minFreqValue = 0;
115+
123116
// The maximum value that can be added to the frequency histogram
124-
// Because we cannot store 0 we have to offset by 1 so we have a maximum
125-
// of 256, instead of 255.
126-
const int64_t maxFreqValue = std::numeric_limits<uint8_t>::max() + 1;
117+
static const uint64_t maxFreqValue = std::numeric_limits<uint8_t>::max();
118+
119+
// The level of precision for the histogram. The value must be between 1
120+
// and 5 (inclusive).
121+
static const int significantFigures = 3;
122+
123+
// The value units per bucket that we use when creating the iterator
124+
// that traverses over the frequency histogram in the copyToHistogram
125+
// method.
126+
static const int valueUnitsPerBucket = 1;
127+
128+
// The execution frequency histogram
129+
HdrHistogram freqHistogram{minFreqValue, maxFreqValue, significantFigures};
127130

128131
// StatCounter: The number of frequencies that need to be added to the
129132
// frequency histogram before it is necessary to update the frequency
130133
// threshold.
131-
uint64_t requiredToUpdateInterval;
134+
uint64_t requiredToUpdateInterval{1};
132135
};

0 commit comments

Comments
 (0)