From c982c1c6cecd4818cf767a700bbc56387a80b32c Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Sun, 20 Nov 2016 03:04:28 +0100 Subject: Avoid including th ewhole world just to get some metrics. --- metrics/src/tests/countmetrictest.cpp | 2 +- metrics/src/tests/loadmetrictest.cpp | 2 + metrics/src/tests/metricmanagertest.cpp | 1 + metrics/src/tests/snapshottest.cpp | 4 +- metrics/src/tests/stresstest.cpp | 4 +- metrics/src/tests/summetrictest.cpp | 3 +- metrics/src/tests/valuemetrictest.cpp | 1 + metrics/src/vespa/metrics/CMakeLists.txt | 18 +- metrics/src/vespa/metrics/countmetric.cpp | 4 +- metrics/src/vespa/metrics/countmetric.h | 230 +------------- metrics/src/vespa/metrics/countmetric.hpp | 199 ++++++++++++ metrics/src/vespa/metrics/countmetricvalues.cpp | 9 + metrics/src/vespa/metrics/countmetricvalues.h | 47 +++ metrics/src/vespa/metrics/countmetricvalues.hpp | 37 +++ metrics/src/vespa/metrics/loadmetric.cpp | 20 ++ metrics/src/vespa/metrics/loadmetric.h | 104 +------ metrics/src/vespa/metrics/loadmetric.hpp | 84 ++++++ metrics/src/vespa/metrics/memoryconsumption.cpp | 113 +++++++ metrics/src/vespa/metrics/memoryconsumption.h | 107 +------ metrics/src/vespa/metrics/metric.cpp | 9 +- metrics/src/vespa/metrics/metric.h | 13 +- metrics/src/vespa/metrics/metricset.cpp | 3 +- metrics/src/vespa/metrics/metricvalueset.cpp | 21 ++ metrics/src/vespa/metrics/metricvalueset.h | 92 +----- metrics/src/vespa/metrics/metricvalueset.hpp | 97 ++++++ metrics/src/vespa/metrics/summetric.cpp | 16 + metrics/src/vespa/metrics/summetric.h | 354 +--------------------- metrics/src/vespa/metrics/summetric.hpp | 335 +++++++++++++++++++++ metrics/src/vespa/metrics/textwriter.cpp | 12 +- metrics/src/vespa/metrics/textwriter.h | 2 +- metrics/src/vespa/metrics/valuemetric.cpp | 9 +- metrics/src/vespa/metrics/valuemetric.h | 383 +----------------------- metrics/src/vespa/metrics/valuemetric.hpp | 289 ++++++++++++++++++ metrics/src/vespa/metrics/valuemetricvalues.cpp | 13 + metrics/src/vespa/metrics/valuemetricvalues.h | 49 +++ metrics/src/vespa/metrics/valuemetricvalues.hpp | 93 ++++++ 36 files changed, 1526 insertions(+), 1253 deletions(-) create mode 100644 metrics/src/vespa/metrics/countmetric.hpp create mode 100644 metrics/src/vespa/metrics/countmetricvalues.cpp create mode 100644 metrics/src/vespa/metrics/countmetricvalues.h create mode 100644 metrics/src/vespa/metrics/countmetricvalues.hpp create mode 100644 metrics/src/vespa/metrics/loadmetric.cpp create mode 100644 metrics/src/vespa/metrics/loadmetric.hpp create mode 100644 metrics/src/vespa/metrics/memoryconsumption.cpp create mode 100644 metrics/src/vespa/metrics/metricvalueset.cpp create mode 100644 metrics/src/vespa/metrics/metricvalueset.hpp create mode 100644 metrics/src/vespa/metrics/summetric.cpp create mode 100644 metrics/src/vespa/metrics/summetric.hpp create mode 100644 metrics/src/vespa/metrics/valuemetric.hpp create mode 100644 metrics/src/vespa/metrics/valuemetricvalues.cpp create mode 100644 metrics/src/vespa/metrics/valuemetricvalues.h create mode 100644 metrics/src/vespa/metrics/valuemetricvalues.hpp (limited to 'metrics') diff --git a/metrics/src/tests/countmetrictest.cpp b/metrics/src/tests/countmetrictest.cpp index 9c99e6c686b..82eb65caf25 100644 --- a/metrics/src/tests/countmetrictest.cpp +++ b/metrics/src/tests/countmetrictest.cpp @@ -48,7 +48,7 @@ void CountMetricTest::testLongCountMetric() CPPUNIT_ASSERT_EQUAL(Double(84), Double(o.getDoubleValue("value"))); CPPUNIT_ASSERT_EQUAL(int64_t(84), o.getLongValue("value")); - (void) expected; +// (void) expected; } } diff --git a/metrics/src/tests/loadmetrictest.cpp b/metrics/src/tests/loadmetrictest.cpp index b0755fa46e9..3585f4adf32 100644 --- a/metrics/src/tests/loadmetrictest.cpp +++ b/metrics/src/tests/loadmetrictest.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include namespace metrics { diff --git a/metrics/src/tests/metricmanagertest.cpp b/metrics/src/tests/metricmanagertest.cpp index 31471cc40ed..d3349d2e91d 100644 --- a/metrics/src/tests/metricmanagertest.cpp +++ b/metrics/src/tests/metricmanagertest.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/metrics/src/tests/snapshottest.cpp b/metrics/src/tests/snapshottest.cpp index 800d9f8465a..626b53f7d90 100644 --- a/metrics/src/tests/snapshottest.cpp +++ b/metrics/src/tests/snapshottest.cpp @@ -1,10 +1,12 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include -#include #include +#include +#include #include +#include LOG_SETUP(".test.snapshot"); namespace metrics { diff --git a/metrics/src/tests/stresstest.cpp b/metrics/src/tests/stresstest.cpp index f88c3a4944c..cb069f27300 100644 --- a/metrics/src/tests/stresstest.cpp +++ b/metrics/src/tests/stresstest.cpp @@ -1,9 +1,11 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include -#include #include +#include +#include #include +#include LOG_SETUP(".metrics.test.stress"); namespace metrics { diff --git a/metrics/src/tests/summetrictest.cpp b/metrics/src/tests/summetrictest.cpp index fd4d67d7f3b..3b5812f363f 100644 --- a/metrics/src/tests/summetrictest.cpp +++ b/metrics/src/tests/summetrictest.cpp @@ -1,7 +1,8 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include -#include #include +#include +#include namespace metrics { diff --git a/metrics/src/tests/valuemetrictest.cpp b/metrics/src/tests/valuemetrictest.cpp index afe4221481e..e50d4c69dfb 100644 --- a/metrics/src/tests/valuemetrictest.cpp +++ b/metrics/src/tests/valuemetrictest.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/metrics/src/vespa/metrics/CMakeLists.txt b/metrics/src/vespa/metrics/CMakeLists.txt index 7a1813d7e18..eeb90553309 100644 --- a/metrics/src/vespa/metrics/CMakeLists.txt +++ b/metrics/src/vespa/metrics/CMakeLists.txt @@ -1,17 +1,23 @@ # Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. vespa_add_library(metrics SOURCES - metric.cpp countmetric.cpp - valuemetric.cpp - metrictimer.cpp - metricset.cpp + countmetricvalues.cpp + jsonwriter.cpp + loadmetric.cpp + metric.cpp + memoryconsumption.cpp metricmanager.cpp + metricset.cpp metricsnapshot.cpp - jsonwriter.cpp + metrictimer.cpp + metricvalueset.cpp + state_api_adapter.cpp + summetric.cpp textwriter.cpp + valuemetric.cpp + valuemetricvalues.cpp xmlwriter.cpp - state_api_adapter.cpp INSTALL lib64 DEPENDS ) diff --git a/metrics/src/vespa/metrics/countmetric.cpp b/metrics/src/vespa/metrics/countmetric.cpp index d152c09a242..9f5ae741b30 100644 --- a/metrics/src/vespa/metrics/countmetric.cpp +++ b/metrics/src/vespa/metrics/countmetric.cpp @@ -1,7 +1,7 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include -#include +#include "countmetric.hpp" #include @@ -22,4 +22,6 @@ AbstractCountMetric::sendLogCountEvent( EV_COUNT(name.c_str(), value); } +template class CountMetric; + } // metrics diff --git a/metrics/src/vespa/metrics/countmetric.h b/metrics/src/vespa/metrics/countmetric.h index c9eef00f6ea..65281fb5b3a 100644 --- a/metrics/src/vespa/metrics/countmetric.h +++ b/metrics/src/vespa/metrics/countmetric.h @@ -13,17 +13,13 @@ #pragma once -#include #include -#include -#include -#include +#include "countmetricvalues.h" namespace metrics { struct AbstractCountMetric : public Metric { - virtual bool visit(MetricVisitor& visitor, - bool tagAsAutoGenerated = false) const + virtual bool visit(MetricVisitor& visitor, bool tagAsAutoGenerated = false) const { return visitor.visitCountMetric(*this, tagAsAutoGenerated); } @@ -56,38 +52,7 @@ protected: template class CountMetric : public AbstractCountMetric { - struct Values : public MetricValueClass { - T _value; - - struct AtomicImpl { - std::atomic _value {0}; - }; - - void relaxedStoreInto(AtomicImpl& target) const noexcept { - target._value.store(_value, std::memory_order_relaxed); - } - - void relaxedLoadFrom(const AtomicImpl& source) noexcept { - _value = source._value.load(std::memory_order_relaxed); - } - - Values() : _value(0) {} - - std::string toString() const { - std::ostringstream ost; - ost << _value; - return ost.str(); - } - double getDoubleValue(const stringref &) const - { return static_cast(_value); } - uint64_t getLongValue(const stringref &) const - { return static_cast(_value); } - void output(const std::string&, std::ostream& out) const - { out << _value; } - void output(const std::string&, vespalib::JsonStream& stream) const - { stream << _value; } - bool inUse() const { return (_value != 0); } - }; + using Values = CountMetricValues; MetricValueSet _values; enum Flag { LOG_IF_UNSET = 2 }; @@ -160,198 +125,9 @@ public: virtual void addToPart(Metric&) const; virtual void addToSnapshot(Metric&, std::vector&) const; - }; typedef CountMetric LongCountMetric; -template -CountMetric::CountMetric(const String& name, const String& tags, - const String& desc, MetricSet* owner) - : AbstractCountMetric(name, tags, desc, owner), - _values() -{ - _values.setFlag(LOG_IF_UNSET); -} - -template -CountMetric::CountMetric(const String& name, Tags dimensions, - const String& desc, MetricSet* owner) - : AbstractCountMetric(name, std::move(dimensions), desc, owner), - _values() -{ - _values.setFlag(LOG_IF_UNSET); -} - -template -CountMetric::CountMetric(const CountMetric& other, - CopyType copyType, MetricSet* owner) - : AbstractCountMetric(other, owner), - _values(other._values, copyType == CLONE ? other._values.size() : 1) -{ -} - -template -CountMetric& -CountMetric::operator+=(const CountMetric& other) -{ - T otherValues(other.getValue()); - bool overflow; - Values values; - do { - values = _values.getValues(); - overflow = (values._value + otherValues < values._value); - values._value += otherValues; - } while (!_values.setValues(values)); - if (overflow) { - _values.reset(); - std::ostringstream ost; - ost << "Overflow in metric " << getPath() << " op +=. Resetting it."; - logWarning(ost.str().c_str()); - } - return *this; -} - -template -CountMetric& -CountMetric::operator-=(const CountMetric& other) -{ - T otherValues(other.getValue()); - bool underflow; - Values values; - do { - values = _values.getValues(); - underflow = (values._value - otherValues > values._value); - values._value -= otherValues; - } while (!_values.setValues(values)); - if (underflow) { - _values.reset(); - std::ostringstream ost; - ost << "Underflow in metric " << getPath() << " op -=. Resetting it."; - logWarning(ost.str().c_str()); - } - return *this; -} - -template -void -CountMetric::set(T value) -{ - Values values; - values._value = value; - while (!_values.setValues(values)) {} -} - -template -void -CountMetric::inc(T value) -{ - bool overflow; - Values values; - do { - values = _values.getValues(); - overflow = (values._value + value < values._value); - values._value += value; - } while (!_values.setValues(values)); - if (overflow) { - _values.reset(); - std::ostringstream ost; - ost << "Overflow in metric " << getPath() << ". Resetting it."; - logWarning(ost.str().c_str()); - } -} - -template -void -CountMetric::dec(T value) -{ - bool underflow; - Values values; - do { - values = _values.getValues(); - underflow = (values._value - value > values._value); - values._value -= value; - } while (!_values.setValues(values)); - if (underflow) { - _values.reset(); - std::ostringstream ost; - ost << "Underflow in metric " << getPath() << ". Resetting it."; - logWarning(ost.str().c_str()); - } -} - -template -void -CountMetric::addToSnapshot( - Metric& other, std::vector&) const -{ - CountMetric& o( - reinterpret_cast&>(other)); - o.inc(_values.getValues()._value); -} - -template -void -CountMetric::addToPart(Metric& other) const -{ - CountMetric& o( - reinterpret_cast&>(other)); - if (SumOnAdd) { - o.inc(_values.getValues()._value); - } else { - o.set((_values.getValues()._value + o._values.getValues()._value) / 2); - } -} - -template -bool -CountMetric::logEvent(const String& fullName) const -{ - Values values(_values.getValues()); - if (!logIfUnset() && values._value == 0) return false; - sendLogCountEvent( - fullName, static_cast(values._value)); - return true; -} - -template -void -CountMetric::print(std::ostream& out, bool verbose, - const std::string& indent, - uint64_t secondsPassed) const -{ - (void) indent; - Values values(_values.getValues()); - if (values._value == 0 && !verbose) return; - out << this->_name << (SumOnAdd ? " count=" : " value=") << values._value; - if (SumOnAdd) { - if (secondsPassed != 0) { - double avgDiff = values._value / ((double) secondsPassed); - out << " average_change_per_second=" << avgDiff; - } - } -} - -template -void -CountMetric::addMemoryUsage(MemoryConsumption& mc) const -{ - ++mc._countMetricCount; - mc._countMetricValues += _values.getMemoryUsageAllocatedInternally(); - mc._countMetricMeta += sizeof(CountMetric) - - sizeof(Metric); - Metric::addMemoryUsage(mc); -} - -template -void -CountMetric::printDebug(std::ostream& out, - const std::string& indent) const -{ - Values values(_values.getValues()); - out << "count=" << values._value << " "; - Metric::printDebug(out, indent); -} - } // metrics diff --git a/metrics/src/vespa/metrics/countmetric.hpp b/metrics/src/vespa/metrics/countmetric.hpp new file mode 100644 index 00000000000..f2f7b953a31 --- /dev/null +++ b/metrics/src/vespa/metrics/countmetric.hpp @@ -0,0 +1,199 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "countmetric.h" +#include "memoryconsumption.h" +#include + +namespace metrics { + +template +CountMetric::CountMetric(const String& name, const String& tags, + const String& desc, MetricSet* owner) + : AbstractCountMetric(name, tags, desc, owner), + _values() +{ + _values.setFlag(LOG_IF_UNSET); +} + +template +CountMetric::CountMetric(const String& name, Tags dimensions, + const String& desc, MetricSet* owner) + : AbstractCountMetric(name, std::move(dimensions), desc, owner), + _values() +{ + _values.setFlag(LOG_IF_UNSET); +} + +template +CountMetric::CountMetric(const CountMetric& other, + CopyType copyType, MetricSet* owner) + : AbstractCountMetric(other, owner), + _values(other._values, copyType == CLONE ? other._values.size() : 1) +{ +} + +template +CountMetric& +CountMetric::operator+=(const CountMetric& other) +{ + T otherValues(other.getValue()); + bool overflow; + Values values; + do { + values = _values.getValues(); + overflow = (values._value + otherValues < values._value); + values._value += otherValues; + } while (!_values.setValues(values)); + if (overflow) { + _values.reset(); + std::ostringstream ost; + ost << "Overflow in metric " << getPath() << " op +=. Resetting it."; + logWarning(ost.str().c_str()); + } + return *this; +} + +template +CountMetric& +CountMetric::operator-=(const CountMetric& other) +{ + T otherValues(other.getValue()); + bool underflow; + Values values; + do { + values = _values.getValues(); + underflow = (values._value - otherValues > values._value); + values._value -= otherValues; + } while (!_values.setValues(values)); + if (underflow) { + _values.reset(); + std::ostringstream ost; + ost << "Underflow in metric " << getPath() << " op -=. Resetting it."; + logWarning(ost.str().c_str()); + } + return *this; +} + +template +void +CountMetric::set(T value) +{ + Values values; + values._value = value; + while (!_values.setValues(values)) {} +} + +template +void +CountMetric::inc(T value) +{ + bool overflow; + Values values; + do { + values = _values.getValues(); + overflow = (values._value + value < values._value); + values._value += value; + } while (!_values.setValues(values)); + if (overflow) { + _values.reset(); + std::ostringstream ost; + ost << "Overflow in metric " << getPath() << ". Resetting it."; + logWarning(ost.str().c_str()); + } +} + +template +void +CountMetric::dec(T value) +{ + bool underflow; + Values values; + do { + values = _values.getValues(); + underflow = (values._value - value > values._value); + values._value -= value; + } while (!_values.setValues(values)); + if (underflow) { + _values.reset(); + std::ostringstream ost; + ost << "Underflow in metric " << getPath() << ". Resetting it."; + logWarning(ost.str().c_str()); + } +} + +template +void +CountMetric::addToSnapshot( + Metric& other, std::vector&) const +{ + CountMetric& o( + reinterpret_cast&>(other)); + o.inc(_values.getValues()._value); +} + +template +void +CountMetric::addToPart(Metric& other) const +{ + CountMetric& o( + reinterpret_cast&>(other)); + if (SumOnAdd) { + o.inc(_values.getValues()._value); + } else { + o.set((_values.getValues()._value + o._values.getValues()._value) / 2); + } +} + +template +bool +CountMetric::logEvent(const String& fullName) const +{ + Values values(_values.getValues()); + if (!logIfUnset() && values._value == 0) return false; + sendLogCountEvent( + fullName, static_cast(values._value)); + return true; +} + +template +void +CountMetric::print(std::ostream& out, bool verbose, + const std::string& indent, + uint64_t secondsPassed) const +{ + (void) indent; + Values values(_values.getValues()); + if (values._value == 0 && !verbose) return; + out << this->_name << (SumOnAdd ? " count=" : " value=") << values._value; + if (SumOnAdd) { + if (secondsPassed != 0) { + double avgDiff = values._value / ((double) secondsPassed); + out << " average_change_per_second=" << avgDiff; + } + } +} + +template +void +CountMetric::addMemoryUsage(MemoryConsumption& mc) const +{ + ++mc._countMetricCount; + mc._countMetricValues += _values.getMemoryUsageAllocatedInternally(); + mc._countMetricMeta += sizeof(CountMetric) + - sizeof(Metric); + Metric::addMemoryUsage(mc); +} + +template +void +CountMetric::printDebug(std::ostream& out, + const std::string& indent) const +{ + Values values(_values.getValues()); + out << "count=" << values._value << " "; + Metric::printDebug(out, indent); +} + +} // metrics + diff --git a/metrics/src/vespa/metrics/countmetricvalues.cpp b/metrics/src/vespa/metrics/countmetricvalues.cpp new file mode 100644 index 00000000000..6be0f6a72d1 --- /dev/null +++ b/metrics/src/vespa/metrics/countmetricvalues.cpp @@ -0,0 +1,9 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "countmetricvalues.hpp" + +namespace metrics { + +template class CountMetricValues; + +} // metrics diff --git a/metrics/src/vespa/metrics/countmetricvalues.h b/metrics/src/vespa/metrics/countmetricvalues.h new file mode 100644 index 00000000000..210668972a9 --- /dev/null +++ b/metrics/src/vespa/metrics/countmetricvalues.h @@ -0,0 +1,47 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/** + * \class CountMetric + * \ingroup metrics + * + * \brief Metric representing a count. + * + * A counter metric have the following properties: + * - It can never decrease, only increase. + * - Logs its value as a count event. + * - When summing counts, the counts are added together. + */ + +#pragma once + +#include +#include + +namespace metrics { + +template +struct CountMetricValues : public MetricValueClass { + T _value; + + struct AtomicImpl { + std::atomic _value {0}; + }; + + void relaxedStoreInto(AtomicImpl& target) const noexcept { + target._value.store(_value, std::memory_order_relaxed); + } + + void relaxedLoadFrom(const AtomicImpl& source) noexcept { + _value = source._value.load(std::memory_order_relaxed); + } + + CountMetricValues() : _value(0) {} + + std::string toString() const; + double getDoubleValue(const stringref &) const override; + uint64_t getLongValue(const stringref &) const override; + void output(const std::string&, std::ostream& out) const override; + void output(const std::string&, vespalib::JsonStream& stream) const override; + bool inUse() const { return (_value != 0); } +}; + +} // metrics diff --git a/metrics/src/vespa/metrics/countmetricvalues.hpp b/metrics/src/vespa/metrics/countmetricvalues.hpp new file mode 100644 index 00000000000..3d94b0b23ee --- /dev/null +++ b/metrics/src/vespa/metrics/countmetricvalues.hpp @@ -0,0 +1,37 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "countmetricvalues.h" +#include + +namespace metrics { + +template +std::string +CountMetricValues::toString() const { + std::ostringstream ost; + ost << _value; + return ost.str(); +} +template +double +CountMetricValues::getDoubleValue(const stringref &) const { + return static_cast(_value); +} +template +uint64_t +CountMetricValues::getLongValue(const stringref &) const { + return static_cast(_value); +} +template +void +CountMetricValues::output(const std::string&, std::ostream& out) const { + out << _value; +} +template +void +CountMetricValues::output(const std::string&, vespalib::JsonStream& stream) const { + stream << _value; +} + +} // metrics diff --git a/metrics/src/vespa/metrics/loadmetric.cpp b/metrics/src/vespa/metrics/loadmetric.cpp new file mode 100644 index 00000000000..861b1256bff --- /dev/null +++ b/metrics/src/vespa/metrics/loadmetric.cpp @@ -0,0 +1,20 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "loadmetric.hpp" +#include "valuemetric.h" +#include "countmetric.h" +#include + +namespace metrics { + +vespalib::string +LoadType::toString() const { + return vespalib::make_string("%s(%u)", _name.c_str(), _id); +} + +template class LoadMetric>; +template class LoadMetric>; +template class LoadMetric>; +template class LoadMetric>; +template class LoadMetric>; + +} diff --git a/metrics/src/vespa/metrics/loadmetric.h b/metrics/src/vespa/metrics/loadmetric.h index dc0762dd161..c141c2d9e61 100644 --- a/metrics/src/vespa/metrics/loadmetric.h +++ b/metrics/src/vespa/metrics/loadmetric.h @@ -18,10 +18,8 @@ #pragma once -#include -#include -#include -#include +#include "metricset.h" +#include "summetric.h" #include namespace metrics { @@ -30,15 +28,13 @@ class MetricSet; class LoadType { public: - typedef vespalib::string string; + using string = vespalib::string; LoadType(uint32_t id, const string& name) : _id(id), _name(name) {} uint32_t getId() const { return _id; } const string& getName() const { return _name; } - string toString() const { - return vespalib::make_string("%s(%u)", _name.c_str(), _id); - } + string toString() const; private: uint32_t _id; string _name; @@ -47,43 +43,18 @@ private: typedef std::vector LoadTypeSet; template -class LoadMetric : public metrics::MetricSet { - std::vector _ownerList; +class LoadMetric : public MetricSet { + std::vector _ownerList; typedef vespalib::LinkedPtr MetricTypeLP; vespalib::hash_map _metrics; - metrics::SumMetric _sum; + SumMetric _sum; public: /** * Create a load metric using the given metric as a template to how they * shuold look. They will get prefix names based on load types existing. */ - LoadMetric(const LoadTypeSet& loadTypes, const MetricType& metric, - metrics::MetricSet* owner = 0) - : MetricSet(metric.getName(), "", metric.getDescription(), owner), - _metrics(), - _sum("sum", "loadsum sum", "Sum of all load metrics", this) - { - _metrics.resize(loadTypes.size()); - // Currently, we only set tags and description on the metric set - // itself, to cut down on size of output when downloading metrics, - // and since matching tags of parent is just as good as matching - // them specifically. - setTags(metric.getTags()); - Tags noTags; - for (uint32_t i=0; i( - metric.clone(_ownerList, CLONE, 0, false))); - assert(copy.get()); - copy->setName(loadTypes[i].getName()); - copy->setTags(noTags); - _metrics[loadTypes[i].getId()] = copy; - registerMetric(*copy); - _sum.addMetricToSum(*copy); - } - metrics::trim(_ownerList); - } + LoadMetric(const LoadTypeSet& loadTypes, const MetricType& metric, MetricSet* owner = 0); /** * A load metric implements a copy constructor and a clone functions that @@ -92,38 +63,10 @@ public: * then assign the values to the new set. (Without screwing up copying as * the load metric alters this data in supplied metric) */ - LoadMetric(const LoadMetric& other, metrics::MetricSet* owner) - : MetricSet(other.getName(), "", other.getDescription(), owner), - _metrics(), - _sum("sum", "loadsum sum", "Sum of all load metrics", this) - { - _metrics.resize(2 * other._metrics.size()); - setTags(other.getTags()); - Tags noTags; - for (typename vespalib::hash_map::const_iterator - it = other._metrics.begin(); it != other._metrics.end(); ++it) - { - MetricTypeLP copy(dynamic_cast( - it->second->clone(_ownerList, CLONE, 0, false))); - assert(copy.get()); - copy->setName(it->second->getName()); - copy->setTags(noTags); - _metrics[it->first] = copy; - registerMetric(*copy); - _sum.addMetricToSum(*copy); - } - metrics::trim(_ownerList); - } - - virtual Metric* clone(std::vector& ownerList, - CopyType copyType, MetricSet* owner, - bool includeUnused = false) const - { - if (copyType == INACTIVE) { - return MetricSet::clone(ownerList, INACTIVE, owner, includeUnused); - } - return new LoadMetric(*this, owner); - } + LoadMetric(const LoadMetric& other, MetricSet* owner); + Metric* clone(std::vector& ownerList, + CopyType copyType, MetricSet* owner, + bool includeUnused = false) const override; MetricType& operator[](const LoadType& type) { return getMetric(type); } const MetricType& operator[](const LoadType& type) const @@ -136,31 +79,14 @@ public: if (it == _metrics.end()) { it = _metrics.find(0); assert(it != _metrics.end()); // Default should always exist - metric = it->second.get(); - assert(metric); - } else { - metric = it->second.get(); - assert(metric); } + metric = it->second.get(); + assert(metric); return *metric; } - virtual void addMemoryUsage(metrics::MemoryConsumption& mc) const { - ++mc._loadMetricCount; - mc._loadMetricMeta += sizeof(metrics::Metric::LP) * _ownerList.size(); - for (typename vespalib::hash_map::const_iterator - it = _metrics.begin(); it != _metrics.end(); ++it) - { - mc._loadMetricMeta += sizeof(uint32_t) + sizeof(MetricTypeLP); - } - _sum.addMemoryUsage(mc); - mc._loadMetricMeta += sizeof(LoadMetric) - - sizeof(metrics::MetricSet) - - sizeof(metrics::SumMetric); - metrics::MetricSet::addMemoryUsage(mc); - } - + void addMemoryUsage(MemoryConsumption& mc) const override; }; } // documentapi diff --git a/metrics/src/vespa/metrics/loadmetric.hpp b/metrics/src/vespa/metrics/loadmetric.hpp new file mode 100644 index 00000000000..68a0a4981a7 --- /dev/null +++ b/metrics/src/vespa/metrics/loadmetric.hpp @@ -0,0 +1,84 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "loadmetric.h" +#include "memoryconsumption.h" + +namespace metrics { + +template +LoadMetric::LoadMetric(const LoadTypeSet& loadTypes, const MetricType& metric, MetricSet* owner) + : MetricSet(metric.getName(), "", metric.getDescription(), owner), + _metrics(), + _sum("sum", "loadsum sum", "Sum of all load metrics", this) +{ + _metrics.resize(loadTypes.size()); + // Currently, we only set tags and description on the metric set + // itself, to cut down on size of output when downloading metrics, + // and since matching tags of parent is just as good as matching + // them specifically. + setTags(metric.getTags()); + Tags noTags; + for (uint32_t i=0; i(metric.clone(_ownerList, CLONE, 0, false))); + assert(copy.get()); + copy->setName(loadTypes[i].getName()); + copy->setTags(noTags); + _metrics[loadTypes[i].getId()] = copy; + registerMetric(*copy); + _sum.addMetricToSum(*copy); + } + trim(_ownerList); +} + +template +LoadMetric::LoadMetric(const LoadMetric& other, MetricSet* owner) + : MetricSet(other.getName(), "", other.getDescription(), owner), + _metrics(), + _sum("sum", "loadsum sum", "Sum of all load metrics", this) +{ + _metrics.resize(2 * other._metrics.size()); + setTags(other.getTags()); + Tags noTags; + for (const auto & metric : _metrics) { + MetricTypeLP copy(dynamic_cast(metric.second->clone(_ownerList, CLONE, 0, false))); + assert(copy.get()); + copy->setName(metric.second->getName()); + copy->setTags(noTags); + _metrics[metric.first] = copy; + registerMetric(*copy); + _sum.addMetricToSum(*copy); + } + trim(_ownerList); +} + +template +Metric* +LoadMetric::clone(std::vector& ownerList, + CopyType copyType, MetricSet* owner, + bool includeUnused) const +{ + if (copyType == INACTIVE) { + return MetricSet::clone(ownerList, INACTIVE, owner, includeUnused); + } + return new LoadMetric(*this, owner); +} + +template +void +LoadMetric::addMemoryUsage(MemoryConsumption& mc) const { + ++mc._loadMetricCount; + mc._loadMetricMeta += sizeof(Metric::LP) * _ownerList.size(); + for (const auto & unused : _metrics) { + (void) unused; + mc._loadMetricMeta += sizeof(uint32_t) + sizeof(MetricTypeLP); + } + _sum.addMemoryUsage(mc); + mc._loadMetricMeta += sizeof(LoadMetric) + - sizeof(MetricSet) + - sizeof(SumMetric); + MetricSet::addMemoryUsage(mc); +} + +} + diff --git a/metrics/src/vespa/metrics/memoryconsumption.cpp b/metrics/src/vespa/metrics/memoryconsumption.cpp new file mode 100644 index 00000000000..883a20e3f78 --- /dev/null +++ b/metrics/src/vespa/metrics/memoryconsumption.cpp @@ -0,0 +1,113 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "memoryconsumption.h" +#include + +namespace metrics { + +MemoryConsumption::MemoryConsumption() { + memset(&_consumerCount, 0, reinterpret_cast(&_seenStrings) - reinterpret_cast(&_consumerCount)); + _seenStrings.resize(1000); +} + +uint32_t +MemoryConsumption::getStringMemoryUsage(const std::string& s, uint32_t& uniqueCount) { + ++_totalStringCount; + const char* internalString = s.c_str(); + if (_seenStrings.find(internalString) != _seenStrings.end()) { + return 0; + } + ++uniqueCount; + _seenStrings.insert(internalString); + return s.capacity(); +} + +void +MemoryConsumption::addSnapShotUsage(const std::string& name, uint32_t usage) { + _snapShotUsage.push_back(std::pair(name, usage)); +} + +uint32_t +MemoryConsumption::getTotalMemoryUsage() const { + return _consumerId + _consumerMetricIds + _consumerMeta + + _snapshotSetMeta + _snapshotName + _snapshotMeta + _metricMeta + + _metricName + _metricPath + _metricDescription + + _metricTags + _metricSetMeta + _nameHash + _nameHashStrings + + _metricSetOrder + _countMetricValues + _countMetricMeta + + _valueMetricValues + _valueMetricMeta + _sumMetricMeta + + _sumMetricParentPath + _loadMetricMeta; +} + +void +MemoryConsumption::print(std::ostream& out, bool verbose, + const std::string& indent) const +{ + (void) verbose; + std::string newl = "\n" + indent + " "; + out << "MemoryConsumption(" + << newl << "Total memory used: " << bval(getTotalMemoryUsage()) + << newl << "Consumer count: " << _consumerCount + << newl << "Consumer ids: " << bval(_consumerId) + << newl << "Consumer metric count: " << _consumerMetricsInTotal + << newl << "Consumer metric ids: " << bval(_consumerMetricIds) + << newl << "Consumer meta: " << bval(_consumerMeta) + << newl << "Name hash: " << bval(_nameHash) + << newl << "Name hash strings: " << bval(_nameHashStrings) + << newl << "Snapshot set count: " << _snapshotSetCount + << newl << "Snapshot set meta: " << bval(_snapshotSetMeta) + << newl << "Snapshot count: " << _snapshotCount + << newl << "Snapshot name: " << bval(_snapshotName) + << newl << "Snapshot meta: " << bval(_snapshotMeta) + << newl << "Metric count: " << _metricCount + << newl << "Metric meta: " << bval(_metricMeta) + << newl << "Metric names: " << bval(_metricName) + << newl << "Metric paths: " << bval(_metricPath) + << newl << "Metric descriptions: " << bval(_metricDescription) + << newl << "Metric tag count: " << _metricTagCount + << newl << "Metric tags: " << bval(_metricTags) + << newl << "Metric set count: " << _metricSetCount + << newl << "Metric set meta: " << bval(_metricSetMeta) + << newl << "Metric set order list: " << bval(_metricSetOrder) + << newl << "Count metric count: " << _countMetricCount + << newl << "Count metric values: " << bval(_countMetricValues) + << newl << "Count metric meta: " << bval(_countMetricMeta) + << newl << "Value metric count: " << _valueMetricCount + << newl << "Value metric values: " << bval(_valueMetricValues) + << newl << "Value metric meta: " << bval(_valueMetricMeta) + << newl << "Sum metric count: " << _sumMetricCount + << newl << "Sum metric meta: " << bval(_sumMetricMeta) + << newl << "Sum metric parent path: " << bval(_sumMetricParentPath) + << newl << "Load metric count: " << _loadMetricCount + << newl << "Load metric meta: " << bval(_loadMetricMeta) + << newl << "Unique string count: " << _seenStrings.size() + << newl << "Strings stored: " << _totalStringCount + << newl << "Unique consumer ids: " << _consumerIdUnique + << newl << "Unique cons metric ids: " << _consumerMetricIdsUnique + << newl << "Unique snapshot names: " << _snapshotNameUnique + << newl << "Unique metric names: " << _metricNameUnique + << newl << "Unique metric paths: " << _metricPathUnique + << newl << "Unique metric descs: " << _metricDescriptionUnique + << newl << "Unique metric tags: " << _metricTagsUnique + << newl << "Unique sum metric paths: " << _sumMetricParentPathUnique + << newl << "Unique name hash strings: " << _nameHashUnique; + for (uint32_t i=0; i<_snapShotUsage.size(); ++i) { + out << newl << "Snapshot " << _snapShotUsage[i].first << ": " + << bval(_snapShotUsage[i].second); + } + out << "\n" << indent << ")"; +} + +std::string +MemoryConsumption::bval(uint32_t bytes) { + std::ostringstream ost; + if (bytes < 10 * 1024) { + ost << bytes << " B"; + } else if (bytes < 10 * 1024 * 1024) { + ost << (bytes / 1024) << " kB"; + } else { + ost << (bytes / (1024 * 1024)) << " MB"; + } + return ost.str(); +} + +} // metrics + diff --git a/metrics/src/vespa/metrics/memoryconsumption.h b/metrics/src/vespa/metrics/memoryconsumption.h index a96ad4d3e43..3cbd8ef1e36 100644 --- a/metrics/src/vespa/metrics/memoryconsumption.h +++ b/metrics/src/vespa/metrics/memoryconsumption.h @@ -83,109 +83,16 @@ struct MemoryConsumption : public vespalib::Printable { vespalib::hash_set _seenStrings; std::vector > _snapShotUsage; - MemoryConsumption() { - memset(&_consumerCount, 0, - reinterpret_cast(&_seenStrings) - - reinterpret_cast(&_consumerCount)); - _seenStrings.resize(1000); - } + MemoryConsumption(); /** Get memory usage of a string that is not included when doing sizeof */ - uint32_t getStringMemoryUsage(const std::string& s, uint32_t& uniqueCount) { - ++_totalStringCount; - const char* internalString = s.c_str(); - if (_seenStrings.find(internalString) != _seenStrings.end()) { - return 0; - } - ++uniqueCount; - _seenStrings.insert(internalString); - return s.capacity(); - } - - void addSnapShotUsage(const std::string& name, uint32_t usage) { - _snapShotUsage.push_back(std::pair(name, usage)); - } - - uint32_t getTotalMemoryUsage() const { - return _consumerId + _consumerMetricIds + _consumerMeta - + _snapshotSetMeta + _snapshotName + _snapshotMeta + _metricMeta - + _metricName + _metricPath + _metricDescription - + _metricTags + _metricSetMeta + _nameHash + _nameHashStrings - + _metricSetOrder + _countMetricValues + _countMetricMeta - + _valueMetricValues + _valueMetricMeta + _sumMetricMeta - + _sumMetricParentPath + _loadMetricMeta; - } - - virtual void print(std::ostream& out, bool verbose, - const std::string& indent) const - { - (void) verbose; - std::string newl = "\n" + indent + " "; - out << "MemoryConsumption(" - << newl << "Total memory used: " << bval(getTotalMemoryUsage()) - << newl << "Consumer count: " << _consumerCount - << newl << "Consumer ids: " << bval(_consumerId) - << newl << "Consumer metric count: " << _consumerMetricsInTotal - << newl << "Consumer metric ids: " << bval(_consumerMetricIds) - << newl << "Consumer meta: " << bval(_consumerMeta) - << newl << "Name hash: " << bval(_nameHash) - << newl << "Name hash strings: " << bval(_nameHashStrings) - << newl << "Snapshot set count: " << _snapshotSetCount - << newl << "Snapshot set meta: " << bval(_snapshotSetMeta) - << newl << "Snapshot count: " << _snapshotCount - << newl << "Snapshot name: " << bval(_snapshotName) - << newl << "Snapshot meta: " << bval(_snapshotMeta) - << newl << "Metric count: " << _metricCount - << newl << "Metric meta: " << bval(_metricMeta) - << newl << "Metric names: " << bval(_metricName) - << newl << "Metric paths: " << bval(_metricPath) - << newl << "Metric descriptions: " << bval(_metricDescription) - << newl << "Metric tag count: " << _metricTagCount - << newl << "Metric tags: " << bval(_metricTags) - << newl << "Metric set count: " << _metricSetCount - << newl << "Metric set meta: " << bval(_metricSetMeta) - << newl << "Metric set order list: " << bval(_metricSetOrder) - << newl << "Count metric count: " << _countMetricCount - << newl << "Count metric values: " << bval(_countMetricValues) - << newl << "Count metric meta: " << bval(_countMetricMeta) - << newl << "Value metric count: " << _valueMetricCount - << newl << "Value metric values: " << bval(_valueMetricValues) - << newl << "Value metric meta: " << bval(_valueMetricMeta) - << newl << "Sum metric count: " << _sumMetricCount - << newl << "Sum metric meta: " << bval(_sumMetricMeta) - << newl << "Sum metric parent path: " << bval(_sumMetricParentPath) - << newl << "Load metric count: " << _loadMetricCount - << newl << "Load metric meta: " << bval(_loadMetricMeta) - << newl << "Unique string count: " << _seenStrings.size() - << newl << "Strings stored: " << _totalStringCount - << newl << "Unique consumer ids: " << _consumerIdUnique - << newl << "Unique cons metric ids: " << _consumerMetricIdsUnique - << newl << "Unique snapshot names: " << _snapshotNameUnique - << newl << "Unique metric names: " << _metricNameUnique - << newl << "Unique metric paths: " << _metricPathUnique - << newl << "Unique metric descs: " << _metricDescriptionUnique - << newl << "Unique metric tags: " << _metricTagsUnique - << newl << "Unique sum metric paths: " << _sumMetricParentPathUnique - << newl << "Unique name hash strings: " << _nameHashUnique; - for (uint32_t i=0; i<_snapShotUsage.size(); ++i) { - out << newl << "Snapshot " << _snapShotUsage[i].first << ": " - << bval(_snapShotUsage[i].second); - } - out << "\n" << indent << ")"; - } - - static std::string bval(uint32_t bytes) { - std::ostringstream ost; - if (bytes < 10 * 1024) { - ost << bytes << " B"; - } else if (bytes < 10 * 1024 * 1024) { - ost << (bytes / 1024) << " kB"; - } else { - ost << (bytes / (1024 * 1024)) << " MB"; - } - return ost.str(); - } + uint32_t getStringMemoryUsage(const std::string& s, uint32_t& uniqueCount); + void addSnapShotUsage(const std::string& name, uint32_t usage); + uint32_t getTotalMemoryUsage() const; + virtual void print(std::ostream& out, bool verbose, const std::string& indent) const; + + static std::string bval(uint32_t bytes); }; } // metrics diff --git a/metrics/src/vespa/metrics/metric.cpp b/metrics/src/vespa/metrics/metric.cpp index f4ad47871e6..01ab46d1093 100644 --- a/metrics/src/vespa/metrics/metric.cpp +++ b/metrics/src/vespa/metrics/metric.cpp @@ -1,12 +1,13 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include -#include +#include "metric.h" -#include -#include +#include "countmetric.h" +#include "valuemetric.h" +#include "metricset.h" +#include "namehash.h" #include #include -#include #include #include diff --git a/metrics/src/vespa/metrics/metric.h b/metrics/src/vespa/metrics/metric.h index 7c42d187f30..40b267652fc 100644 --- a/metrics/src/vespa/metrics/metric.h +++ b/metrics/src/vespa/metrics/metric.h @@ -2,17 +2,9 @@ #pragma once #include -#include -#include -#include -#include -#include -#include #include #include -#include #include -#include namespace metrics { @@ -22,6 +14,8 @@ class Metric; class MetricSet; class MetricSnapshot; class XmlWriterMetricVisitor; +class MemoryConsumption; +class NameHash; template void trim(std::vector& v) { @@ -104,8 +98,7 @@ struct Tag Tag(vespalib::stringref k, vespalib::stringref v) : key(k), value(v) - { - } + { } }; class Metric : public vespalib::Printable diff --git a/metrics/src/vespa/metrics/metricset.cpp b/metrics/src/vespa/metrics/metricset.cpp index cbddccfa787..4fc925f0218 100644 --- a/metrics/src/vespa/metrics/metricset.cpp +++ b/metrics/src/vespa/metrics/metricset.cpp @@ -1,7 +1,8 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include -#include +#include "metricset.h" +#include "memoryconsumption.h" #include #include #include diff --git a/metrics/src/vespa/metrics/metricvalueset.cpp b/metrics/src/vespa/metrics/metricvalueset.cpp new file mode 100644 index 00000000000..bb243dfff36 --- /dev/null +++ b/metrics/src/vespa/metrics/metricvalueset.cpp @@ -0,0 +1,21 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "metricvalueset.hpp" +#include "valuemetricvalues.h" +#include "countmetricvalues.h" + +namespace metrics { + +std::string +MetricValueClass::toString(const std::string& id) { + std::ostringstream ost; + output(id, ost); + return ost.str(); +} + +template class MetricValueSet>; +template class MetricValueSet>; +template class MetricValueSet>; + +} // metrics + diff --git a/metrics/src/vespa/metrics/metricvalueset.h b/metrics/src/vespa/metrics/metricvalueset.h index 98bc6160833..e934a5cdb6f 100644 --- a/metrics/src/vespa/metrics/metricvalueset.h +++ b/metrics/src/vespa/metrics/metricvalueset.h @@ -27,7 +27,6 @@ */ #pragma once -#include #include #include #include @@ -36,18 +35,15 @@ namespace metrics { struct MetricValueClass { - typedef std::unique_ptr UP; + using UP = std::unique_ptr; + using stringref = vespalib::stringref; virtual ~MetricValueClass() {} - virtual double getDoubleValue(const vespalib::stringref & id) const = 0; - virtual uint64_t getLongValue(const vespalib::stringref & id) const = 0; + virtual double getDoubleValue(const stringref & id) const = 0; + virtual uint64_t getLongValue(const stringref & id) const = 0; virtual void output(const std::string& id, std::ostream&) const = 0; virtual void output(const std::string& id, vespalib::JsonStream&) const = 0; - std::string toString(const std::string& id) { - std::ostringstream ost; - output(id, ost); - return ost.str(); - } + std::string toString(const std::string& id); }; template @@ -63,42 +59,13 @@ class MetricValueSet { void validateCorrectValueSuperClass(const MetricValueClass&) {} public: - MetricValueSet(uint32_t copyCount = 3) - : _values(copyCount), - _activeValueIndex(0), - _flags(0) - { - } - - MetricValueSet(const MetricValueSet& other, uint32_t copyCount = 3) - : _values(copyCount), - _activeValueIndex(0), - _flags(other._flags.load(std::memory_order_relaxed)) - { - setValues(other.getValues()); - } - - MetricValueSet& operator=(const MetricValueSet& other) - { - setValues(other.getValues()); - return *this; - } + MetricValueSet(uint32_t copyCount = 3); + MetricValueSet(const MetricValueSet& other, uint32_t copyCount = 3); + MetricValueSet& operator=(const MetricValueSet& other); /** Get the current values. */ - 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; - } + ValueClass getValues() const; /** * Get the current values from the metric. This function should not be @@ -107,54 +74,19 @@ public: * In which case, redo getValues(), apply the update again, and call * setValues() again. */ - bool setValues(const ValueClass& values) { - validateCorrectValueSuperClass(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; - } - } + bool setValues(const ValueClass& values); /** * Retrieve and reset in a single operation, to minimize chance of * alteration in the process. */ - ValueClass getValuesAndReset() { - ValueClass result(getValues()); - setFlag(RESET); - return result; - } + ValueClass getValuesAndReset(); void reset() { setFlag(RESET); } - std::string toString() { - std::ostringstream ost; - ost << "MetricValueSet(reset=" << (isReset() ? "true" : "false") - << ", active " << _activeValueIndex; - ost << "\n empty: " << ValueClass().toString(); - for (uint32_t i=0; i<_values.size(); ++i) { - ost << "\n " << _values[i].toString(); - } - ost << "\n)"; - return ost.str(); - } + std::string toString(); uint32_t getMemoryUsageAllocatedInternally() const { return _values.capacity() * sizeof(ValueClass); diff --git a/metrics/src/vespa/metrics/metricvalueset.hpp b/metrics/src/vespa/metrics/metricvalueset.hpp new file mode 100644 index 00000000000..be62bab3f1e --- /dev/null +++ b/metrics/src/vespa/metrics/metricvalueset.hpp @@ -0,0 +1,97 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "metricvalueset.h" +#include + +namespace metrics { + +template +MetricValueSet::MetricValueSet(uint32_t copyCount) + : _values(copyCount), + _activeValueIndex(0), + _flags(0) +{ } + +template +MetricValueSet::MetricValueSet(const MetricValueSet& other, uint32_t copyCount) + : _values(copyCount), + _activeValueIndex(0), + _flags(other._flags.load(std::memory_order_relaxed)) +{ + setValues(other.getValues()); +} + +template +MetricValueSet & MetricValueSet::operator=(const MetricValueSet& other) +{ + setValues(other.getValues()); + return *this; +} + +template +ValueClass +MetricValueSet::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 +bool +MetricValueSet::setValues(const ValueClass& values) { + validateCorrectValueSuperClass(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 +ValueClass +MetricValueSet::getValuesAndReset() { + ValueClass result(getValues()); + setFlag(RESET); + return result; +} + +template +std::string +MetricValueSet::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 + diff --git a/metrics/src/vespa/metrics/summetric.cpp b/metrics/src/vespa/metrics/summetric.cpp new file mode 100644 index 00000000000..a1658bf0781 --- /dev/null +++ b/metrics/src/vespa/metrics/summetric.cpp @@ -0,0 +1,16 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "summetric.hpp" +#include "valuemetric.h" +#include "countmetric.h" + +namespace metrics { + +template class SumMetric>; +template class SumMetric>; +template class SumMetric>; +template class SumMetric>; +template class SumMetric>; + +} // metrics + diff --git a/metrics/src/vespa/metrics/summetric.h b/metrics/src/vespa/metrics/summetric.h index 6f1c92e5b4f..f40495a0334 100644 --- a/metrics/src/vespa/metrics/summetric.h +++ b/metrics/src/vespa/metrics/summetric.h @@ -13,13 +13,12 @@ #pragma once -#include -#include -#include -#include +#include "metric.h" namespace metrics { +class MetricSet; + template class SumMetric : public Metric { @@ -43,14 +42,10 @@ private: std::vector _metricsToSum; public: - SumMetric(const String& name, const String& tags, - const String& description, MetricSet* owner = 0); - SumMetric(const SumMetric& other, - std::vector& ownerList, MetricSet* owner = 0); + SumMetric(const String& name, const String& tags, const String& description, MetricSet* owner = 0); + SumMetric(const SumMetric& other, std::vector& ownerList, MetricSet* owner = 0); - virtual Metric* clone( - std::vector&, CopyType, MetricSet* owner, - bool includeUnused = false) const; + virtual Metric* clone( std::vector&, CopyType, MetricSet* owner, bool includeUnused = false) const; /** * If you want to support sums of collections of metrics that may @@ -65,16 +60,14 @@ public: virtual bool logEvent(const String& fullName) const; - virtual void print(std::ostream&, bool verbose, - const std::string& indent, uint64_t secondsPassed) const; + virtual void print(std::ostream&, bool verbose, const std::string& indent, uint64_t secondsPassed) const; virtual int64_t getLongValue(const stringref & id) const; virtual double getDoubleValue(const stringref & id) const; virtual void reset() {} - virtual bool visit(MetricVisitor& visitor, - bool tagAsAutoGenerated = false) const; + virtual bool visit(MetricVisitor& visitor, bool tagAsAutoGenerated = false) const; virtual bool used() const; @@ -82,341 +75,16 @@ public: virtual void printDebug(std::ostream&, const std::string& indent="") const; - virtual void addToPart(metrics::Metric&) const; - virtual void addToSnapshot(metrics::Metric&, - std::vector&) const; + virtual void addToPart(Metric&) const; + virtual void addToSnapshot(Metric&, std::vector&) const; private: friend class MetricManagerTest; std::pair, Metric::LP> generateSum() const; - virtual void addTo(metrics::Metric&, - std::vector* ownerList) const; + virtual void addTo(Metric&, std::vector* ownerList) const; bool isAddendType(const Metric* m) const; }; -template -bool -SumMetric::visit(MetricVisitor& visitor, - bool tagAsAutoGenerated) const -{ - (void) tagAsAutoGenerated; - if (_metricsToSum.empty()) return true; - std::pair, Metric::LP> sum(generateSum()); - return sum.second->visit(visitor, true); -} - -template -SumMetric::SumMetric(const String& name, const String& tags, - const String& description, MetricSet* owner) - : Metric(name, tags, description, owner), - _startValue(), - _metricsToSum() -{ -} - -template -SumMetric::SumMetric(const SumMetric& other, - std::vector& ownerList, - MetricSet* owner) - : Metric(other, owner), - _startValue(other._startValue), - _metricsToSum() -{ - (void) ownerList; - if (other._owner == 0) { - throw vespalib::IllegalStateException( - "Cannot copy a sum metric not registered in a metric set, as " - "we need to use parent to detect new metrics to point to.", - VESPA_STRLOC); - } - if (owner == 0) { - throw vespalib::IllegalStateException( - "Cannot copy a sum metric directly. One needs to at least " - "include metric set above it in order to include metrics " - "summed.", VESPA_STRLOC); - } - std::vector parentPath(other._owner->getPathVector()); - _metricsToSum.reserve(other._metricsToSum.size()); - for (typename std::vector::const_iterator it - = other._metricsToSum.begin(); - it != other._metricsToSum.end(); ++it) - { - std::vector addendPath((**it).getPathVector()); - MetricSet* newAddendParent = owner; - for (uint32_t i=parentPath.size(), n=addendPath.size() - 1; igetMetric(addendPath[i]); - if (child == 0) { - throw vespalib::IllegalStateException( - "Metric " + addendPath[i] + " in metric set " - + newAddendParent->getPath() + " was expected to " - "exist. This sounds like a bug.", VESPA_STRLOC); - } - if (!child->isMetricSet()) { - throw vespalib::IllegalStateException( - "Metric " + addendPath[i] + " in metric set " - + newAddendParent->getPath() + " was expected to be a " - "metric set. This sounds like a bug.", VESPA_STRLOC); - } - newAddendParent = static_cast(child); - } - Metric* child = newAddendParent->getMetric( - addendPath[addendPath.size() - 1]); - if (child == 0) { - throw vespalib::IllegalStateException( - "Metric " + addendPath[addendPath.size() - 1] + " in " - "metric set " + newAddendParent->getPath() + " was " - "expected to exist. This sounds like a bug.", VESPA_STRLOC); - } - AddendMetric* am(dynamic_cast(child)); - if (am == 0) { - throw vespalib::IllegalStateException( - "Metric " + child->getPath() + " is of wrong type for sum " - + other.getPath() + ". This sounds like a bug.", - VESPA_STRLOC); - } - _metricsToSum.push_back(am); - } -} - -template -Metric* -SumMetric::clone(std::vector& ownerList, - CopyType copyType, MetricSet* owner, - bool includeUnused) const -{ - (void) includeUnused; - if (_metricsToSum.empty() && _startValue.get() == 0) { - throw vespalib::IllegalStateException( - "Attempted to clone sum metric without any children or start value. " - "This is currently illegal, to avoid needing to be able to " - "construct a metric of appropriate type without having a " - "template. (Hard to know how to construct any metric.", - VESPA_STRLOC); - } - if (copyType == CLONE) { - return new SumMetric(*this, ownerList, owner); - } - // Else we're generating an inactive copy by evaluating sum - typename std::vector::const_iterator it( - _metricsToSum.begin()); - // Clone start value or first child and use as accumulator - // As the metric cloned will have wrong info, we have to wait to - // register it in parent until we have fixed that. - Metric *m = 0; - if (_startValue.get() != 0) { - m = _startValue->getStartValue().clone(ownerList, INACTIVE, 0, true); - } else { - m = (**it).clone(ownerList, INACTIVE, 0, true); - ++it; - } - m->setName(getName()); - m->setDescription(getDescription()); - m->setTags(getTags()); - if (owner != 0) owner->registerMetric(*m); - // Add the others to the metric cloned. - for (; it != _metricsToSum.end(); ++it) { - (**it).addToPart(*m); - } - return m; -} - -template -void -SumMetric::addToPart(metrics::Metric& m) const -{ - std::pair, Metric::LP> sum(generateSum()); - sum.second->addToPart(m); -} - -template -void -SumMetric::addToSnapshot( - metrics::Metric& m, std::vector& ownerList) const -{ - if (isAddendType(&m)) { - // If the type to add to is an addend metric, it is part of an inactive - // copy we need to add data to. - std::pair, Metric::LP> sum(generateSum()); - sum.second->addToSnapshot(m, ownerList); - } -} - -template -void -SumMetric::addTo(metrics::Metric& m, - std::vector* ownerList) const -{ - if (ownerList == 0) { - std::pair, Metric::LP> sum(generateSum()); - sum.second->addToPart(m); - } else { - if (isAddendType(&m)) { - // If the type to add to is an addend metric, it is part of an - // inactive copy we need to add data to. - std::pair, Metric::LP> sum(generateSum()); - sum.second->addToSnapshot(m, *ownerList); - } - } -} - -template -void -SumMetric::addMetricToSum(const AddendMetric& metric) -{ - if (_owner == 0) { - throw vespalib::IllegalStateException( - "Sum metric needs to be registered in a parent metric set " - "prior to adding metrics to sum.", VESPA_STRLOC); - } - std::vector sumParentPath(_owner->getPathVector()); - std::vector addedPath(metric.getPathVector()); - bool error = false; - if (addedPath.size() <= sumParentPath.size()) { - error = true; - } else for (uint32_t i=0; igetPath(), VESPA_STRLOC); - } - std::vector metrics(_metricsToSum.size() + 1); - for (uint32_t i=0; i<_metricsToSum.size(); ++i) { - metrics[i] = _metricsToSum[i]; - } - metrics[metrics.size() - 1] = &metric; - _metricsToSum.swap(metrics); - // Ensure we don't use extra memory - assert(_metricsToSum.capacity() == _metricsToSum.size()); -} - -template -void -SumMetric::removeMetricFromSum(const AddendMetric &metric) -{ - _metricsToSum.erase(remove(_metricsToSum.begin(), _metricsToSum.end(), - &metric)); -} - -template -std::pair, Metric::LP> -SumMetric::generateSum() const -{ - std::pair, Metric::LP> retVal; - Metric* m = clone(retVal.first, INACTIVE, 0, true); - m->setRegistered(_owner); - retVal.second.reset(m); - return retVal; -} - -template -int64_t -SumMetric::getLongValue(const stringref & id) const -{ - std::pair, Metric::LP> sum(generateSum()); - if (sum.second.get() == 0) return 0; - return sum.second->getLongValue(id); -} - -template -double -SumMetric::getDoubleValue(const stringref & id) const -{ - std::pair, Metric::LP> sum(generateSum()); - if (sum.second.get() == 0) return 0.0; - return sum.second->getDoubleValue(id); -} - -template -bool -SumMetric::logEvent(const String & fullName) const -{ - std::pair, Metric::LP> sum(generateSum()); - if (sum.second.get() == 0) return false; - return sum.second->logEvent(fullName); -} - -template -void -SumMetric::print(std::ostream& out, bool verbose, - const std::string& indent, - uint64_t secondsPassed) const -{ - std::pair, Metric::LP> sum(generateSum()); - if (sum.second.get() == 0) return; - sum.second->print(out, verbose, indent, secondsPassed); -} - -template -bool -SumMetric::used() const -{ - for(typename std::vector::const_iterator it( - _metricsToSum.begin()); it != _metricsToSum.end(); ++it) - { - if ((**it).used()) return true; - } - return false; -} - -template -void -SumMetric::addMemoryUsage(MemoryConsumption& mc) const -{ - ++mc._sumMetricCount; - mc._sumMetricMeta += sizeof(SumMetric) - sizeof(Metric) - + _metricsToSum.capacity() * sizeof(Metric*); - Metric::addMemoryUsage(mc); -} - -template -void -SumMetric::printDebug(std::ostream& out, - const std::string& indent) const -{ - out << "sum "; - Metric::printDebug(out, indent); - out << " {"; - for(typename std::vector::const_iterator it( - _metricsToSum.begin()); it != _metricsToSum.end(); ++it) - { - out << "\n" << indent << " "; - (**it).printDebug(out, indent + " "); - } - out << "}"; -} - -template -bool -SumMetric::isAddendType(const Metric* m) const -{ - // If metric to addend it a metric set, we can only check if target also is - // a metric set, as other type will be lost when going inactive. Is there a - // way to do this without using an actual instance? - if (_metricsToSum.empty() && _startValue.get() == 0) { - throw vespalib::IllegalStateException( - "Attempted to verify addend type for sum metric without any " - "children or start value.", VESPA_STRLOC); - } - const Metric* wantedType; - if (!_metricsToSum.empty()) { - wantedType = _metricsToSum[0]; - } else { - wantedType = &_startValue->getStartValue(); - } - if (wantedType->isMetricSet()) { - return (m->isMetricSet()); - } else { - return (dynamic_cast(m) != 0); - } -} - } // metrics diff --git a/metrics/src/vespa/metrics/summetric.hpp b/metrics/src/vespa/metrics/summetric.hpp new file mode 100644 index 00000000000..59739779901 --- /dev/null +++ b/metrics/src/vespa/metrics/summetric.hpp @@ -0,0 +1,335 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "summetric.h" +#include "metricset.h" +#include "memoryconsumption.h" +#include + +namespace metrics { + +template +bool +SumMetric::visit(MetricVisitor& visitor, + bool tagAsAutoGenerated) const +{ + (void) tagAsAutoGenerated; + if (_metricsToSum.empty()) return true; + std::pair, Metric::LP> sum(generateSum()); + return sum.second->visit(visitor, true); +} + +template +SumMetric::SumMetric(const String& name, const String& tags, + const String& description, MetricSet* owner) + : Metric(name, tags, description, owner), + _startValue(), + _metricsToSum() +{ +} + +template +SumMetric::SumMetric(const SumMetric& other, + std::vector& ownerList, + MetricSet* owner) + : Metric(other, owner), + _startValue(other._startValue), + _metricsToSum() +{ + (void) ownerList; + if (other._owner == 0) { + throw vespalib::IllegalStateException( + "Cannot copy a sum metric not registered in a metric set, as " + "we need to use parent to detect new metrics to point to.", + VESPA_STRLOC); + } + if (owner == 0) { + throw vespalib::IllegalStateException( + "Cannot copy a sum metric directly. One needs to at least " + "include metric set above it in order to include metrics " + "summed.", VESPA_STRLOC); + } + std::vector parentPath(other._owner->getPathVector()); + _metricsToSum.reserve(other._metricsToSum.size()); + for (typename std::vector::const_iterator it + = other._metricsToSum.begin(); + it != other._metricsToSum.end(); ++it) + { + std::vector addendPath((**it).getPathVector()); + MetricSet* newAddendParent = owner; + for (uint32_t i=parentPath.size(), n=addendPath.size() - 1; igetMetric(addendPath[i]); + if (child == 0) { + throw vespalib::IllegalStateException( + "Metric " + addendPath[i] + " in metric set " + + newAddendParent->getPath() + " was expected to " + "exist. This sounds like a bug.", VESPA_STRLOC); + } + if (!child->isMetricSet()) { + throw vespalib::IllegalStateException( + "Metric " + addendPath[i] + " in metric set " + + newAddendParent->getPath() + " was expected to be a " + "metric set. This sounds like a bug.", VESPA_STRLOC); + } + newAddendParent = static_cast(child); + } + Metric* child = newAddendParent->getMetric( + addendPath[addendPath.size() - 1]); + if (child == 0) { + throw vespalib::IllegalStateException( + "Metric " + addendPath[addendPath.size() - 1] + " in " + "metric set " + newAddendParent->getPath() + " was " + "expected to exist. This sounds like a bug.", VESPA_STRLOC); + } + AddendMetric* am(dynamic_cast(child)); + if (am == 0) { + throw vespalib::IllegalStateException( + "Metric " + child->getPath() + " is of wrong type for sum " + + other.getPath() + ". This sounds like a bug.", + VESPA_STRLOC); + } + _metricsToSum.push_back(am); + } +} + +template +Metric* +SumMetric::clone(std::vector& ownerList, + CopyType copyType, MetricSet* owner, + bool includeUnused) const +{ + (void) includeUnused; + if (_metricsToSum.empty() && _startValue.get() == 0) { + throw vespalib::IllegalStateException( + "Attempted to clone sum metric without any children or start value. " + "This is currently illegal, to avoid needing to be able to " + "construct a metric of appropriate type without having a " + "template. (Hard to know how to construct any metric.", + VESPA_STRLOC); + } + if (copyType == CLONE) { + return new SumMetric(*this, ownerList, owner); + } + // Else we're generating an inactive copy by evaluating sum + typename std::vector::const_iterator it( + _metricsToSum.begin()); + // Clone start value or first child and use as accumulator + // As the metric cloned will have wrong info, we have to wait to + // register it in parent until we have fixed that. + Metric *m = 0; + if (_startValue.get() != 0) { + m = _startValue->getStartValue().clone(ownerList, INACTIVE, 0, true); + } else { + m = (**it).clone(ownerList, INACTIVE, 0, true); + ++it; + } + m->setName(getName()); + m->setDescription(getDescription()); + m->setTags(getTags()); + if (owner != 0) owner->registerMetric(*m); + // Add the others to the metric cloned. + for (; it != _metricsToSum.end(); ++it) { + (**it).addToPart(*m); + } + return m; +} + +template +void +SumMetric::addToPart(Metric& m) const +{ + std::pair, Metric::LP> sum(generateSum()); + sum.second->addToPart(m); +} + +template +void +SumMetric::addToSnapshot( + Metric& m, std::vector& ownerList) const +{ + if (isAddendType(&m)) { + // If the type to add to is an addend metric, it is part of an inactive + // copy we need to add data to. + std::pair, Metric::LP> sum(generateSum()); + sum.second->addToSnapshot(m, ownerList); + } +} + +template +void +SumMetric::addTo(Metric& m, + std::vector* ownerList) const +{ + if (ownerList == 0) { + std::pair, Metric::LP> sum(generateSum()); + sum.second->addToPart(m); + } else { + if (isAddendType(&m)) { + // If the type to add to is an addend metric, it is part of an + // inactive copy we need to add data to. + std::pair, Metric::LP> sum(generateSum()); + sum.second->addToSnapshot(m, *ownerList); + } + } +} + +template +void +SumMetric::addMetricToSum(const AddendMetric& metric) +{ + if (_owner == 0) { + throw vespalib::IllegalStateException( + "Sum metric needs to be registered in a parent metric set " + "prior to adding metrics to sum.", VESPA_STRLOC); + } + std::vector sumParentPath(_owner->getPathVector()); + std::vector addedPath(metric.getPathVector()); + bool error = false; + if (addedPath.size() <= sumParentPath.size()) { + error = true; + } else for (uint32_t i=0; igetPath(), VESPA_STRLOC); + } + std::vector metrics(_metricsToSum.size() + 1); + for (uint32_t i=0; i<_metricsToSum.size(); ++i) { + metrics[i] = _metricsToSum[i]; + } + metrics[metrics.size() - 1] = &metric; + _metricsToSum.swap(metrics); + // Ensure we don't use extra memory + assert(_metricsToSum.capacity() == _metricsToSum.size()); +} + +template +void +SumMetric::removeMetricFromSum(const AddendMetric &metric) +{ + _metricsToSum.erase(remove(_metricsToSum.begin(), _metricsToSum.end(), + &metric)); +} + +template +std::pair, Metric::LP> +SumMetric::generateSum() const +{ + std::pair, Metric::LP> retVal; + Metric* m = clone(retVal.first, INACTIVE, 0, true); + m->setRegistered(_owner); + retVal.second.reset(m); + return retVal; +} + +template +int64_t +SumMetric::getLongValue(const stringref & id) const +{ + std::pair, Metric::LP> sum(generateSum()); + if (sum.second.get() == 0) return 0; + return sum.second->getLongValue(id); +} + +template +double +SumMetric::getDoubleValue(const stringref & id) const +{ + std::pair, Metric::LP> sum(generateSum()); + if (sum.second.get() == 0) return 0.0; + return sum.second->getDoubleValue(id); +} + +template +bool +SumMetric::logEvent(const String & fullName) const +{ + std::pair, Metric::LP> sum(generateSum()); + if (sum.second.get() == 0) return false; + return sum.second->logEvent(fullName); +} + +template +void +SumMetric::print(std::ostream& out, bool verbose, + const std::string& indent, + uint64_t secondsPassed) const +{ + std::pair, Metric::LP> sum(generateSum()); + if (sum.second.get() == 0) return; + sum.second->print(out, verbose, indent, secondsPassed); +} + +template +bool +SumMetric::used() const +{ + for(typename std::vector::const_iterator it( + _metricsToSum.begin()); it != _metricsToSum.end(); ++it) + { + if ((**it).used()) return true; + } + return false; +} + +template +void +SumMetric::addMemoryUsage(MemoryConsumption& mc) const +{ + ++mc._sumMetricCount; + mc._sumMetricMeta += sizeof(SumMetric) - sizeof(Metric) + + _metricsToSum.capacity() * sizeof(Metric*); + Metric::addMemoryUsage(mc); +} + +template +void +SumMetric::printDebug(std::ostream& out, + const std::string& indent) const +{ + out << "sum "; + Metric::printDebug(out, indent); + out << " {"; + for(typename std::vector::const_iterator it( + _metricsToSum.begin()); it != _metricsToSum.end(); ++it) + { + out << "\n" << indent << " "; + (**it).printDebug(out, indent + " "); + } + out << "}"; +} + +template +bool +SumMetric::isAddendType(const Metric* m) const +{ + // If metric to addend it a metric set, we can only check if target also is + // a metric set, as other type will be lost when going inactive. Is there a + // way to do this without using an actual instance? + if (_metricsToSum.empty() && _startValue.get() == 0) { + throw vespalib::IllegalStateException( + "Attempted to verify addend type for sum metric without any " + "children or start value.", VESPA_STRLOC); + } + const Metric* wantedType; + if (!_metricsToSum.empty()) { + wantedType = _metricsToSum[0]; + } else { + wantedType = &_startValue->getStartValue(); + } + if (wantedType->isMetricSet()) { + return (m->isMetricSet()); + } else { + return (dynamic_cast(m) != 0); + } +} + +} // metrics + diff --git a/metrics/src/vespa/metrics/textwriter.cpp b/metrics/src/vespa/metrics/textwriter.cpp index 0b5cb9a287b..259b8157d57 100644 --- a/metrics/src/vespa/metrics/textwriter.cpp +++ b/metrics/src/vespa/metrics/textwriter.cpp @@ -1,11 +1,11 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -#include - -#include -#include -#include -#include +#include "textwriter.h" +#include "countmetric.h" +#include "metricset.h" +#include "metricsnapshot.h" +#include "valuemetric.h" +#include namespace metrics { diff --git a/metrics/src/vespa/metrics/textwriter.h b/metrics/src/vespa/metrics/textwriter.h index dadeb70a7fc..88fc807fd2f 100644 --- a/metrics/src/vespa/metrics/textwriter.h +++ b/metrics/src/vespa/metrics/textwriter.h @@ -2,8 +2,8 @@ #pragma once +#include "metric.h" #include -#include namespace metrics { diff --git a/metrics/src/vespa/metrics/valuemetric.cpp b/metrics/src/vespa/metrics/valuemetric.cpp index 3da48885054..1b00bf8cbeb 100644 --- a/metrics/src/vespa/metrics/valuemetric.cpp +++ b/metrics/src/vespa/metrics/valuemetric.cpp @@ -1,9 +1,7 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include -#include -#include - +#include "valuemetric.hpp" #include LOG_SETUP(".metrics.metric.value"); @@ -46,4 +44,9 @@ AbstractValueMetric::logNonFiniteValueWarning() const } } +template class ValueMetric; +template class ValueMetric; +template class ValueMetric; +template class ValueMetric; + } // metrics diff --git a/metrics/src/vespa/metrics/valuemetric.h b/metrics/src/vespa/metrics/valuemetric.h index 9c9d750a1a8..1766c92e680 100644 --- a/metrics/src/vespa/metrics/valuemetric.h +++ b/metrics/src/vespa/metrics/valuemetric.h @@ -13,16 +13,8 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "valuemetricvalues.h" +#include "metric.h" namespace metrics { @@ -54,98 +46,10 @@ protected: }; template -class ValueMetric - : public AbstractValueMetric +class ValueMetric : public AbstractValueMetric { - typedef Metric::String String; // Redefine so template finds it easy - - struct Values : MetricValueClass { - uint32_t _count; - AvgVal _min, _max, _last; - TotVal _total; - - struct AtomicImpl { - std::atomic _count {0}; - std::atomic _min {std::numeric_limits::max()}; - std::atomic _max {std::numeric_limits::min()}; - std::atomic _last {0}; - std::atomic _total {0}; - }; - - Values() - : _count(0), - _min(std::numeric_limits::max()), - _max(std::numeric_limits::min()), - _last(0), - _total(0) - { - // numeric_limits min() returns smallest positive number - // for signed floating point types. Haven't found a way to - // get minimum negative value, so using -1 * positive for those. - if (std::numeric_limits::is_signed - && !std::numeric_limits::is_integer) - { - _max = -1 * std::numeric_limits::max(); - } - } - - void relaxedStoreInto(AtomicImpl& target) const noexcept { - target._count.store(_count, std::memory_order_relaxed); - target._min.store(_min, std::memory_order_relaxed); - target._max.store(_max, std::memory_order_relaxed); - target._last.store(_last, std::memory_order_relaxed); - target._total.store(_total, std::memory_order_relaxed); - } - - void relaxedLoadFrom(const AtomicImpl& source) noexcept { - _count = source._count.load(std::memory_order_relaxed); - _min = source._min.load(std::memory_order_relaxed); - _max = source._max.load(std::memory_order_relaxed); - _last = source._last.load(std::memory_order_relaxed); - _total = source._total.load(std::memory_order_relaxed); - } - - template - T getValue(const stringref & id) const { - if (id == "last") return static_cast(_last); - if (id == "count") return static_cast(_count); - if (id == "total") return static_cast(_total); - if (id == "min") return static_cast(_count > 0 ? _min : 0); - if (id == "max") return static_cast( _count > 0 ? _max : 0); - throw vespalib::IllegalArgumentException( - "No value " + vespalib::string(id) + " in value metric.", VESPA_STRLOC); - } - - double getDoubleValue(const stringref & id) const { - return getValue(id); - } - uint64_t getLongValue(const stringref & id) const { - return getValue(id); - } - void output(const std::string& id, std::ostream& out) const { - if (id == "last") { out << _last; return; } - if (id == "count") { out << _count; return; } - if (id == "total") { out << _total; return; } - if (id == "min") { out << (_count > 0 ? _min : 0); return; } - if (id == "max") { out << (_count > 0 ? _max : 0); return; } - throw vespalib::IllegalArgumentException( - "No value " + id + " in value metric.", VESPA_STRLOC); - } - void output(const std::string& id, vespalib::JsonStream& stream) const { - if (id == "last") { stream << _last; return; } - if (id == "count") { stream << _count; return; } - if (id == "total") { stream << _total; return; } - if (id == "min") { stream << (_count > 0 ? _min : 0); return; } - if (id == "max") { stream << (_count > 0 ? _max : 0); return; } - throw vespalib::IllegalArgumentException( - "No value " + id + " in value metric.", VESPA_STRLOC); - } - friend std::ostream & operator << (std::ostream & os, const Values & v) { - os << "count=" << v._count; - os << ", total=" << v._total; - return os; - } - }; + using String = Metric::String; // Redefine so template finds it easy + using Values = ValueMetricValues; MetricValueSet _values; @@ -251,282 +155,5 @@ typedef ValueMetric DoubleAverageMetric; typedef ValueMetric LongValueMetric; typedef ValueMetric LongAverageMetric; -template -ValueMetric::ValueMetric( - const String& name, const String& tags, - const String& description, MetricSet* owner) - : AbstractValueMetric(name, tags, description, owner), - _values() -{ - _values.setFlag(LOG_IF_UNSET); -} - -template -ValueMetric::ValueMetric( - const String& name, const Tags dimensions, - const String& description, MetricSet* owner) - : AbstractValueMetric(name, std::move(dimensions), description, owner), - _values() -{ - _values.setFlag(LOG_IF_UNSET); -} - -template -ValueMetric::ValueMetric( - const ValueMetric& other, - CopyType copyType, MetricSet* owner) - : AbstractValueMetric(other, owner), - _values(other._values, copyType == CLONE ? other._values.size() : 1) -{ -} - -template -void ValueMetric::inc(AvgVal incVal) -{ - if (!checkFinite(incVal, std::is_floating_point())) { - return; - } - Values values; - do { - values = _values.getValues(); - AvgVal val = values._last + incVal; - ++values._count; - values._total += val; - if (val < values._min) values._min = val; - if (val > values._max) values._max = val; - values._last = val; - } while (!_values.setValues(values)); -} - -template -void ValueMetric::dec(AvgVal decVal) -{ - if (!checkFinite(decVal, std::is_floating_point())) { - return; - } - Values values; - do { - values = _values.getValues(); - AvgVal val = values._last - decVal; - ++values._count; - values._total += val; - if (val < values._min) values._min = val; - if (val > values._max) values._max = val; - values._last = val; - } while (!_values.setValues(values)); -} - -template -void -ValueMetric::addToSnapshot( - Metric& other, std::vector&) const -{ - ValueMetric& o( - reinterpret_cast&>(other)); - if (_values.getValues()._count == 0) return; // Don't add if not set - o.add(_values.getValues(), false); -} - -template -void -ValueMetric::addToPart(Metric& other) const -{ - ValueMetric& o( - reinterpret_cast&>( - other)); - o.add(_values.getValues(), SumOnAdd); -} - -template -void -ValueMetric::add(const Values& values2, bool sumOnAdd) -{ - bool overflow; - Values values; - do { - values = _values.getValues(); - overflow = values._count > values._count + values2._count - || (values2._total >= 0 - ? values._total > values._total + values2._total - : values._total < values._total + values2._total); - if (values._count == 0) { - values = values2; - } else if (values2._count == 0) { - // Do nothing - } else if (sumOnAdd) { - double totalAverage - = static_cast(values._total) / values._count - + static_cast(values2._total) / values2._count; - values._count += values2._count; - values._total = static_cast(totalAverage * values._count); - values._last += values2._last; - _values.setFlag(SUMMED_AVERAGE); - } else { - values._count += values2._count; - values._total += values2._total; - values._last = values2._last; - } - if (values._min > values2._min) values._min = values2._min; - if (values._max < values2._max) values._max = values2._max; - } while (!_values.setValues(values)); - if (overflow) { - std::ostringstream ost; - ost << "ValueMetric " << getPath() << " overflowed. Resetting it. Old value = ("; - ost << values << "), Incoming = (" << values2 << ")"; - logWarning(ost.str().c_str()); - _values.reset(); - } -} - -template -void -ValueMetric::dec(const Values& values2) -{ - bool underflow; - Values values; - do { - values = _values.getValues(); - underflow = values._count < values._count - values2._count - || values._total < values._total - values2._total; - values._count -= values2._count; - values._total -= values2._total; - } while (!_values.setValues(values)); - if (underflow) { - _values.reset(); - std::ostringstream ost; - ost << "ValueMetric " << getPath() << " underflowed. Resetting it."; - logWarning(ost.str().c_str()); - } -} - -template -void ValueMetric::addValueWithCount( - AvgVal avg, TotVal tot, uint32_t count) -{ - if (!checkFinite(avg, std::is_floating_point())) { - return; - } - Values values; - do { - values = _values.getValues(); - values._count += count; - values._total += tot; - if (avg < values._min) values._min = avg; - if (avg > values._max) values._max = avg; - values._last = avg; - } while (!_values.setValues(values)); -} - -template -ValueMetric& -ValueMetric::operator+=( - const ValueMetric& other) -{ - add(other._values.getValues(), SumOnAdd); - return *this; -} - -template -double -ValueMetric::getAverage() const -{ - Values values(_values.getValues()); - if (values._count == 0) return 0; - return static_cast(values._total) / values._count; -} - -template -bool -ValueMetric::logEvent(const String& fullName) const -{ - Values values(_values.getValues()); - if (!logIfUnset() && !inUse(values)) return false; - sendLogEvent(fullName, SumOnAdd - ? static_cast(values._last) - : static_cast(values._total) / values._count); - return true; -} - -template -void -ValueMetric::print( - std::ostream& out, bool verbose, const std::string& indent, - uint64_t secondsPassed) const -{ - (void) indent; - (void) secondsPassed; - Values values(_values.getValues()); - if (!inUse(values) && !verbose) return; - out << this->_name << " average=" << (values._count == 0 - ? 0 : static_cast(values._total) / values._count) - << " last=" << values._last; - if (!summedAverage()) { - if (values._count > 0) { - out << " min=" << values._min << " max=" << values._max; - } - out << " count=" << values._count << " total=" << values._total; - } -} - -template -int64_t -ValueMetric::getLongValue(const stringref & id) const -{ - Values values(_values.getValues()); - if (id == "last" || (SumOnAdd && id == "value")) - return static_cast(values._last); - if (id == "average" || (!SumOnAdd && id == "value")) - return static_cast(getAverage()); - if (id == "count") return static_cast(values._count); - if (id == "total") return static_cast(values._total); - if (id == "min") return static_cast( - values._count > 0 ? values._min : 0); - if (id == "max") return static_cast( - values._count > 0 ? values._max : 0); - throw vespalib::IllegalArgumentException( - "No value " + id + " in average metric.", VESPA_STRLOC); -} - -template -double -ValueMetric::getDoubleValue(const stringref & id) const -{ - Values values(_values.getValues()); - if (id == "last" || (SumOnAdd && id == "value")) - return static_cast(values._last); - if (id == "average" || (!SumOnAdd && id == "value")) - return getAverage(); - if (id == "count") return static_cast(values._count); - if (id == "total") return static_cast(values._total); - if (id == "min") return static_cast( - values._count > 0 ? values._min : 0); - if (id == "max") return static_cast( - values._count > 0 ? values._max : 0); - throw vespalib::IllegalArgumentException( - "No value " + vespalib::string(id) + " in average metric.", VESPA_STRLOC); -} - -template -void -ValueMetric::addMemoryUsage( - MemoryConsumption& mc) const -{ - ++mc._valueMetricCount; - mc._valueMetricValues += _values.getMemoryUsageAllocatedInternally(); - mc._valueMetricMeta += sizeof(ValueMetric) - - sizeof(Metric); - Metric::addMemoryUsage(mc); -} - -template -void -ValueMetric::printDebug( - std::ostream& out, const std::string& indent) const -{ - Values values(_values.getValues()); - out << "value=" << values._last << " "; - Metric::printDebug(out, indent); -} - } // metrics diff --git a/metrics/src/vespa/metrics/valuemetric.hpp b/metrics/src/vespa/metrics/valuemetric.hpp new file mode 100644 index 00000000000..0a196ec420f --- /dev/null +++ b/metrics/src/vespa/metrics/valuemetric.hpp @@ -0,0 +1,289 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "valuemetric.h" +#include "memoryconsumption.h" +#include +#include + +namespace metrics { + +template +ValueMetric::ValueMetric( + const String& name, const String& tags, + const String& description, MetricSet* owner) + : AbstractValueMetric(name, tags, description, owner), + _values() +{ + _values.setFlag(LOG_IF_UNSET); +} + +template +ValueMetric::ValueMetric( + const String& name, const Tags dimensions, + const String& description, MetricSet* owner) + : AbstractValueMetric(name, std::move(dimensions), description, owner), + _values() +{ + _values.setFlag(LOG_IF_UNSET); +} + +template +ValueMetric::ValueMetric( + const ValueMetric& other, + CopyType copyType, MetricSet* owner) + : AbstractValueMetric(other, owner), + _values(other._values, copyType == CLONE ? other._values.size() : 1) +{ +} + +template +void ValueMetric::inc(AvgVal incVal) +{ + if (!checkFinite(incVal, std::is_floating_point())) { + return; + } + Values values; + do { + values = _values.getValues(); + AvgVal val = values._last + incVal; + ++values._count; + values._total += val; + if (val < values._min) values._min = val; + if (val > values._max) values._max = val; + values._last = val; + } while (!_values.setValues(values)); +} + +template +void ValueMetric::dec(AvgVal decVal) +{ + if (!checkFinite(decVal, std::is_floating_point())) { + return; + } + Values values; + do { + values = _values.getValues(); + AvgVal val = values._last - decVal; + ++values._count; + values._total += val; + if (val < values._min) values._min = val; + if (val > values._max) values._max = val; + values._last = val; + } while (!_values.setValues(values)); +} + +template +void +ValueMetric::addToSnapshot( + Metric& other, std::vector&) const +{ + ValueMetric& o( + reinterpret_cast&>(other)); + if (_values.getValues()._count == 0) return; // Don't add if not set + o.add(_values.getValues(), false); +} + +template +void +ValueMetric::addToPart(Metric& other) const +{ + ValueMetric& o( + reinterpret_cast&>( + other)); + o.add(_values.getValues(), SumOnAdd); +} + +template +void +ValueMetric::add(const Values& values2, bool sumOnAdd) +{ + bool overflow; + Values values; + do { + values = _values.getValues(); + overflow = values._count > values._count + values2._count + || (values2._total >= 0 + ? values._total > values._total + values2._total + : values._total < values._total + values2._total); + if (values._count == 0) { + values = values2; + } else if (values2._count == 0) { + // Do nothing + } else if (sumOnAdd) { + double totalAverage + = static_cast(values._total) / values._count + + static_cast(values2._total) / values2._count; + values._count += values2._count; + values._total = static_cast(totalAverage * values._count); + values._last += values2._last; + _values.setFlag(SUMMED_AVERAGE); + } else { + values._count += values2._count; + values._total += values2._total; + values._last = values2._last; + } + if (values._min > values2._min) values._min = values2._min; + if (values._max < values2._max) values._max = values2._max; + } while (!_values.setValues(values)); + if (overflow) { + std::ostringstream ost; + ost << "ValueMetric " << getPath() << " overflowed. Resetting it. Old value = ("; + ost << values << "), Incoming = (" << values2 << ")"; + logWarning(ost.str().c_str()); + _values.reset(); + } +} + +template +void +ValueMetric::dec(const Values& values2) +{ + bool underflow; + Values values; + do { + values = _values.getValues(); + underflow = values._count < values._count - values2._count + || values._total < values._total - values2._total; + values._count -= values2._count; + values._total -= values2._total; + } while (!_values.setValues(values)); + if (underflow) { + _values.reset(); + std::ostringstream ost; + ost << "ValueMetric " << getPath() << " underflowed. Resetting it."; + logWarning(ost.str().c_str()); + } +} + +template +void ValueMetric::addValueWithCount( + AvgVal avg, TotVal tot, uint32_t count) +{ + if (!checkFinite(avg, std::is_floating_point())) { + return; + } + Values values; + do { + values = _values.getValues(); + values._count += count; + values._total += tot; + if (avg < values._min) values._min = avg; + if (avg > values._max) values._max = avg; + values._last = avg; + } while (!_values.setValues(values)); +} + +template +ValueMetric& +ValueMetric::operator+=( + const ValueMetric& other) +{ + add(other._values.getValues(), SumOnAdd); + return *this; +} + +template +double +ValueMetric::getAverage() const +{ + Values values(_values.getValues()); + if (values._count == 0) return 0; + return static_cast(values._total) / values._count; +} + +template +bool +ValueMetric::logEvent(const String& fullName) const +{ + Values values(_values.getValues()); + if (!logIfUnset() && !inUse(values)) return false; + sendLogEvent(fullName, SumOnAdd + ? static_cast(values._last) + : static_cast(values._total) / values._count); + return true; +} + +template +void +ValueMetric::print( + std::ostream& out, bool verbose, const std::string& indent, + uint64_t secondsPassed) const +{ + (void) indent; + (void) secondsPassed; + Values values(_values.getValues()); + if (!inUse(values) && !verbose) return; + out << this->_name << " average=" << (values._count == 0 + ? 0 : static_cast(values._total) / values._count) + << " last=" << values._last; + if (!summedAverage()) { + if (values._count > 0) { + out << " min=" << values._min << " max=" << values._max; + } + out << " count=" << values._count << " total=" << values._total; + } +} + +template +int64_t +ValueMetric::getLongValue(const stringref & id) const +{ + Values values(_values.getValues()); + if (id == "last" || (SumOnAdd && id == "value")) + return static_cast(values._last); + if (id == "average" || (!SumOnAdd && id == "value")) + return static_cast(getAverage()); + if (id == "count") return static_cast(values._count); + if (id == "total") return static_cast(values._total); + if (id == "min") return static_cast( + values._count > 0 ? values._min : 0); + if (id == "max") return static_cast( + values._count > 0 ? values._max : 0); + throw vespalib::IllegalArgumentException( + "No value " + id + " in average metric.", VESPA_STRLOC); +} + +template +double +ValueMetric::getDoubleValue(const stringref & id) const +{ + Values values(_values.getValues()); + if (id == "last" || (SumOnAdd && id == "value")) + return static_cast(values._last); + if (id == "average" || (!SumOnAdd && id == "value")) + return getAverage(); + if (id == "count") return static_cast(values._count); + if (id == "total") return static_cast(values._total); + if (id == "min") return static_cast( + values._count > 0 ? values._min : 0); + if (id == "max") return static_cast( + values._count > 0 ? values._max : 0); + throw vespalib::IllegalArgumentException( + "No value " + vespalib::string(id) + " in average metric.", VESPA_STRLOC); +} + +template +void +ValueMetric::addMemoryUsage( + MemoryConsumption& mc) const +{ + ++mc._valueMetricCount; + mc._valueMetricValues += _values.getMemoryUsageAllocatedInternally(); + mc._valueMetricMeta += sizeof(ValueMetric) + - sizeof(Metric); + Metric::addMemoryUsage(mc); +} + +template +void +ValueMetric::printDebug( + std::ostream& out, const std::string& indent) const +{ + Values values(_values.getValues()); + out << "value=" << values._last << " "; + Metric::printDebug(out, indent); +} + +} // metrics + diff --git a/metrics/src/vespa/metrics/valuemetricvalues.cpp b/metrics/src/vespa/metrics/valuemetricvalues.cpp new file mode 100644 index 00000000000..bab66bfa346 --- /dev/null +++ b/metrics/src/vespa/metrics/valuemetricvalues.cpp @@ -0,0 +1,13 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "valuemetricvalues.hpp" + +namespace metrics { + +template class ValueMetricValues; +template std::ostream & operator << (std::ostream & os, const ValueMetricValues & v); + +template class ValueMetricValues; +template std::ostream & operator << (std::ostream & os, const ValueMetricValues & v); + +} // metrics + diff --git a/metrics/src/vespa/metrics/valuemetricvalues.h b/metrics/src/vespa/metrics/valuemetricvalues.h new file mode 100644 index 00000000000..347205ebe75 --- /dev/null +++ b/metrics/src/vespa/metrics/valuemetricvalues.h @@ -0,0 +1,49 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +/** + * @class metrics::ValueMetric + * @ingroup metrics + * + * @brief Creates a metric measuring any value. + * + * A value metric have the following properties: + * - Logs the average as a value event. (It is not strictly increasing) + * - When summing average metrics together, the sum becomes the average of + * all values added to both. + */ + +#pragma once + +#include "metricvalueset.h" + +namespace metrics { + +template +struct ValueMetricValues : MetricValueClass { + uint32_t _count; + AvgVal _min, _max, _last; + TotVal _total; + + struct AtomicImpl { + std::atomic _count {0}; + std::atomic _min {std::numeric_limits::max()}; + std::atomic _max {std::numeric_limits::min()}; + std::atomic _last {0}; + std::atomic _total {0}; + }; + + ValueMetricValues(); + void relaxedStoreInto(AtomicImpl& target) const noexcept; + void relaxedLoadFrom(const AtomicImpl& source) noexcept; + + template + T getValue(const stringref & id) const; + double getDoubleValue(const stringref & id) const override; + uint64_t getLongValue(const stringref & id) const override; + void output(const std::string& id, std::ostream& out) const override; + void output(const std::string& id, vespalib::JsonStream& stream) const override; + template + friend std::ostream & operator << (std::ostream & os, const ValueMetricValues & v); +}; + +} // metrics + diff --git a/metrics/src/vespa/metrics/valuemetricvalues.hpp b/metrics/src/vespa/metrics/valuemetricvalues.hpp new file mode 100644 index 00000000000..fe58a1f53c6 --- /dev/null +++ b/metrics/src/vespa/metrics/valuemetricvalues.hpp @@ -0,0 +1,93 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#pragma once + +#include "valuemetricvalues.h" +#include + +namespace metrics { + +using vespalib::IllegalArgumentException; + +template +ValueMetricValues::ValueMetricValues() + : _count(0), + _min(std::numeric_limits::max()), + _max(std::numeric_limits::min()), + _last(0), + _total(0) +{ + // numeric_limits min() returns smallest positive number + // for signed floating point types. Haven't found a way to + // get minimum negative value, so using -1 * positive for those. + if (std::numeric_limits::is_signed + && !std::numeric_limits::is_integer) + { + _max = -1 * std::numeric_limits::max(); + } +} + +template +void ValueMetricValues::relaxedStoreInto(AtomicImpl& target) const noexcept { + target._count.store(_count, std::memory_order_relaxed); + target._min.store(_min, std::memory_order_relaxed); + target._max.store(_max, std::memory_order_relaxed); + target._last.store(_last, std::memory_order_relaxed); + target._total.store(_total, std::memory_order_relaxed); +} + +template +void ValueMetricValues::relaxedLoadFrom(const AtomicImpl& source) noexcept { + _count = source._count.load(std::memory_order_relaxed); + _min = source._min.load(std::memory_order_relaxed); + _max = source._max.load(std::memory_order_relaxed); + _last = source._last.load(std::memory_order_relaxed); + _total = source._total.load(std::memory_order_relaxed); +} + +template +template +T ValueMetricValues::getValue(const stringref & id) const { + if (id == "last") return static_cast(_last); + if (id == "count") return static_cast(_count); + if (id == "total") return static_cast(_total); + if (id == "min") return static_cast(_count > 0 ? _min : 0); + if (id == "max") return static_cast( _count > 0 ? _max : 0); + throw IllegalArgumentException("No value " + vespalib::string(id) + " in value metric.", VESPA_STRLOC); +} + +template +double ValueMetricValues::getDoubleValue(const stringref & id) const { + return getValue(id); +} +template +uint64_t ValueMetricValues::getLongValue(const stringref & id) const { + return getValue(id); +} +template +void ValueMetricValues::output(const std::string& id, std::ostream& out) const { + if (id == "last") { out << _last; return; } + if (id == "count") { out << _count; return; } + if (id == "total") { out << _total; return; } + if (id == "min") { out << (_count > 0 ? _min : 0); return; } + if (id == "max") { out << (_count > 0 ? _max : 0); return; } + throw IllegalArgumentException("No value " + id + " in value metric.", VESPA_STRLOC); +} +template +void ValueMetricValues::output(const std::string& id, vespalib::JsonStream& stream) const { + if (id == "last") { stream << _last; return; } + if (id == "count") { stream << _count; return; } + if (id == "total") { stream << _total; return; } + if (id == "min") { stream << (_count > 0 ? _min : 0); return; } + if (id == "max") { stream << (_count > 0 ? _max : 0); return; } + throw IllegalArgumentException("No value " + id + " in value metric.", VESPA_STRLOC); +} + +template +std::ostream & operator << (std::ostream & os, const ValueMetricValues & v) { + os << "count=" << v._count; + os << ", total=" << v._total; + return os; +} + +} // metrics + -- cgit v1.2.3