From 3e451cba84d53199f865bf0fad6daf1b31da1c84 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 24 Jul 2019 10:51:43 -0700 Subject: [PATCH] Add some batch-update interfaces. --- src/medida/histogram.cc | 47 +++++++++++++++++-------- src/medida/histogram.h | 1 + src/medida/stats/exp_decay_sample.cc | 51 +++++++++++++++++++++------- src/medida/stats/exp_decay_sample.h | 2 ++ src/medida/stats/sample.h | 1 + src/medida/stats/uniform_sample.cc | 35 +++++++++++++------ src/medida/stats/uniform_sample.h | 1 + src/medida/timer.cc | 19 +++++++++++ src/medida/timer.h | 1 + 9 files changed, 121 insertions(+), 37 deletions(-) diff --git a/src/medida/histogram.cc b/src/medida/histogram.cc index e885f45..f47ae2c 100644 --- a/src/medida/histogram.cc +++ b/src/medida/histogram.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include "medida/stats/exp_decay_sample.h" #include "medida/stats/uniform_sample.h" @@ -26,6 +27,7 @@ class Histogram::Impl { double mean() const; double std_dev() const; void Update(std::int64_t value); + void Update(std::vector const& value); std::uint64_t count() const; double variance() const; void Process(MetricProcessor& processor); @@ -97,6 +99,10 @@ void Histogram::Update(std::int64_t value) { impl_->Update(value); } +void Histogram::Update(std::vector const& values) { + impl_->Update(values); +} + stats::Snapshot Histogram::GetSnapshot() const { return impl_->GetSnapshot(); } @@ -194,32 +200,43 @@ stats::Snapshot Histogram::Impl::GetSnapshot() const { void Histogram::Impl::Update(std::int64_t value) { - sample_->Update(value); + std::vector tmp{value}; + Update(tmp); +} + + +void Histogram::Impl::Update(std::vector const& values) { + sample_->Update(values); + auto pair = std::minmax_element(begin(values), end(values)); + auto minval = pair.first == values.end() ? 0 : *pair.first; + auto maxval = pair.second == values.end() ? 0 : *pair.second; if (count_ > 0) { auto cur_max = max_.load(); auto cur_min = min_.load(); - while (cur_max < value && !max_.compare_exchange_weak(cur_max, value)) { + while (cur_max < maxval && !max_.compare_exchange_weak(cur_max, maxval)) { // Spin until max is updated } - while(cur_min > value && !min_.compare_exchange_weak(cur_min, value)) { + while(cur_min > minval && !min_.compare_exchange_weak(cur_min, minval)) { // Spin until min is updated } } else { - max_ = value; - min_ = value; + max_ = maxval; + min_ = minval; } - sum_ += value; - auto new_count = ++count_; std::lock_guard lock {variance_mutex_}; - auto old_vm = variance_m_; - auto old_vs = variance_s_; - if (new_count > 1) { - variance_m_ = old_vm + (value - old_vm) / new_count; - variance_s_ = old_vs + (value - old_vm) * (value - variance_m_); - } else { - variance_m_ = value; + for (auto value : values) + { + sum_ += value; + auto new_count = ++count_; + auto old_vm = variance_m_; + auto old_vs = variance_s_; + if (new_count > 1) { + variance_m_ = old_vm + (value - old_vm) / new_count; + variance_s_ = old_vs + (value - old_vm) * (value - variance_m_); + } else { + variance_m_ = value; + } } } - } // namespace medida diff --git a/src/medida/histogram.h b/src/medida/histogram.h index 760fb32..fd8ffed 100644 --- a/src/medida/histogram.h +++ b/src/medida/histogram.h @@ -26,6 +26,7 @@ class Histogram : public MetricInterface, SamplingInterface, SummarizableInterfa virtual double mean() const; virtual double std_dev() const; void Update(std::int64_t value); + void Update(std::vector const& values); std::uint64_t count() const; double variance() const; void Process(MetricProcessor& processor); diff --git a/src/medida/stats/exp_decay_sample.cc b/src/medida/stats/exp_decay_sample.cc index 2042403..d373352 100644 --- a/src/medida/stats/exp_decay_sample.cc +++ b/src/medida/stats/exp_decay_sample.cc @@ -27,7 +27,9 @@ class ExpDecaySample::Impl { void Clear(); std::uint64_t size() const; void Update(std::int64_t value); + void Update(std::vector const& values); void Update(std::int64_t value, Clock::time_point timestamp); + void Update(std::vector const& values, Clock::time_point timestamp); Snapshot MakeSnapshot() const; private: const double alpha_; @@ -68,11 +70,21 @@ void ExpDecaySample::Update(std::int64_t value) { } +void ExpDecaySample::Update(std::vector const& values) { + impl_->Update(values); +} + + void ExpDecaySample::Update(std::int64_t value, Clock::time_point timestamp) { impl_->Update(value, timestamp); } +void ExpDecaySample::Update(std::vector const& values, Clock::time_point timestamp) { + impl_->Update(values, timestamp); +} + + Snapshot ExpDecaySample::MakeSnapshot() const { return impl_->MakeSnapshot(); } @@ -110,27 +122,42 @@ std::uint64_t ExpDecaySample::Impl::size() const { void ExpDecaySample::Impl::Update(std::int64_t value) { - Update(value, Clock::now()); + std::vector tmp{value}; + Update(tmp); +} + + +void ExpDecaySample::Impl::Update(std::vector const& values) { + Update(values, Clock::now()); } void ExpDecaySample::Impl::Update(std::int64_t value, Clock::time_point timestamp) { + std::vector tmp{value}; + Update(tmp, timestamp); +} + + +void ExpDecaySample::Impl::Update(std::vector const& values, Clock::time_point timestamp) { { if (timestamp >= nextScaleTime_) { Rescale(timestamp); } std::lock_guard lock {mutex_}; - auto dur = std::chrono::duration_cast(timestamp - startTime_); - auto priority = std::exp(alpha_ * dur.count()) / dist_(rng_); - auto count = ++count_; - - if (count <= reservoirSize_) { - values_[priority] = value; - } else { - auto first = std::begin(values_)->first; - if (first < priority && values_.insert({priority, value}).second) { - while (values_.erase(first) == 0) { - first = std::begin(values_)->first; + for (auto value : values) + { + auto dur = std::chrono::duration_cast(timestamp - startTime_); + auto priority = std::exp(alpha_ * dur.count()) / dist_(rng_); + auto count = ++count_; + + if (count <= reservoirSize_) { + values_[priority] = value; + } else { + auto first = std::begin(values_)->first; + if (first < priority && values_.insert({priority, value}).second) { + while (values_.erase(first) == 0) { + first = std::begin(values_)->first; + } } } } diff --git a/src/medida/stats/exp_decay_sample.h b/src/medida/stats/exp_decay_sample.h index 9843653..25e1e9b 100644 --- a/src/medida/stats/exp_decay_sample.h +++ b/src/medida/stats/exp_decay_sample.h @@ -22,7 +22,9 @@ class ExpDecaySample : public Sample { virtual void Clear(); virtual std::uint64_t size() const; virtual void Update(std::int64_t value); + virtual void Update(std::vector const& values); virtual void Update(std::int64_t value, Clock::time_point timestamp); + virtual void Update(std::vector const& values, Clock::time_point timestamp); virtual Snapshot MakeSnapshot() const; private: class Impl; diff --git a/src/medida/stats/sample.h b/src/medida/stats/sample.h index 41ec60e..7b9084f 100644 --- a/src/medida/stats/sample.h +++ b/src/medida/stats/sample.h @@ -19,6 +19,7 @@ class Sample { virtual void Clear() = 0; virtual std::uint64_t size() const = 0; virtual void Update(std::int64_t value) = 0; + virtual void Update(std::vector const& values) = 0; virtual Snapshot MakeSnapshot() const = 0; }; diff --git a/src/medida/stats/uniform_sample.cc b/src/medida/stats/uniform_sample.cc index 549fa58..377eb5f 100644 --- a/src/medida/stats/uniform_sample.cc +++ b/src/medida/stats/uniform_sample.cc @@ -20,6 +20,7 @@ class UniformSample::Impl { void Clear(); std::uint64_t size() const; void Update(std::int64_t value); + void Update(std::vector const& value); Snapshot MakeSnapshot() const; private: std::atomic count_; @@ -53,6 +54,11 @@ void UniformSample::Update(std::int64_t value) { } +void UniformSample::Update(std::vector const& values) { + impl_->Update(values); +} + + Snapshot UniformSample::MakeSnapshot() const { return impl_->MakeSnapshot(); } @@ -91,17 +97,26 @@ std::uint64_t UniformSample::Impl::size() const { void UniformSample::Impl::Update(std::int64_t value) { - auto count = ++count_; + std::vector tmp{value}; + Update(tmp); +} + + +void UniformSample::Impl::Update(std::vector const& values) { std::lock_guard lock {mutex_}; - auto size = values_.size(); - if (count < size) { - values_[count - 1] = value; - } else { - std::uniform_int_distribution uniform(0, count - 1); - auto rand = uniform(rng_); - if (rand < size) { - values_[rand] = value; - } + for (auto value : values) + { + auto count = ++count_; + auto size = values_.size(); + if (count < size) { + values_[count - 1] = value; + } else { + std::uniform_int_distribution uniform(0, count - 1); + auto rand = uniform(rng_); + if (rand < size) { + values_[rand] = value; + } + } } } diff --git a/src/medida/stats/uniform_sample.h b/src/medida/stats/uniform_sample.h index d520462..bddf3e3 100644 --- a/src/medida/stats/uniform_sample.h +++ b/src/medida/stats/uniform_sample.h @@ -21,6 +21,7 @@ class UniformSample : public Sample { virtual void Clear(); virtual std::uint64_t size() const; virtual void Update(std::int64_t value); + virtual void Update(std::vector const& values); virtual Snapshot MakeSnapshot() const; private: class Impl; diff --git a/src/medida/timer.cc b/src/medida/timer.cc index f2100fb..11af6b2 100644 --- a/src/medida/timer.cc +++ b/src/medida/timer.cc @@ -33,6 +33,7 @@ class Timer::Impl { std::chrono::nanoseconds duration_unit() const; void Clear(); void Update(std::chrono::nanoseconds duration); + void Update(std::vector durations); TimerContext TimeScope(); void Time(std::function); private: @@ -134,6 +135,9 @@ void Timer::Update(std::chrono::nanoseconds duration) { impl_->Update(duration); } +void Timer::Update(std::vector durations) { + impl_->Update(durations); +} stats::Snapshot Timer::GetSnapshot() const { return impl_->GetSnapshot(); @@ -251,6 +255,21 @@ void Timer::Impl::Update(std::chrono::nanoseconds duration) { } +void Timer::Impl::Update(std::vector durations) { + std::vector counts(durations.size()); + for (auto const& ns : durations) + { + auto count = ns.count(); + if (count != 0) + { + counts.emplace_back(count); + } + }; + histogram_.Update(counts); + meter_.Mark(counts.size()); +} + + stats::Snapshot Timer::Impl::GetSnapshot() const { auto values = histogram_.GetSnapshot().getValues(); std::vector converted; diff --git a/src/medida/timer.h b/src/medida/timer.h index fbe8bff..0f1e5e8 100644 --- a/src/medida/timer.h +++ b/src/medida/timer.h @@ -41,6 +41,7 @@ class Timer : public MetricInterface, MeteredInterface, SamplingInterface, Summa std::chrono::nanoseconds duration_unit() const; void Clear(); void Update(std::chrono::nanoseconds duration); + void Update(std::vector durations); TimerContext TimeScope(); void Time(std::function); private: