diff options
49 files changed, 833 insertions, 559 deletions
diff --git a/staging_vespalib/src/tests/metrics/CMakeLists.txt b/staging_vespalib/src/tests/metrics/CMakeLists.txt index 5319511e769..fc9a496c972 100644 --- a/staging_vespalib/src/tests/metrics/CMakeLists.txt +++ b/staging_vespalib/src/tests/metrics/CMakeLists.txt @@ -6,3 +6,11 @@ vespa_add_executable(staging_vespalib_metrics_test_app TEST staging_vespalib ) vespa_add_test(NAME staging_vespalib_metrics_test_app COMMAND staging_vespalib_metrics_test_app) + +vespa_add_executable(staging_vespalib_stablestore_test_app TEST + SOURCES + stable_store_test.cpp + DEPENDS + staging_vespalib +) +vespa_add_test(NAME staging_vespalib_stablestore_test_app COMMAND staging_vespalib_stablestore_test_app) diff --git a/staging_vespalib/src/tests/metrics/simple_metrics_test.cpp b/staging_vespalib/src/tests/metrics/simple_metrics_test.cpp index 0adef8d353f..1bd10d90384 100644 --- a/staging_vespalib/src/tests/metrics/simple_metrics_test.cpp +++ b/staging_vespalib/src/tests/metrics/simple_metrics_test.cpp @@ -2,7 +2,7 @@ #include <vespa/vespalib/testkit/testapp.h> #include <vespa/vespalib/metrics/simple_metrics.h> #include <vespa/vespalib/metrics/simple_metrics_manager.h> -#include <vespa/vespalib/metrics/no_realloc_bunch.h> +#include <vespa/vespalib/metrics/stable_store.h> #include <vespa/vespalib/metrics/json_formatter.h> #include <stdio.h> #include <unistd.h> @@ -12,7 +12,7 @@ using namespace vespalib::metrics; TEST("require that simple metrics gauge merge works") { - MetricIdentifier id(42); + MetricIdentifier id(MetricName(42)); GaugeAggregator a(id), b(id), c(id); b.observedCount = 3; b.sumValue = 24.0; @@ -52,44 +52,6 @@ TEST("require that simple metrics gauge merge works") EXPECT_EQUAL(a.lastValue, 1.0); } -struct Foo { - int a; - char *p; - explicit Foo(int v) : a(v), p(nullptr) {} - bool operator==(const Foo &other) const { - return a == other.a; - } -}; - -TEST("require that no_realloc_bunch works") -{ - vespalib::NoReallocBunch<Foo> bunch; - bunch.add(Foo(1)); - bunch.add(Foo(2)); - bunch.add(Foo(3)); - bunch.add(Foo(5)); - bunch.add(Foo(8)); - bunch.add(Foo(13)); - bunch.add(Foo(21)); - bunch.add(Foo(34)); - bunch.add(Foo(55)); - bunch.add(Foo(89)); - - EXPECT_EQUAL(bunch.size(), 10u); - - int sum = 0; - - bunch.apply([&sum](const Foo& value) { sum += value.a; }); - EXPECT_EQUAL(231, sum); - - const Foo& val = bunch.lookup(8); - EXPECT_TRUE(Foo(55) == val); - - for (int i = 0; i < 20000; ++i) { - bunch.add(Foo(i)); - } - EXPECT_TRUE(Foo(19999) == bunch.lookup(20009)); -} TEST("use simple_metrics_collector") { @@ -132,9 +94,11 @@ TEST("use simple_metrics_collector") myGauge.sample(14.0, two); myGauge.sample(11.0, three); - // sleep(2); + for (int i = 0; i < 61; ++i) { + ((SimpleMetricsManager &)*manager).tick(); + } - Snapshot snap = manager->snapshot(); + Snapshot snap = manager->totalSnapshot(); fprintf(stdout, "snap begin: %15f\n", snap.startTime()); fprintf(stdout, "snap end: %15f\n", snap.endTime()); diff --git a/staging_vespalib/src/tests/metrics/stable_store_test.cpp b/staging_vespalib/src/tests/metrics/stable_store_test.cpp new file mode 100644 index 00000000000..03b6663cd64 --- /dev/null +++ b/staging_vespalib/src/tests/metrics/stable_store_test.cpp @@ -0,0 +1,65 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include <vespa/vespalib/testkit/testapp.h> +#include <vespa/vespalib/metrics/simple_metrics.h> +#include <vespa/vespalib/metrics/simple_metrics_manager.h> +#include <vespa/vespalib/metrics/stable_store.h> +#include <vespa/vespalib/metrics/json_formatter.h> +#include <stdio.h> +#include <unistd.h> + +using namespace vespalib; +using namespace vespalib::metrics; + +struct Foo { + int a; + char *p; + explicit Foo(int v) : a(v), p(nullptr) {} + bool operator==(const Foo &other) const { + return a == other.a; + } +}; + +TEST("require that stable_store works") +{ + vespalib::StableStore<Foo> bunch; + bunch.add(Foo(1)); + bunch.add(Foo(2)); + bunch.add(Foo(3)); + bunch.add(Foo(5)); + bunch.add(Foo(8)); + bunch.add(Foo(13)); + bunch.add(Foo(21)); + bunch.add(Foo(34)); + bunch.add(Foo(55)); + bunch.add(Foo(89)); + + EXPECT_EQUAL(bunch.size(), 10u); + + int sum = 0; + + bunch.for_each([&sum](const Foo& value) { sum += value.a; }); + EXPECT_EQUAL(231, sum); + + std::vector<const Foo *> pointers; + bunch.for_each([&pointers](const Foo& value) + { pointers.push_back(&value); }); + EXPECT_EQUAL(1, pointers[0]->a); + EXPECT_EQUAL(2, pointers[1]->a); + EXPECT_EQUAL(55, pointers[8]->a); + EXPECT_EQUAL(89, pointers[9]->a); + + for (int i = 0; i < 20000; ++i) { + bunch.add(Foo(i)); + } + bunch.for_each([&sum](const Foo& value) { sum -= value.a; }); + EXPECT_EQUAL(-199990000, sum); + + std::vector<const Foo *> after; + bunch.for_each([&after](const Foo& value) + { if (after.size() < 10) after.push_back(&value); }); + + EXPECT_EQUAL(pointers[0], after[0]); + EXPECT_EQUAL(pointers[9], after[9]); +} + +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/staging_vespalib/src/vespa/vespalib/metrics/CMakeLists.txt b/staging_vespalib/src/vespa/vespalib/metrics/CMakeLists.txt index 657565fc974..c56605c9181 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/CMakeLists.txt +++ b/staging_vespalib/src/vespa/vespalib/metrics/CMakeLists.txt @@ -1,26 +1,33 @@ # Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. vespa_add_library(staging_vespalib_vespalib_metrics OBJECT SOURCES + bucket.cpp clock.cpp + counter_aggregator.cpp counter.cpp + current_samples.cpp dimension.cpp dummy_metrics_manager.cpp + gauge_aggregator.cpp gauge.cpp + handle.cpp json_formatter.cpp label.cpp - mergers.cpp metric_identifier.cpp + metric_name.cpp metrics_manager.cpp metric_types.cpp name_collection.cpp - no_realloc_bunch.cpp point_builder.cpp point.cpp + point_map_collection.cpp point_map.cpp producer.cpp simple_metrics.cpp simple_metrics_manager.cpp snapshots.cpp + stable_store.cpp + ticker_thread.cpp DEPENDS ) diff --git a/staging_vespalib/src/vespa/vespalib/metrics/bucket.cpp b/staging_vespalib/src/vespa/vespalib/metrics/bucket.cpp new file mode 100644 index 00000000000..e0d456a5259 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/bucket.cpp @@ -0,0 +1,90 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "bucket.h" +#include <assert.h> +#include <map> + +namespace vespalib { +namespace metrics { + +namespace { + +template<typename T> +std::vector<typename T::aggregator_type> +mergeFromSamples(const StableStore<typename T::sample_type> &source) +{ + using Aggregator = typename T::aggregator_type; + using Sample = typename T::sample_type; + using Map = std::map<MetricIdentifier, Aggregator>; + using MapValue = typename Map::value_type; + + Map map; + source.for_each([&map] (const Sample &sample) { + MetricIdentifier id = sample.idx; + auto iter_check = map.emplace(id, Aggregator(id)); + iter_check.first->second.merge(sample); + }); + std::vector<typename T::aggregator_type> result; + for (const MapValue &entry : map) { + result.push_back(entry.second); + } + return result; +} + +template<typename T> +std::vector<T> +mergeVectors(const std::vector<T> &a, + const std::vector<T> &b) +{ + std::vector<T> result; + auto a_iter = a.begin(); + auto b_iter = b.begin(); + while (a_iter != a.end() && + b_iter != b.end()) + { + if (a_iter->idx < b_iter->idx) { + result.push_back(*a_iter); + ++a_iter; + } else if (b_iter->idx < a_iter->idx) { + result.push_back(*b_iter); + ++b_iter; + } else { + result.push_back(*a_iter); + result.back().merge(*b_iter); + ++a_iter; + ++b_iter; + } + } + while (a_iter != a.end()) { + result.push_back(*a_iter); + ++a_iter; + } + while (b_iter != b.end()) { + result.push_back(*b_iter); + ++b_iter; + } + return result; +} + +} // namespace <unnamed> + +void Bucket::merge(const CurrentSamples &samples) +{ + counters = mergeFromSamples<Counter>(samples.counterIncrements); + gauges = mergeFromSamples<Gauge>(samples.gaugeMeasurements); +} + +void Bucket::merge(const Bucket &other) +{ + assert(startTime <= other.startTime); + assert(endTime <= other.endTime); + endTime = other.endTime; + + std::vector<CounterAggregator> nextCounters = mergeVectors(counters, other.counters); + counters = std::move(nextCounters); + + std::vector<GaugeAggregator> nextGauges = mergeVectors(gauges, other.gauges); + gauges = std::move(nextGauges); +} + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/bucket.h b/staging_vespalib/src/vespa/vespalib/metrics/bucket.h new file mode 100644 index 00000000000..c35be945343 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/bucket.h @@ -0,0 +1,40 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include <mutex> +#include "stable_store.h" +#include "metric_identifier.h" +#include "counter.h" +#include "gauge.h" +#include "clock.h" +#include "counter_aggregator.h" +#include "gauge_aggregator.h" +#include "current_samples.h" + +namespace vespalib { +namespace metrics { + +// internal +struct Bucket { + InternalTimeStamp startTime; + InternalTimeStamp endTime; + std::vector<CounterAggregator> counters; + std::vector<GaugeAggregator> gauges; + + void merge(const CurrentSamples &other); + void merge(const Bucket &other); + + Bucket(InternalTimeStamp started, InternalTimeStamp ended) + : startTime(started), + endTime(ended), + counters(), + gauges() + {} + ~Bucket() {} + Bucket(Bucket &&) = default; + Bucket(const Bucket &) = default; + Bucket& operator= (Bucket &&) = default; +}; + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/clock.cpp b/staging_vespalib/src/vespa/vespalib/metrics/clock.cpp index 088dd721cbf..32f7eaec1ad 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/clock.cpp +++ b/staging_vespalib/src/vespa/vespalib/metrics/clock.cpp @@ -2,6 +2,7 @@ #include "clock.h" namespace vespalib { +namespace metrics { std::chrono::microseconds since_epoch(InternalTimeStamp stamp) { @@ -24,4 +25,5 @@ std::chrono::microseconds since_epoch(InternalTimeStamp stamp) return microseconds(stampms + difference + adjust); } +} // namespace metrics } // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/clock.h b/staging_vespalib/src/vespa/vespalib/metrics/clock.h index 9bdb8241139..eebfab58336 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/clock.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/clock.h @@ -4,6 +4,7 @@ #include <chrono> namespace vespalib { +namespace metrics { using InternalClock = std::chrono::steady_clock; using InternalTimeStamp = std::chrono::time_point<std::chrono::steady_clock, @@ -20,4 +21,5 @@ inline InternalTimeStamp now_stamp() std::chrono::microseconds since_epoch(InternalTimeStamp stamp); +} // namespace metrics } // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/counter.cpp b/staging_vespalib/src/vespa/vespalib/metrics/counter.cpp index 2eb3719801b..08f72e6aa34 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/counter.cpp +++ b/staging_vespalib/src/vespa/vespalib/metrics/counter.cpp @@ -5,32 +5,13 @@ namespace vespalib { namespace metrics { -void -Counter::add() const -{ - add(1); -} - -void -Counter::add(Point p) const -{ - add(1, p); -} - -void -Counter::add(size_t count) const -{ - if (_manager) { - _manager->add(CounterIncrement(ident(), count)); - } -} void Counter::add(size_t count, Point point) const { if (_manager) { - MetricIdentifier id(_idx.name_idx, point.id()); - _manager->add(CounterIncrement(id, count)); + MetricIdentifier fullId(_id, point); + _manager->add(Increment(fullId, count)); } } diff --git a/staging_vespalib/src/vespa/vespalib/metrics/counter.h b/staging_vespalib/src/vespa/vespalib/metrics/counter.h index 56b5d277e90..efa4e29f18a 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/counter.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/counter.h @@ -11,34 +11,33 @@ namespace metrics { class MetricsManager; class CounterAggregator; -struct CounterIncrement { - MetricIdentifier idx; - size_t value; - CounterIncrement() = delete; - CounterIncrement(MetricIdentifier id, size_t v) : idx(id), value(v) {} -}; class Counter { std::shared_ptr<MetricsManager> _manager; - MetricIdentifier _idx; - MetricIdentifier ident() const { return _idx; } + MetricName _id; public: - Counter() : _manager(), _idx() {} + Counter() : _manager(), _id(0) {} Counter(const Counter&) = delete; Counter(Counter &&other) = default; Counter& operator= (const Counter &) = delete; Counter& operator= (Counter &&other) = default; - Counter(std::shared_ptr<MetricsManager> m, MetricIdentifier id) - : _manager(std::move(m)), _idx(id) + Counter(std::shared_ptr<MetricsManager> m, MetricName id) + : _manager(std::move(m)), _id(id) {} - void add() const; - void add(size_t count) const; - void add(Point p) const; - void add(size_t count, Point p) const; + void add() const { add(1, Point::empty); } + void add(Point p) { add(1, p); } + void add(size_t count, Point p = Point::empty) const; + + struct Increment { + MetricIdentifier idx; + size_t value; + Increment() = delete; + Increment(MetricIdentifier id, size_t v) : idx(id), value(v) {} + }; typedef CounterAggregator aggregator_type; - typedef CounterIncrement sample_type; + typedef Increment sample_type; }; } // namespace vespalib::metrics diff --git a/staging_vespalib/src/vespa/vespalib/metrics/counter_aggregator.cpp b/staging_vespalib/src/vespa/vespalib/metrics/counter_aggregator.cpp new file mode 100644 index 00000000000..6c7e42da193 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/counter_aggregator.cpp @@ -0,0 +1,28 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "counter_aggregator.h" +#include <assert.h> +#include <map> + +namespace vespalib { +namespace metrics { + +CounterAggregator::CounterAggregator(MetricIdentifier id) + : idx(id), count(0) +{} + +void +CounterAggregator::merge(const Counter::Increment &increment) +{ + assert(idx == increment.idx); + count += increment.value; +} + +void +CounterAggregator::merge(const CounterAggregator &other) +{ + assert(idx == other.idx); + count += other.count; +} + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/counter_aggregator.h b/staging_vespalib/src/vespa/vespalib/metrics/counter_aggregator.h new file mode 100644 index 00000000000..969c80337a0 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/counter_aggregator.h @@ -0,0 +1,22 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "metric_identifier.h" +#include "counter.h" + +namespace vespalib { +namespace metrics { + +// internal +struct CounterAggregator { + MetricIdentifier idx; + size_t count; + + CounterAggregator(MetricIdentifier id); + + void merge(const Counter::Increment &other); + void merge(const CounterAggregator &other); +}; + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/current_samples.cpp b/staging_vespalib/src/vespa/vespalib/metrics/current_samples.cpp new file mode 100644 index 00000000000..4dbd5b6063e --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/current_samples.cpp @@ -0,0 +1,15 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "current_samples.h" + +namespace vespalib { +namespace metrics { + +void swap(CurrentSamples& a, CurrentSamples& b) +{ + using std::swap; + swap(a.counterIncrements, b.counterIncrements); + swap(a.gaugeMeasurements, b.gaugeMeasurements); +} + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/current_samples.h b/staging_vespalib/src/vespa/vespalib/metrics/current_samples.h new file mode 100644 index 00000000000..78667a3020a --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/current_samples.h @@ -0,0 +1,33 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include <mutex> +#include "stable_store.h" +#include "counter.h" +#include "gauge.h" + +namespace vespalib { +namespace metrics { + +// internal +struct CurrentSamples { + std::mutex lock; + StableStore<Counter::Increment> counterIncrements; + StableStore<Gauge::Measurement> gaugeMeasurements; + + ~CurrentSamples() {} + + void add(Counter::Increment inc) { + std::lock_guard<std::mutex> guard(lock); + counterIncrements.add(inc); + } + void sample(Gauge::Measurement value) { + std::lock_guard<std::mutex> guard(lock); + gaugeMeasurements.add(value); + } +}; + +void swap(CurrentSamples& a, CurrentSamples& b); + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/dimension.h b/staging_vespalib/src/vespa/vespalib/metrics/dimension.h index 3d6e2cc0eea..680370ba84c 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/dimension.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/dimension.h @@ -2,18 +2,19 @@ #pragma once #include <vespa/vespalib/stllike/string.h> +#include "handle.h" namespace vespalib { namespace metrics { using DimensionName = vespalib::string; -class Dimension { - const size_t _dimension_idx; +/** + * Opaque handle representing an uniquely named dimension. + **/ +class Dimension : public Handle<Dimension> { public: - size_t id() const { return _dimension_idx; } - Dimension(size_t id) : _dimension_idx(id) {} - bool operator< (const Dimension &other) const { return id() < other.id(); } + explicit Dimension(size_t id) : Handle<Dimension>(id) {} }; } // namespace vespalib::metrics diff --git a/staging_vespalib/src/vespa/vespalib/metrics/dummy_metrics_manager.cpp b/staging_vespalib/src/vespa/vespalib/metrics/dummy_metrics_manager.cpp index 50b26cf60fb..cd7a3abb1eb 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/dummy_metrics_manager.cpp +++ b/staging_vespalib/src/vespa/vespalib/metrics/dummy_metrics_manager.cpp @@ -9,11 +9,14 @@ DummyMetricsManager::~DummyMetricsManager() {} Snapshot DummyMetricsManager::snapshot() { - InternalTimeStamp endTime = now_stamp(); - std::chrono::microseconds s = since_epoch(_startTime); - std::chrono::microseconds e = since_epoch(endTime); - const double micro = 0.000001; - Snapshot snap(s.count() * micro, e.count() * micro); + Snapshot snap(0, 0); + return snap; +} + +Snapshot +DummyMetricsManager::totalSnapshot() +{ + Snapshot snap(0, 0); return snap; } diff --git a/staging_vespalib/src/vespa/vespalib/metrics/dummy_metrics_manager.h b/staging_vespalib/src/vespa/vespalib/metrics/dummy_metrics_manager.h index 1eeda79e117..59e23e6ea84 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/dummy_metrics_manager.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/dummy_metrics_manager.h @@ -5,7 +5,7 @@ #include <thread> #include <vespa/vespalib/stllike/string.h> #include "name_collection.h" -#include "mergers.h" +#include "current_samples.h" #include "snapshots.h" #include "metrics_manager.h" #include "clock.h" @@ -21,8 +21,7 @@ namespace metrics { class DummyMetricsManager : public MetricsManager { private: - InternalTimeStamp _startTime; - DummyMetricsManager() : _startTime(now_stamp()) {} + DummyMetricsManager() {} public: ~DummyMetricsManager(); @@ -31,10 +30,10 @@ public: } Counter counter(const vespalib::string &) override { - return Counter(shared_from_this(), MetricIdentifier(0)); + return Counter(shared_from_this(), MetricName(0)); } Gauge gauge(const vespalib::string &) override { - return Gauge(shared_from_this(), MetricIdentifier(0)); + return Gauge(shared_from_this(), MetricName(0)); } Dimension dimension(const vespalib::string &) override { @@ -46,16 +45,17 @@ public: PointBuilder pointBuilder(Point) override { return PointBuilder(shared_from_this()); } - Point pointFrom(PointMapBacking &&) override { + Point pointFrom(PointMap::BackingMap) override { return Point(0); } Snapshot snapshot() override; + Snapshot totalSnapshot() override; // for use from Counter only - void add(CounterIncrement) override {} + void add(Counter::Increment) override {} // for use from Gauge only - void sample(GaugeMeasurement) override {} + void sample(Gauge::Measurement) override {} }; } // namespace vespalib::metrics diff --git a/staging_vespalib/src/vespa/vespalib/metrics/gauge.cpp b/staging_vespalib/src/vespa/vespalib/metrics/gauge.cpp index b2d9f6b946a..af98ba2de18 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/gauge.cpp +++ b/staging_vespalib/src/vespa/vespalib/metrics/gauge.cpp @@ -6,19 +6,11 @@ namespace vespalib { namespace metrics { void -Gauge::sample(double value) const -{ - if (_manager) { - _manager->sample(GaugeMeasurement(ident(), value)); - } -} - -void Gauge::sample(double value, Point point) const { if (_manager) { - MetricIdentifier id(_idx.name_idx, point.id()); - _manager->sample(GaugeMeasurement(id, value)); + MetricIdentifier fullId(_id, point); + _manager->sample(Measurement(fullId, value)); } } diff --git a/staging_vespalib/src/vespa/vespalib/metrics/gauge.h b/staging_vespalib/src/vespa/vespalib/metrics/gauge.h index c5a1bfb25d8..5f15a573b73 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/gauge.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/gauge.h @@ -11,28 +11,26 @@ namespace metrics { class MetricsManager; class GaugeAggregator; -struct GaugeMeasurement { - MetricIdentifier idx; - double value; - GaugeMeasurement() = delete; - GaugeMeasurement(MetricIdentifier id, double v) : idx(id), value(v) {} -}; - class Gauge { private: std::shared_ptr<MetricsManager> _manager; - MetricIdentifier _idx; - MetricIdentifier ident() const { return _idx; } + MetricName _id; public: - Gauge(std::shared_ptr<MetricsManager> m, MetricIdentifier id) - : _manager(std::move(m)), _idx(id) + Gauge(std::shared_ptr<MetricsManager> m, MetricName id) + : _manager(std::move(m)), _id(id) {} - void sample(double value) const; - void sample(double value, Point p) const; + void sample(double value, Point p = Point::empty) const; + + struct Measurement { + MetricIdentifier idx; + double value; + Measurement() = delete; + Measurement(MetricIdentifier id, double v) : idx(id), value(v) {} + }; typedef GaugeAggregator aggregator_type; - typedef GaugeMeasurement sample_type; + typedef Measurement sample_type; }; } // namespace vespalib::metrics diff --git a/staging_vespalib/src/vespa/vespalib/metrics/gauge_aggregator.cpp b/staging_vespalib/src/vespa/vespalib/metrics/gauge_aggregator.cpp new file mode 100644 index 00000000000..3e36b4e1b30 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/gauge_aggregator.cpp @@ -0,0 +1,52 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "gauge_aggregator.h" +#include <assert.h> +#include <map> + +namespace vespalib { +namespace metrics { + +GaugeAggregator::GaugeAggregator(MetricIdentifier id) + : idx(id), + observedCount(0), + sumValue(0.0), + minValue(0.0), + maxValue(0.0), + lastValue(0.0) +{} + +void +GaugeAggregator::merge(const Gauge::Measurement &other) +{ + assert(idx == other.idx); + if (observedCount == 0) { + sumValue = other.value; + minValue = other.value; + maxValue = other.value; + } else { + sumValue += other.value; + minValue = std::min(minValue, other.value); + maxValue = std::max(maxValue, other.value); + } + lastValue = other.value; + ++observedCount; +} + +void +GaugeAggregator::merge(const GaugeAggregator &other) +{ + assert(idx == other.idx); + if (observedCount == 0) { + minValue = other.minValue; + maxValue = other.maxValue; + } else { + minValue = std::min(minValue, other.minValue); + maxValue = std::max(maxValue, other.maxValue); + } + sumValue += other.sumValue; + lastValue = other.lastValue; + observedCount += other.observedCount; +} + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/gauge_aggregator.h b/staging_vespalib/src/vespa/vespalib/metrics/gauge_aggregator.h new file mode 100644 index 00000000000..231f5650dca --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/gauge_aggregator.h @@ -0,0 +1,26 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "metric_identifier.h" +#include "gauge.h" + +namespace vespalib { +namespace metrics { + +// internal +struct GaugeAggregator { + MetricIdentifier idx; + size_t observedCount; + double sumValue; + double minValue; + double maxValue; + double lastValue; + + GaugeAggregator(MetricIdentifier id); + + void merge(const Gauge::Measurement &other); + void merge(const GaugeAggregator &other); +}; + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/handle.cpp b/staging_vespalib/src/vespa/vespalib/metrics/handle.cpp new file mode 100644 index 00000000000..2b806caeaea --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/handle.cpp @@ -0,0 +1,2 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "handle.h" diff --git a/staging_vespalib/src/vespa/vespalib/metrics/handle.h b/staging_vespalib/src/vespa/vespalib/metrics/handle.h new file mode 100644 index 00000000000..cd5d0c9e940 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/handle.h @@ -0,0 +1,53 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include <cstddef> + +namespace vespalib { +namespace metrics { + +/** + * Common implementation of an opaque handle identified only + * by a (64-bit) integer. Templated to avoid different concepts + * sharing a superclass. + **/ +template <typename T> +class Handle { +private: + const size_t _id; +protected: + explicit Handle(size_t id) : _id(id) {} +public: + size_t id() const { return _id; } +}; + +template <typename T> +bool +operator< (const Handle<T> &a, const Handle<T> &b) +{ + return a.id() < b.id(); +} + +template <typename T> +bool +operator> (const Handle<T> &a, const Handle<T> &b) +{ + return a.id() > b.id(); +} + +template <typename T> +bool +operator== (const Handle<T> &a, const Handle<T> &b) +{ + return a.id() == b.id(); +} + +template <typename T> +bool +operator!= (const Handle<T> &a, const Handle<T> &b) +{ + return a.id() != b.id(); +} + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/json_formatter.cpp b/staging_vespalib/src/vespa/vespalib/metrics/json_formatter.cpp index 58ef76ce8b0..280211bd780 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/json_formatter.cpp +++ b/staging_vespalib/src/vespa/vespalib/metrics/json_formatter.cpp @@ -66,7 +66,7 @@ JsonFormatter::handle(const PointSnapshot &snapshot, vespalib::slime::Cursor &ta return; } Cursor& inner = target.setObject("dimensions"); - for (const AxisMeasure &entry : snapshot.dimensions) { + for (const DimensionBinding &entry : snapshot.dimensions) { inner.setString(entry.dimensionName(), entry.labelValue()); } } diff --git a/staging_vespalib/src/vespa/vespalib/metrics/label.h b/staging_vespalib/src/vespa/vespalib/metrics/label.h index 09c5b20e45b..81e96728c27 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/label.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/label.h @@ -2,17 +2,19 @@ #pragma once #include <vespa/vespalib/stllike/string.h> +#include "handle.h" namespace vespalib { namespace metrics { using LabelValue = vespalib::string; -class Label { - const size_t _coord_idx; +/** + * Opaque handle representing an uniquely named label. + **/ +class Label : public Handle<Label> { public: - size_t id() const { return _coord_idx; } - Label(size_t id) : _coord_idx(id) {} + explicit Label(size_t id) : Handle<Label>(id) {} }; } // namespace vespalib::metrics diff --git a/staging_vespalib/src/vespa/vespalib/metrics/mergers.cpp b/staging_vespalib/src/vespa/vespalib/metrics/mergers.cpp deleted file mode 100644 index 1a4731065b5..00000000000 --- a/staging_vespalib/src/vespa/vespalib/metrics/mergers.cpp +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include "mergers.h" -#include <assert.h> -#include <map> - -namespace vespalib { -namespace metrics { - -CounterAggregator::CounterAggregator(MetricIdentifier id) - : idx(id), count(0) -{} - -void -CounterAggregator::merge(const CounterIncrement &increment) -{ - assert(idx == increment.idx); - count += increment.value; -} - -void -CounterAggregator::merge(const CounterAggregator &other) -{ - assert(idx == other.idx); - count += other.count; -} - - -GaugeAggregator::GaugeAggregator(MetricIdentifier id) - : idx(id), - observedCount(0), - sumValue(0.0), - minValue(0.0), - maxValue(0.0), - lastValue(0.0) -{} - -void -GaugeAggregator::merge(const GaugeMeasurement &other) -{ - assert(idx == other.idx); - if (observedCount == 0) { - sumValue = other.value; - minValue = other.value; - maxValue = other.value; - } else { - sumValue += other.value; - minValue = std::min(minValue, other.value); - maxValue = std::max(maxValue, other.value); - } - lastValue = other.value; - ++observedCount; -} - -void -GaugeAggregator::merge(const GaugeAggregator &other) -{ - assert(idx == other.idx); - if (observedCount == 0) { - minValue = other.minValue; - maxValue = other.maxValue; - } else { - minValue = std::min(minValue, other.minValue); - maxValue = std::max(maxValue, other.maxValue); - } - sumValue += other.sumValue; - lastValue = other.lastValue; - observedCount += other.observedCount; -} - -namespace { - -template<typename T> -void -mergeWithMap(const NoReallocBunch<typename T::sample_type> &other, - std::vector<typename T::aggregator_type> &result) -{ - using Aggregator = typename T::aggregator_type; - using Sample = typename T::sample_type; - using Map = std::map<MetricIdentifier, Aggregator>; - using MapValue = typename Map::value_type; - - assert(result.size() == 0); - Map map; - other.apply([&map] (const Sample &sample) { - MetricIdentifier id = sample.idx; - auto iter = map.find(id); - if (iter != map.end()) { - iter->second.merge(sample); - } else { - auto check_iter = map.insert(MapValue(id, Aggregator(id))); - assert(check_iter.second); - check_iter.first->second.merge(sample); - } - }); - for (const MapValue &entry : map) { - result.push_back(entry.second); - } -} - -template<typename T> -std::vector<T> -mergeVectors(const std::vector<T> &a, - const std::vector<T> &b) -{ - std::vector<T> result; - auto a_iter = a.begin(); - auto b_iter = b.begin(); - while (a_iter != a.end() && - b_iter != b.end()) - { - if (a_iter->idx < b_iter->idx) { - result.push_back(*a_iter); - ++a_iter; - } else if (b_iter->idx < a_iter->idx) { - result.push_back(*b_iter); - ++b_iter; - } else { - T both = *a_iter; - both.merge(*b_iter); - result.push_back(both); - ++a_iter; - ++b_iter; - } - } - while (a_iter != a.end()) { - result.push_back(*a_iter); - ++a_iter; - } - while (b_iter != b.end()) { - result.push_back(*b_iter); - ++b_iter; - } - return result; -} - -} // namespace <unnamed> - -void Bucket::merge(const CurrentSamples &other) -{ - mergeWithMap<Counter>(other.counterIncrements, counters); - mergeWithMap<Gauge>(other.gaugeMeasurements, gauges); -} - -void Bucket::merge(const Bucket &other) -{ - assert(startTime <= other.startTime); - assert(endTime <= other.endTime); - endTime = other.endTime; - - std::vector<CounterAggregator> nextCounters = mergeVectors(counters, other.counters); - counters = std::move(nextCounters); - - std::vector<GaugeAggregator> nextGauges = mergeVectors(gauges, other.gauges); - gauges = std::move(nextGauges); -} - -void swap(CurrentSamples& a, CurrentSamples& b) -{ - using std::swap; - swap(a.counterIncrements, b.counterIncrements); - swap(a.gaugeMeasurements, b.gaugeMeasurements); -} - -void swap(Bucket& a, Bucket& b) -{ - using std::swap; - swap(a.startTime, b.startTime); - swap(a.endTime, b.endTime); - swap(a.counters, b.counters); - swap(a.gauges, b.gauges); -} - -} // namespace vespalib::metrics -} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/mergers.h b/staging_vespalib/src/vespa/vespalib/metrics/mergers.h deleted file mode 100644 index e08efff1599..00000000000 --- a/staging_vespalib/src/vespa/vespalib/metrics/mergers.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#pragma once - -#include <mutex> -#include "no_realloc_bunch.h" -#include "metric_identifier.h" -#include "counter.h" -#include "gauge.h" -#include "clock.h" - -namespace vespalib { -namespace metrics { - -// internal -struct CounterAggregator { - MetricIdentifier idx; - size_t count; - - CounterAggregator(MetricIdentifier id); - - void merge(const CounterIncrement &other); - void merge(const CounterAggregator &other); -}; - -// internal -struct GaugeAggregator { - MetricIdentifier idx; - size_t observedCount; - double sumValue; - double minValue; - double maxValue; - double lastValue; - - GaugeAggregator(MetricIdentifier id); - - void merge(const GaugeMeasurement &other); - void merge(const GaugeAggregator &other); -}; - -// internal -struct CurrentSamples { - std::mutex lock; - NoReallocBunch<CounterIncrement> counterIncrements; - NoReallocBunch<GaugeMeasurement> gaugeMeasurements; - - ~CurrentSamples() {} - - void add(CounterIncrement inc) { - std::lock_guard<std::mutex> guard(lock); - counterIncrements.add(inc); - } - void sample(GaugeMeasurement value) { - std::lock_guard<std::mutex> guard(lock); - gaugeMeasurements.add(value); - } -}; - -// internal -struct Bucket { - InternalTimeStamp startTime; - InternalTimeStamp endTime; - std::vector<CounterAggregator> counters; - std::vector<GaugeAggregator> gauges; - - void merge(const CurrentSamples &other); - void merge(const Bucket &other); - - Bucket(InternalTimeStamp started, InternalTimeStamp ended) - : startTime(started), - endTime(ended), - counters(), - gauges() - {} - ~Bucket() {} -}; - -void swap(CurrentSamples& a, CurrentSamples& b); -void swap(Bucket& a, Bucket& b); - -} // namespace vespalib::metrics -} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/metric_identifier.h b/staging_vespalib/src/vespa/vespalib/metrics/metric_identifier.h index 4feb8f1a22d..0fbff69658e 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/metric_identifier.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/metric_identifier.h @@ -1,35 +1,39 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once -#include <cstddef> +#include "metric_name.h" +#include "point.h" #include <functional> namespace vespalib { namespace metrics { struct MetricIdentifier { - const size_t name_idx; - const size_t point_idx; + const MetricName _name; + const Point _point; - MetricIdentifier() : name_idx(-1), point_idx(0) {} + MetricIdentifier() = delete; - explicit MetricIdentifier(size_t id) - : name_idx(id), point_idx(0) {} + explicit MetricIdentifier(MetricName name) + : _name(name), _point(0) {} - MetricIdentifier(size_t id, size_t pt) - : name_idx(id), point_idx(pt) {} + MetricIdentifier(MetricName name, Point point) + : _name(name), _point(point) {} bool operator< (const MetricIdentifier &other) const { - if (name_idx < other.name_idx) return true; - if (name_idx == other.name_idx) { - return (point_idx < other.point_idx); + if (_name != other._name) { + return _name < other._name; } - return false; + return _point < other._point; } bool operator== (const MetricIdentifier &other) const { - return (name_idx == other.name_idx && - point_idx == other.point_idx); + return (_name == other._name && + _point == other._point); } + + MetricName name() const { return _name; } + Point point() const { return _point; } + }; } // namespace vespalib::metrics @@ -43,7 +47,7 @@ namespace std typedef std::size_t result_type; result_type operator()(argument_type const& ident) const noexcept { - return (ident.point_idx << 20) + ident.name_idx; + return (ident.point().id() << 20) + ident.name().id(); } }; } diff --git a/staging_vespalib/src/vespa/vespalib/metrics/metric_name.cpp b/staging_vespalib/src/vespa/vespalib/metrics/metric_name.cpp new file mode 100644 index 00000000000..2a58d55e945 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/metric_name.cpp @@ -0,0 +1,2 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "metric_name.h" diff --git a/staging_vespalib/src/vespa/vespalib/metrics/metric_name.h b/staging_vespalib/src/vespa/vespalib/metrics/metric_name.h new file mode 100644 index 00000000000..baf35b05e45 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/metric_name.h @@ -0,0 +1,18 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "handle.h" + +namespace vespalib { +namespace metrics { + +/** + * Opaque handle representing an uniquely named metric. + **/ +class MetricName : public Handle<MetricName> { +public: + explicit MetricName(size_t id) : Handle<MetricName>(id) {} +}; + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/metric_types.cpp b/staging_vespalib/src/vespa/vespalib/metrics/metric_types.cpp index 2f34390f7c9..1d633553796 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/metric_types.cpp +++ b/staging_vespalib/src/vespa/vespalib/metrics/metric_types.cpp @@ -1,5 +1,6 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "metric_types.h" +#include <assert.h> #include <vespa/log/log.h> LOG_SETUP(".vespalib.metrics.metric_types"); @@ -24,16 +25,10 @@ MetricTypes::check(size_t id, const vespalib::string &name, MetricType ty) if (old == ty) { return; } - if (old == NONE) { - _seen[id] = ty; - return; - } LOG(warning, "metric '%s' with different types %s and %s, this will be confusing", name.c_str(), _typeNames[ty], _typeNames[old]); } - while (_seen.size() < id) { - _seen.push_back(NONE); - } + assert (_seen.size() == id); _seen.push_back(ty); } diff --git a/staging_vespalib/src/vespa/vespalib/metrics/metric_types.h b/staging_vespalib/src/vespa/vespalib/metrics/metric_types.h index e2f30d18b4c..5bda0230bd4 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/metric_types.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/metric_types.h @@ -12,7 +12,7 @@ class MetricTypes { static const char *_typeNames[]; public: enum MetricType { - NONE, + INVALID, COUNTER, GAUGE, HISTOGRAM, diff --git a/staging_vespalib/src/vespa/vespalib/metrics/metrics_manager.h b/staging_vespalib/src/vespa/vespalib/metrics/metrics_manager.h index e05d42810cb..2742252ed44 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/metrics_manager.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/metrics_manager.h @@ -7,7 +7,7 @@ #include "name_collection.h" #include "counter.h" #include "gauge.h" -#include "mergers.h" +#include "current_samples.h" #include "snapshots.h" #include "point.h" #include "point_builder.h" @@ -34,15 +34,16 @@ public: } virtual PointBuilder pointBuilder(Point from) = 0; - virtual Point pointFrom(PointMapBacking &&map) = 0; + virtual Point pointFrom(PointMap::BackingMap map) = 0; virtual Snapshot snapshot() = 0; + virtual Snapshot totalSnapshot() = 0; // for use from Counter only - virtual void add(CounterIncrement inc) = 0; + virtual void add(Counter::Increment inc) = 0; // for use from Gauge only - virtual void sample(GaugeMeasurement value) = 0; + virtual void sample(Gauge::Measurement value) = 0; }; diff --git a/staging_vespalib/src/vespa/vespalib/metrics/name_collection.cpp b/staging_vespalib/src/vespa/vespalib/metrics/name_collection.cpp index 61dec6ef048..697d41c4c6b 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/name_collection.cpp +++ b/staging_vespalib/src/vespa/vespalib/metrics/name_collection.cpp @@ -8,9 +8,8 @@ namespace metrics { using Guard = std::lock_guard<std::mutex>; const vespalib::string & -NameCollection::lookup(int idx) const +NameCollection::lookup(size_t id) const { - size_t id = idx; Guard guard(_lock); assert(id < _names_by_id.size()); return _names_by_id[id]->first; @@ -20,16 +19,12 @@ size_t NameCollection::resolve(const vespalib::string& name) { Guard guard(_lock); - Map::const_iterator iter = _names.find(name); - if (iter != _names.end()) { - return iter->second; - } else { - size_t id = _names_by_id.size(); - auto iter_check = _names.insert(Map::value_type(name, id)); - assert(iter_check.second); + size_t nextId = _names_by_id.size(); + auto iter_check = _names.emplace(name, nextId); + if (iter_check.second) { _names_by_id.push_back(iter_check.first); - return id; } + return iter_check.first->second; } size_t diff --git a/staging_vespalib/src/vespa/vespalib/metrics/name_collection.h b/staging_vespalib/src/vespa/vespalib/metrics/name_collection.h index 536075b2987..6fd25552d6e 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/name_collection.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/name_collection.h @@ -16,7 +16,7 @@ private: Map _names; std::vector<Map::const_iterator> _names_by_id; public: - const vespalib::string &lookup(int idx) const; + const vespalib::string &lookup(size_t id) const; size_t resolve(const vespalib::string& name); size_t size() const; diff --git a/staging_vespalib/src/vespa/vespalib/metrics/point.h b/staging_vespalib/src/vespa/vespalib/metrics/point.h index 5843f6d3c51..3ef66f731f6 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/point.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/point.h @@ -1,20 +1,18 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #pragma once -#include <cstddef> +#include "handle.h" namespace vespalib { namespace metrics { -class Point { -private: - const size_t _point_idx; +/** + * Opaque handle representing an unique N-dimensional point + **/ +class Point : public Handle<Point> { public: - size_t id() const { return _point_idx; } - static Point empty; - - explicit Point(size_t id) : _point_idx(id) {} + explicit Point(size_t id) : Handle<Point>(id) {} }; } // namespace vespalib::metrics diff --git a/staging_vespalib/src/vespa/vespalib/metrics/point_builder.cpp b/staging_vespalib/src/vespa/vespalib/metrics/point_builder.cpp index c2846ef592e..7ee4ca35d0e 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/point_builder.cpp +++ b/staging_vespalib/src/vespa/vespalib/metrics/point_builder.cpp @@ -10,7 +10,7 @@ PointBuilder::PointBuilder(std::shared_ptr<MetricsManager> m) {} PointBuilder::PointBuilder(std::shared_ptr<MetricsManager> m, - const PointMapBacking ©From) + const PointMap::BackingMap ©From) : _owner(std::move(m)), _map(copyFrom) {} @@ -18,7 +18,7 @@ PointBuilder && PointBuilder::bind(Dimension dimension, Label label) && { _map.erase(dimension); - _map.insert(PointMapBacking::value_type(dimension, label)); + _map.emplace(dimension, label); return std::move(*this); } @@ -40,7 +40,7 @@ PointBuilder::bind(DimensionName dimension, LabelValue label) && Point PointBuilder::build() { - return _owner->pointFrom(PointMapBacking(_map)); + return _owner->pointFrom(PointMap::BackingMap(_map)); } PointBuilder::operator Point() && diff --git a/staging_vespalib/src/vespa/vespalib/metrics/point_builder.h b/staging_vespalib/src/vespa/vespalib/metrics/point_builder.h index ca0d21b9b8a..84d4c7fb569 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/point_builder.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/point_builder.h @@ -15,11 +15,11 @@ class MetricsManager; class PointBuilder { private: std::shared_ptr<MetricsManager> _owner; - PointMapBacking _map; + PointMap::BackingMap _map; public: PointBuilder(std::shared_ptr<MetricsManager> m); - PointBuilder(std::shared_ptr<MetricsManager> m, const PointMapBacking &from); + PointBuilder(std::shared_ptr<MetricsManager> m, const PointMap::BackingMap &from); ~PointBuilder() {} PointBuilder &&bind(Dimension dimension, Label label) &&; diff --git a/staging_vespalib/src/vespa/vespalib/metrics/point_map.cpp b/staging_vespalib/src/vespa/vespalib/metrics/point_map.cpp index 5fb29cee005..ca62a3a7d6e 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/point_map.cpp +++ b/staging_vespalib/src/vespa/vespalib/metrics/point_map.cpp @@ -5,11 +5,11 @@ namespace vespalib { namespace metrics { -PointMap::PointMap(PointMapBacking &&from) +PointMap::PointMap(BackingMap &&from) : _map(std::move(from)), _hash(0) { - for (const PointMapBacking::value_type &entry : _map) { + for (const BackingMap::value_type &entry : _map) { _hash = (_hash << 7) + (_hash >> 31) + entry.first.id(); _hash = (_hash << 7) + (_hash >> 31) + entry.second.id(); } @@ -19,21 +19,26 @@ bool PointMap::operator< (const PointMap &other) const { // cheap comparison first - if (_hash < other._hash) return true; - if (_hash > other._hash) return false; + if (_hash != other._hash) { + return _hash < other._hash; + } + if (_map.size() != other._map.size()) { + return _map.size() < other._map.size(); + } + // sizes equal, iterate in parallel auto m = _map.begin(); auto o = other._map.begin(); while (m != _map.end()) { - size_t my_f = m->first.id(); - size_t ot_f = o->first.id(); - if (my_f < ot_f) return true; - if (my_f > ot_f) return false; - - size_t my_s = m->second.id(); - size_t ot_s = o->second.id(); - if (my_s < ot_s) return true; - if (my_s > ot_s) return false; - + const Dimension& d1 = m->first; + const Dimension& d2 = o->first; + if (d1 != d2) { + return d1 < d2; + } + const Label &l1 = m->second; + const Label &l2 = o->second; + if (l1 != l2) { + return l1 != l2; + } ++m; ++o; } diff --git a/staging_vespalib/src/vespa/vespalib/metrics/point_map.h b/staging_vespalib/src/vespa/vespalib/metrics/point_map.h index fd4498e1b20..2810aa1aa9d 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/point_map.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/point_map.h @@ -8,18 +8,18 @@ namespace vespalib { namespace metrics { -using PointMapBacking = std::map<Dimension, Label>; - class PointMap { +public: + using BackingMap = std::map<Dimension, Label>; private: - const PointMapBacking _map; + const PointMap::BackingMap _map; size_t _hash; public: PointMap() : _map(), _hash(0) {} - PointMap(PointMapBacking &&from); + PointMap(BackingMap &&from); bool operator< (const PointMap &other) const; - const PointMapBacking &backing() const { return _map; } + const BackingMap &backingMap() const { return _map; } }; } // namespace vespalib::metrics diff --git a/staging_vespalib/src/vespa/vespalib/metrics/point_map_collection.cpp b/staging_vespalib/src/vespa/vespalib/metrics/point_map_collection.cpp new file mode 100644 index 00000000000..7b09fbf7746 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/point_map_collection.cpp @@ -0,0 +1,39 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "point_map_collection.h" +#include <assert.h> + +namespace vespalib { +namespace metrics { + +using Guard = std::lock_guard<std::mutex>; + +const PointMap & +PointMapCollection::lookup(size_t id) +{ + Guard guard(_lock); + assert(id < _vec.size()); + PointMapMap::const_iterator iter = _vec[id]; + return iter->first; +} + +size_t +PointMapCollection::resolve(PointMap map) +{ + Guard guard(_lock); + size_t nextId = _vec.size(); + auto iter_check = _map.emplace(std::move(map), nextId); + if (iter_check.second) { + _vec.push_back(iter_check.first); + } + return iter_check.first->second; +} + +size_t +PointMapCollection::size() const +{ + Guard guard(_lock); + return _vec.size(); +} + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/point_map_collection.h b/staging_vespalib/src/vespa/vespalib/metrics/point_map_collection.h new file mode 100644 index 00000000000..83891e7fa0c --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/point_map_collection.h @@ -0,0 +1,29 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include <mutex> +#include <map> +#include <vector> +#include "point_map.h" + +namespace vespalib { +namespace metrics { + +class PointMapCollection { +private: + using PointMapMap = std::map<PointMap, size_t>; + + mutable std::mutex _lock; + PointMapMap _map; + std::vector<PointMapMap::const_iterator> _vec; +public: + const PointMap &lookup(size_t id); + size_t resolve(PointMap map); + size_t size() const; + + PointMapCollection() = default; + ~PointMapCollection() {} +}; + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/simple_metrics_manager.cpp b/staging_vespalib/src/vespa/vespalib/metrics/simple_metrics_manager.cpp index 9c55a4e2aff..4d906df8624 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/simple_metrics_manager.cpp +++ b/staging_vespalib/src/vespa/vespalib/metrics/simple_metrics_manager.cpp @@ -20,18 +20,17 @@ SimpleMetricsManager::SimpleMetricsManager(const SimpleManagerConfig &config) _buckets(), _firstBucket(0), _maxBuckets(config.sliding_window_seconds), - _stopFlag(false), - _collectorThread(doCollectLoop, this) + _totalsBucket(_startTime, _startTime), + _ticker(this) { if (_maxBuckets < 1) _maxBuckets = 1; - Point empty = pointFrom(PointMapBacking()); + Point empty = pointFrom(PointMap::BackingMap()); assert(empty.id() == 0); } SimpleMetricsManager::~SimpleMetricsManager() { - _stopFlag = true; - _collectorThread.join(); + _ticker.stop(); } @@ -46,18 +45,18 @@ Counter SimpleMetricsManager::counter(const vespalib::string &name) { size_t id = _metricNames.resolve(name); - _metricTypes.check(id, name, MetricTypes::COUNTER); - LOG(debug, "metric name %s -> %zd", name.c_str(), id); - return Counter(shared_from_this(), MetricIdentifier(id)); + _metricTypes.check(id, name, MetricTypes::MetricType::COUNTER); + LOG(debug, "counter with metric name %s -> %zd", name.c_str(), id); + return Counter(shared_from_this(), MetricName(id)); } Gauge SimpleMetricsManager::gauge(const vespalib::string &name) { size_t id = _metricNames.resolve(name); - _metricTypes.check(id, name, MetricTypes::GAUGE); - LOG(debug, "metric name %s -> %zd", name.c_str(), id); - return Gauge(shared_from_this(), MetricIdentifier(id)); + _metricTypes.check(id, name, MetricTypes::MetricType::GAUGE); + LOG(debug, "gauge with metric name %s -> %zd", name.c_str(), id); + return Gauge(shared_from_this(), MetricName(id)); } Bucket @@ -78,36 +77,34 @@ SimpleMetricsManager::mergeBuckets() } Snapshot -SimpleMetricsManager::snapshot() +SimpleMetricsManager::snapshotFrom(const Bucket &bucket) { - Bucket merged = mergeBuckets(); std::vector<PointSnapshot> points; - std::chrono::microseconds s = since_epoch(merged.startTime); - std::chrono::microseconds e = since_epoch(merged.endTime); + std::chrono::microseconds s = since_epoch(bucket.startTime); + std::chrono::microseconds e = since_epoch(bucket.endTime); const double micro = 0.000001; Snapshot snap(s.count() * micro, e.count() * micro); { - Guard guard(_pointMaps.lock); - for (auto entry : _pointMaps.vec) { - const PointMapBacking &map = entry->first.backing(); + for (size_t i = 0; i < _pointMaps.size(); ++i) { + const PointMap::BackingMap &map = _pointMaps.lookup(i).backingMap(); PointSnapshot point; - for (const PointMapBacking::value_type &kv : map) { + for (const PointMap::BackingMap::value_type &kv : map) { point.dimensions.emplace_back(nameFor(kv.first), valueFor(kv.second)); } snap.add(point); } } - for (const CounterAggregator& entry : merged.counters) { - size_t ni = entry.idx.name_idx; - size_t pi = entry.idx.point_idx; + for (const CounterAggregator& entry : bucket.counters) { + size_t ni = entry.idx.name().id(); + size_t pi = entry.idx.point().id(); const vespalib::string &name = _metricNames.lookup(ni); CounterSnapshot val(name, snap.points()[pi], entry); snap.add(val); } - for (const GaugeAggregator& entry : merged.gauges) { - size_t ni = entry.idx.name_idx; - size_t pi = entry.idx.point_idx; + for (const GaugeAggregator& entry : bucket.gauges) { + size_t ni = entry.idx.name().id(); + size_t pi = entry.idx.point().id(); const vespalib::string &name = _metricNames.lookup(ni); GaugeSnapshot val(name, snap.points()[pi], entry); snap.add(val); @@ -115,19 +112,18 @@ SimpleMetricsManager::snapshot() return snap; } -void -SimpleMetricsManager::doCollectLoop(SimpleMetricsManager *me) +Snapshot +SimpleMetricsManager::snapshot() { - const std::chrono::milliseconds jiffy{20}; - const std::chrono::seconds oneSec{1}; - while (!me->_stopFlag) { - std::this_thread::sleep_for(jiffy); - InternalTimeStamp now = now_stamp(); - InternalTimeStamp::duration elapsed = now - me->_curTime; - if (elapsed >= oneSec) { - me->collectCurrentBucket(); - } - } + Bucket merged = mergeBuckets(); + return snapshotFrom(merged); +} + +Snapshot +SimpleMetricsManager::totalSnapshot() +{ + Guard guard(_bucketsLock); + return snapshotFrom(_totalsBucket); } void @@ -141,15 +137,15 @@ SimpleMetricsManager::collectCurrentBucket() Guard guard(_currentBucket.lock); swap(samples, _currentBucket); } + Bucket newBucket(prev, curr); + newBucket.merge(samples); - Bucket merger(prev, curr); Guard guard(_bucketsLock); + _totalsBucket.merge(newBucket); if (_buckets.size() < _maxBuckets) { - _buckets.push_back(merger); - _buckets.back().merge(samples); + _buckets.emplace_back(std::move(newBucket)); } else { - merger.merge(samples); - swap(_buckets[_firstBucket], merger); + _buckets[_firstBucket] = std::move(newBucket); _firstBucket = (_firstBucket + 1) % _buckets.size(); } _curTime = curr; @@ -174,24 +170,15 @@ SimpleMetricsManager::label(const vespalib::string &value) PointBuilder SimpleMetricsManager::pointBuilder(Point from) { - Guard guard(_pointMaps.lock); - const PointMap &map = _pointMaps.vec[from.id()]->first; - return PointBuilder(shared_from_this(), map.backing()); + const PointMap &map = _pointMaps.lookup(from.id()); + return PointBuilder(shared_from_this(), map.backingMap()); } Point -SimpleMetricsManager::pointFrom(PointMapBacking &&map) +SimpleMetricsManager::pointFrom(PointMap::BackingMap map) { - Guard guard(_pointMaps.lock); - size_t nextId = _pointMaps.vec.size(); - auto iter_check = _pointMaps.map.emplace(std::move(map), nextId); - if (iter_check.second) { - LOG(debug, "new point map -> %zd / %zd", nextId, iter_check.first->second); - _pointMaps.vec.push_back(iter_check.first); - } else { - LOG(debug, "found point map -> %zd", iter_check.first->second); - } - return Point(iter_check.first->second); + size_t id = _pointMaps.resolve(PointMap(std::move(map))); + return Point(id); } } // namespace vespalib::metrics diff --git a/staging_vespalib/src/vespa/vespalib/metrics/simple_metrics_manager.h b/staging_vespalib/src/vespa/vespalib/metrics/simple_metrics_manager.h index a768ef7f29e..5f6cb881480 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/simple_metrics_manager.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/simple_metrics_manager.h @@ -5,11 +5,14 @@ #include <thread> #include <vespa/vespalib/stllike/string.h> #include "name_collection.h" -#include "mergers.h" +#include "current_samples.h" #include "snapshots.h" #include "metrics_manager.h" #include "metric_types.h" #include "clock.h" +#include "point_map_collection.h" +#include "bucket.h" +#include "ticker_thread.h" namespace vespalib { namespace metrics { @@ -26,7 +29,7 @@ struct SimpleManagerConfig { * single global repo with std::mutex locks used around * most operations. Only implements sliding window * and a fixed (1 Hz) collecting interval. - * Consider renaming to "LockingManager" or "SlidingWindowManager". + * XXX: Consider renaming this to "SlidingWindowManager". **/ class SimpleMetricsManager : public MetricsManager { @@ -35,12 +38,7 @@ private: MetricTypes _metricTypes; NameCollection _dimensionNames; NameCollection _labelValues; - using PointMapMap = std::map<PointMap, size_t>; - struct { - std::mutex lock; - PointMapMap map; - std::vector<PointMapMap::const_iterator> vec; - } _pointMaps; + PointMapCollection _pointMaps; const vespalib::string& nameFor(Dimension dimension) { return _dimensionNames.lookup(dimension.id()); } const vespalib::string& valueFor(Label label) { return _labelValues.lookup(label.id()); } @@ -54,12 +52,12 @@ private: std::vector<Bucket> _buckets; size_t _firstBucket; size_t _maxBuckets; + Bucket _totalsBucket; - bool _stopFlag; - std::thread _collectorThread; - static void doCollectLoop(SimpleMetricsManager *me); + TickerThread _ticker; void collectCurrentBucket(); // called once per second from another thread Bucket mergeBuckets(); + Snapshot snapshotFrom(const Bucket &bucket); SimpleMetricsManager(const SimpleManagerConfig &config); public: @@ -71,17 +69,20 @@ public: Dimension dimension(const vespalib::string &name) override; Label label(const vespalib::string &value) override; PointBuilder pointBuilder(Point from) override; - Point pointFrom(PointMapBacking &&map) override; + Point pointFrom(PointMap::BackingMap map) override; Snapshot snapshot() override; + Snapshot totalSnapshot() override; // for use from Counter only - void add(CounterIncrement inc) override { + void add(Counter::Increment inc) override { _currentBucket.add(inc); } // for use from Gauge only - void sample(GaugeMeasurement value) override { + void sample(Gauge::Measurement value) override { _currentBucket.sample(value); } + + void tick() { collectCurrentBucket(); } }; } // namespace vespalib::metrics diff --git a/staging_vespalib/src/vespa/vespalib/metrics/snapshots.h b/staging_vespalib/src/vespa/vespalib/metrics/snapshots.h index 87be72d2d52..406df44d894 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/snapshots.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/snapshots.h @@ -2,37 +2,41 @@ #pragma once #include <vespa/vespalib/stllike/string.h> -#include "mergers.h" +#include <vector> +#include "counter_aggregator.h" +#include "gauge_aggregator.h" namespace vespalib { namespace metrics { -class AxisMeasure { +class DimensionBinding { private: - const vespalib::string &_dimensionName; - const vespalib::string &_labelValue; + const vespalib::string _dimensionName; + const vespalib::string _labelValue; public: const vespalib::string &dimensionName() const { return _dimensionName; } const vespalib::string &labelValue() const { return _labelValue; } - AxisMeasure(const vespalib::string &a, - const vespalib::string &v) + DimensionBinding(const vespalib::string &a, + const vespalib::string &v) : _dimensionName(a), _labelValue(v) {} + ~DimensionBinding() {} }; struct PointSnapshot { - std::vector<AxisMeasure> dimensions; + std::vector<DimensionBinding> dimensions; }; class CounterSnapshot { private: - const vespalib::string &_name; + const vespalib::string _name; const PointSnapshot &_point; const size_t _count; public: CounterSnapshot(const vespalib::string &n, const PointSnapshot &p, const CounterAggregator &c) : _name(n), _point(p), _count(c.count) {} + ~CounterSnapshot() {} const vespalib::string &name() const { return _name; } const PointSnapshot &point() const { return _point; } size_t count() const { return _count; } @@ -40,7 +44,7 @@ public: class GaugeSnapshot { private: - const vespalib::string &_name; + const vespalib::string _name; const PointSnapshot &_point; const size_t _observedCount; const double _averageValue; @@ -57,6 +61,7 @@ public: _maxValue(c.maxValue), _lastValue(c.lastValue) {} + ~GaugeSnapshot() {} const vespalib::string &name() const { return _name; } const PointSnapshot &point() const { return _point; } size_t observedCount() const { return _observedCount; } @@ -91,6 +96,7 @@ public: Snapshot(double s, double e) : _start(s), _end(e), _counters(), _gauges() {} + ~Snapshot() {} void add(const PointSnapshot &entry) { _points.push_back(entry); } void add(const CounterSnapshot &entry) { _counters.push_back(entry); } void add(const GaugeSnapshot &entry) { _gauges.push_back(entry); } diff --git a/staging_vespalib/src/vespa/vespalib/metrics/no_realloc_bunch.cpp b/staging_vespalib/src/vespa/vespalib/metrics/stable_store.cpp index 4e641ff1c31..dd649133988 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/no_realloc_bunch.cpp +++ b/staging_vespalib/src/vespa/vespalib/metrics/stable_store.cpp @@ -1,4 +1,4 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include "no_realloc_bunch.h" +#include "stable_store.h" diff --git a/staging_vespalib/src/vespa/vespalib/metrics/no_realloc_bunch.h b/staging_vespalib/src/vespa/vespalib/metrics/stable_store.h index e5bd8f7af62..ca9db21a2d8 100644 --- a/staging_vespalib/src/vespa/vespalib/metrics/no_realloc_bunch.h +++ b/staging_vespalib/src/vespa/vespalib/metrics/stable_store.h @@ -9,16 +9,16 @@ namespace vespalib { template <typename T> -class NoReallocBunch +class StableStore { - using MyClass = NoReallocBunch<T>; + using MyClass = StableStore<T>; template<typename U> - friend void swap(NoReallocBunch<U> &a, NoReallocBunch<U> &b); + friend void swap(StableStore<U> &a, StableStore<U> &b); public: typedef std::unique_ptr<MyClass> UP; - NoReallocBunch(); - ~NoReallocBunch() {} + StableStore(); + ~StableStore() {} void add(T t) { size_t sz = _mine.size(); @@ -33,7 +33,7 @@ public: } template<typename FUNC> - void apply(FUNC &&func) const { + void for_each(FUNC &&func) const { std::vector<const MyClass *> vv; dffill(vv); for (const MyClass *p : vv) { @@ -45,28 +45,13 @@ public: size_t size() const { return _size; } - const T& lookup(size_t idx) const { - assert(idx < _size); - std::vector<const MyClass *> vv; - dffill(vv); - for (const MyClass *p : vv) { - size_t sz = p->_mine.size(); - if (idx < sz) { - return p->_mine[idx]; - } - idx -= sz; - } - // assert: - return *((T*)nullptr); - } - private: void dffill(std::vector<const MyClass *> &vv) const { if (_more) { _more->dffill(vv); } vv.push_back(this); } - NoReallocBunch(size_t sz, UP &&more, std::vector<T> &&mine); + StableStore(size_t sz, UP &&more, std::vector<T> &&mine); size_t _size; UP _more; @@ -74,7 +59,7 @@ private: }; template<typename T> -NoReallocBunch<T>::NoReallocBunch() +StableStore<T>::StableStore() : _size(0), _more(), _mine() @@ -83,15 +68,15 @@ NoReallocBunch<T>::NoReallocBunch() } template<typename T> -NoReallocBunch<T>::NoReallocBunch(size_t sz, UP &&more, std::vector<T> &&mine) +StableStore<T>::StableStore(size_t sz, UP &&more, std::vector<T> &&mine) : _size(sz), _more(std::move(more)), _mine(std::move(mine)) {} template <typename T> -void swap(NoReallocBunch<T> &a, - NoReallocBunch<T> &b) +void swap(StableStore<T> &a, + StableStore<T> &b) { using std::swap; swap(a._size, b._size); diff --git a/staging_vespalib/src/vespa/vespalib/metrics/ticker_thread.cpp b/staging_vespalib/src/vespa/vespalib/metrics/ticker_thread.cpp new file mode 100644 index 00000000000..dfed3bd053d --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/ticker_thread.cpp @@ -0,0 +1,43 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "ticker_thread.h" +#include "simple_metrics_manager.h" +#include <chrono> + +#include <vespa/log/log.h> +LOG_SETUP(".vespalib.metrics.ticker_thread"); + +namespace vespalib { +namespace metrics { + +void +TickerThread::doTickerLoop(TickerThread *me) +{ + me->tickerLoop(); +} + +void +TickerThread::tickerLoop() +{ + const std::chrono::seconds oneSec{1}; + std::unique_lock<std::mutex> locker(_lock); + while (_runFlag) { + auto r = _cond.wait_for(locker, oneSec); + if (r == std::cv_status::timeout) { + _owner->tick(); + } + } +} + +void +TickerThread::stop() +{ + std::unique_lock<std::mutex> locker(_lock); + _runFlag.store(false); + _cond.notify_all(); + locker.unlock(); + _thread.join(); +} + + +} // namespace vespalib::metrics +} // namespace vespalib diff --git a/staging_vespalib/src/vespa/vespalib/metrics/ticker_thread.h b/staging_vespalib/src/vespa/vespalib/metrics/ticker_thread.h new file mode 100644 index 00000000000..e00b68e8486 --- /dev/null +++ b/staging_vespalib/src/vespa/vespalib/metrics/ticker_thread.h @@ -0,0 +1,36 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include <atomic> +#include <condition_variable> +#include <mutex> +#include <thread> + +namespace vespalib { +namespace metrics { + +class SimpleMetricsManager; + +class TickerThread { +private: + SimpleMetricsManager *_owner; + std::mutex _lock; + std::atomic<bool> _runFlag; + std::condition_variable _cond; + std::thread _thread; + + static void doTickerLoop(TickerThread *me); + void tickerLoop(); +public: + TickerThread(SimpleMetricsManager * owner) + : _owner(owner), + _runFlag(true), + _thread(doTickerLoop, this) + {} + ~TickerThread() {} + + void stop(); +}; + +} // namespace vespalib::metrics +} // namespace vespalib |