blob: db1b77cbace85cb4f5561e4a7cfabf9a1911eda9 (
plain) (
blame)
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
|
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
#include "metricvalueset.h"
#include <sstream>
namespace metrics {
template<typename ValueClass>
MetricValueSet<ValueClass>::MetricValueSet() noexcept
: _values(),
_activeValueIndex(0),
_flags(0)
{ }
template<typename ValueClass>
MetricValueSet<ValueClass>::MetricValueSet(const MetricValueSet& rhs) noexcept
: _values(rhs._values),
_activeValueIndex(rhs._activeValueIndex.load(std::memory_order_relaxed)),
_flags(rhs._flags.load(std::memory_order_relaxed))
{ }
template<typename ValueClass>
MetricValueSet<ValueClass> & MetricValueSet<ValueClass>::operator=(const MetricValueSet& other) noexcept
{
setValues(other.getValues());
return *this;
}
template<typename ValueClass>
ValueClass
MetricValueSet<ValueClass>::getValues() const {
ValueClass v{};
if (!isReset()) {
// Must load with acquire to match release store in setValues.
// Note that despite being atomic on _individual fields_, this
// does not guarantee reading a consistent snapshot _across_
// fields for any given metric.
const size_t readIndex(_activeValueIndex.load(std::memory_order_acquire));
v.relaxedLoadFrom(_values[readIndex]);
}
return v;
}
template<typename ValueClass>
bool
MetricValueSet<ValueClass>::setValues(const ValueClass& values) {
// Only setter-thread can write _activeValueIndex, so relaxed
// load suffices.
uint32_t nextIndex = (_activeValueIndex.load(std::memory_order_relaxed) + 1) % _values.size();
// Reset flag is loaded/stored with relaxed semantics since it does not
// carry data dependencies. _activeValueIndex has a dependency on
// _values, however, so we must ensure that stores are published
// and loads acquired.
if (isReset()) {
removeFlag(RESET);
ValueClass resetValues{};
resetValues.relaxedStoreInto(_values[nextIndex]);
_activeValueIndex.store(nextIndex, std::memory_order_release);
return false;
} else {
values.relaxedStoreInto(_values[nextIndex]);
_activeValueIndex.store(nextIndex, std::memory_order_release);
return true;
}
}
template<typename ValueClass>
std::string
MetricValueSet<ValueClass>::toString() {
std::ostringstream ost;
ost << "MetricValueSet(reset=" << (isReset() ? "true" : "false")
<< ", active " << _activeValueIndex;
#if 0
ost << "\n empty: " << ValueClass().toString("unknown");
for (uint32_t i=0; i<_values.size(); ++i) {
ost << "\n " << _values[i].toString("unknown");
}
#endif
ost << "\n)";
return ost.str();
}
} // metrics
|