summaryrefslogtreecommitdiffstats
path: root/metrics
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2016-11-20 03:04:28 +0100
committerHenning Baldersheim <balder@yahoo-inc.com>2016-11-20 03:12:50 +0100
commitc982c1c6cecd4818cf767a700bbc56387a80b32c (patch)
tree4a7d5e7290668697431e86e01d7b5dd14111de62 /metrics
parent81b959e4472035f9c44b3f6c8e54a6cc41ec4259 (diff)
Avoid including th ewhole world just to get some metrics.
Diffstat (limited to 'metrics')
-rw-r--r--metrics/src/tests/countmetrictest.cpp2
-rw-r--r--metrics/src/tests/loadmetrictest.cpp2
-rw-r--r--metrics/src/tests/metricmanagertest.cpp1
-rw-r--r--metrics/src/tests/snapshottest.cpp4
-rw-r--r--metrics/src/tests/stresstest.cpp4
-rw-r--r--metrics/src/tests/summetrictest.cpp3
-rw-r--r--metrics/src/tests/valuemetrictest.cpp1
-rw-r--r--metrics/src/vespa/metrics/CMakeLists.txt18
-rw-r--r--metrics/src/vespa/metrics/countmetric.cpp4
-rw-r--r--metrics/src/vespa/metrics/countmetric.h230
-rw-r--r--metrics/src/vespa/metrics/countmetric.hpp199
-rw-r--r--metrics/src/vespa/metrics/countmetricvalues.cpp9
-rw-r--r--metrics/src/vespa/metrics/countmetricvalues.h47
-rw-r--r--metrics/src/vespa/metrics/countmetricvalues.hpp37
-rw-r--r--metrics/src/vespa/metrics/loadmetric.cpp20
-rw-r--r--metrics/src/vespa/metrics/loadmetric.h104
-rw-r--r--metrics/src/vespa/metrics/loadmetric.hpp84
-rw-r--r--metrics/src/vespa/metrics/memoryconsumption.cpp113
-rw-r--r--metrics/src/vespa/metrics/memoryconsumption.h107
-rw-r--r--metrics/src/vespa/metrics/metric.cpp9
-rw-r--r--metrics/src/vespa/metrics/metric.h13
-rw-r--r--metrics/src/vespa/metrics/metricset.cpp3
-rw-r--r--metrics/src/vespa/metrics/metricvalueset.cpp21
-rw-r--r--metrics/src/vespa/metrics/metricvalueset.h92
-rw-r--r--metrics/src/vespa/metrics/metricvalueset.hpp97
-rw-r--r--metrics/src/vespa/metrics/summetric.cpp16
-rw-r--r--metrics/src/vespa/metrics/summetric.h354
-rw-r--r--metrics/src/vespa/metrics/summetric.hpp335
-rw-r--r--metrics/src/vespa/metrics/textwriter.cpp12
-rw-r--r--metrics/src/vespa/metrics/textwriter.h2
-rw-r--r--metrics/src/vespa/metrics/valuemetric.cpp9
-rw-r--r--metrics/src/vespa/metrics/valuemetric.h383
-rw-r--r--metrics/src/vespa/metrics/valuemetric.hpp289
-rw-r--r--metrics/src/vespa/metrics/valuemetricvalues.cpp13
-rw-r--r--metrics/src/vespa/metrics/valuemetricvalues.h49
-rw-r--r--metrics/src/vespa/metrics/valuemetricvalues.hpp93
36 files changed, 1526 insertions, 1253 deletions
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 <vespa/fastos/fastos.h>
#include <vespa/metrics/loadmetric.h>
#include <vespa/metrics/valuemetric.h>
+#include <vespa/metrics/loadmetric.hpp>
+#include <vespa/metrics/summetric.hpp>
#include <vespa/vdstestlib/cppunit/macros.h>
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 <vespa/fastos/fastos.h>
#include <vespa/log/log.h>
#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/summetric.hpp>
#include <vespa/metrics/xmlwriter.h>
#include <vespa/metrics/jsonwriter.h>
#include <vespa/metrics/textwriter.h>
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 <vespa/fastos/fastos.h>
-#include <vespa/log/log.h>
#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/loadmetric.hpp>
+#include <vespa/metrics/summetric.hpp>
#include <vespa/vdstestlib/cppunit/macros.h>
+#include <vespa/log/log.h>
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 <vespa/fastos/fastos.h>
-#include <vespa/log/log.h>
#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/loadmetric.hpp>
+#include <vespa/metrics/summetric.hpp>
#include <vespa/vdstestlib/cppunit/macros.h>
+#include <vespa/log/log.h>
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 <vespa/fastos/fastos.h>
-#include <vespa/vdstestlib/cppunit/macros.h>
#include <vespa/metrics/metrics.h>
+#include <vespa/metrics/summetric.hpp>
+#include <vespa/vdstestlib/cppunit/macros.h>
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 <vespa/fastos/fastos.h>
#include <vespa/vdstestlib/cppunit/macros.h>
#include <vespa/vespalib/objects/floatingpointtype.h>
+#include <vespa/vespalib/text/stringtokenizer.h>
#include <vespa/metrics/jsonwriter.h>
#include <vespa/metrics/metricmanager.h>
#include <vespa/metrics/valuemetric.h>
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 <vespa/fastos/fastos.h>
-#include <vespa/metrics/countmetric.h>
+#include "countmetric.hpp"
#include <vespa/log/log.h>
@@ -22,4 +22,6 @@ AbstractCountMetric::sendLogCountEvent(
EV_COUNT(name.c_str(), value);
}
+template class CountMetric<uint64_t, true>;
+
} // 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 <sstream>
#include <vespa/metrics/metric.h>
-#include <vespa/metrics/metricvalueset.h>
-#include <vespa/vespalib/util/jsonstream.h>
-#include <atomic>
+#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<typename T, bool SumOnAdd>
class CountMetric : public AbstractCountMetric
{
- struct Values : public MetricValueClass {
- T _value;
-
- struct AtomicImpl {
- std::atomic<T> _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<double>(_value); }
- uint64_t getLongValue(const stringref &) const
- { return static_cast<uint64_t>(_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<T>;
MetricValueSet<Values> _values;
enum Flag { LOG_IF_UNSET = 2 };
@@ -160,198 +125,9 @@ public:
virtual void addToPart(Metric&) const;
virtual void addToSnapshot(Metric&, std::vector<Metric::LP>&) const;
-
};
typedef CountMetric<uint64_t, true> LongCountMetric;
-template <typename T, bool SumOnAdd>
-CountMetric<T, SumOnAdd>::CountMetric(const String& name, const String& tags,
- const String& desc, MetricSet* owner)
- : AbstractCountMetric(name, tags, desc, owner),
- _values()
-{
- _values.setFlag(LOG_IF_UNSET);
-}
-
-template <typename T, bool SumOnAdd>
-CountMetric<T, SumOnAdd>::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 <typename T, bool SumOnAdd>
-CountMetric<T, SumOnAdd>::CountMetric(const CountMetric<T, SumOnAdd>& other,
- CopyType copyType, MetricSet* owner)
- : AbstractCountMetric(other, owner),
- _values(other._values, copyType == CLONE ? other._values.size() : 1)
-{
-}
-
-template <typename T, bool SumOnAdd>
-CountMetric<T, SumOnAdd>&
-CountMetric<T, SumOnAdd>::operator+=(const CountMetric<T, SumOnAdd>& 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 <typename T, bool SumOnAdd>
-CountMetric<T, SumOnAdd>&
-CountMetric<T, SumOnAdd>::operator-=(const CountMetric<T, SumOnAdd>& 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 <typename T, bool SumOnAdd>
-void
-CountMetric<T, SumOnAdd>::set(T value)
-{
- Values values;
- values._value = value;
- while (!_values.setValues(values)) {}
-}
-
-template <typename T, bool SumOnAdd>
-void
-CountMetric<T, SumOnAdd>::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 <typename T, bool SumOnAdd>
-void
-CountMetric<T, SumOnAdd>::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 <typename T, bool SumOnAdd>
-void
-CountMetric<T, SumOnAdd>::addToSnapshot(
- Metric& other, std::vector<Metric::LP>&) const
-{
- CountMetric<T, SumOnAdd>& o(
- reinterpret_cast<CountMetric<T, SumOnAdd>&>(other));
- o.inc(_values.getValues()._value);
-}
-
-template <typename T, bool SumOnAdd>
-void
-CountMetric<T, SumOnAdd>::addToPart(Metric& other) const
-{
- CountMetric<T, SumOnAdd>& o(
- reinterpret_cast<CountMetric<T, SumOnAdd>&>(other));
- if (SumOnAdd) {
- o.inc(_values.getValues()._value);
- } else {
- o.set((_values.getValues()._value + o._values.getValues()._value) / 2);
- }
-}
-
-template <typename T, bool SumOnAdd>
-bool
-CountMetric<T, SumOnAdd>::logEvent(const String& fullName) const
-{
- Values values(_values.getValues());
- if (!logIfUnset() && values._value == 0) return false;
- sendLogCountEvent(
- fullName, static_cast<uint64_t>(values._value));
- return true;
-}
-
-template <typename T, bool SumOnAdd>
-void
-CountMetric<T, SumOnAdd>::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 <typename T, bool SumOnAdd>
-void
-CountMetric<T, SumOnAdd>::addMemoryUsage(MemoryConsumption& mc) const
-{
- ++mc._countMetricCount;
- mc._countMetricValues += _values.getMemoryUsageAllocatedInternally();
- mc._countMetricMeta += sizeof(CountMetric<T, SumOnAdd>)
- - sizeof(Metric);
- Metric::addMemoryUsage(mc);
-}
-
-template <typename T, bool SumOnAdd>
-void
-CountMetric<T, SumOnAdd>::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 <sstream>
+
+namespace metrics {
+
+template <typename T, bool SumOnAdd>
+CountMetric<T, SumOnAdd>::CountMetric(const String& name, const String& tags,
+ const String& desc, MetricSet* owner)
+ : AbstractCountMetric(name, tags, desc, owner),
+ _values()
+{
+ _values.setFlag(LOG_IF_UNSET);
+}
+
+template <typename T, bool SumOnAdd>
+CountMetric<T, SumOnAdd>::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 <typename T, bool SumOnAdd>
+CountMetric<T, SumOnAdd>::CountMetric(const CountMetric<T, SumOnAdd>& other,
+ CopyType copyType, MetricSet* owner)
+ : AbstractCountMetric(other, owner),
+ _values(other._values, copyType == CLONE ? other._values.size() : 1)
+{
+}
+
+template <typename T, bool SumOnAdd>
+CountMetric<T, SumOnAdd>&
+CountMetric<T, SumOnAdd>::operator+=(const CountMetric<T, SumOnAdd>& 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 <typename T, bool SumOnAdd>
+CountMetric<T, SumOnAdd>&
+CountMetric<T, SumOnAdd>::operator-=(const CountMetric<T, SumOnAdd>& 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 <typename T, bool SumOnAdd>
+void
+CountMetric<T, SumOnAdd>::set(T value)
+{
+ Values values;
+ values._value = value;
+ while (!_values.setValues(values)) {}
+}
+
+template <typename T, bool SumOnAdd>
+void
+CountMetric<T, SumOnAdd>::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 <typename T, bool SumOnAdd>
+void
+CountMetric<T, SumOnAdd>::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 <typename T, bool SumOnAdd>
+void
+CountMetric<T, SumOnAdd>::addToSnapshot(
+ Metric& other, std::vector<Metric::LP>&) const
+{
+ CountMetric<T, SumOnAdd>& o(
+ reinterpret_cast<CountMetric<T, SumOnAdd>&>(other));
+ o.inc(_values.getValues()._value);
+}
+
+template <typename T, bool SumOnAdd>
+void
+CountMetric<T, SumOnAdd>::addToPart(Metric& other) const
+{
+ CountMetric<T, SumOnAdd>& o(
+ reinterpret_cast<CountMetric<T, SumOnAdd>&>(other));
+ if (SumOnAdd) {
+ o.inc(_values.getValues()._value);
+ } else {
+ o.set((_values.getValues()._value + o._values.getValues()._value) / 2);
+ }
+}
+
+template <typename T, bool SumOnAdd>
+bool
+CountMetric<T, SumOnAdd>::logEvent(const String& fullName) const
+{
+ Values values(_values.getValues());
+ if (!logIfUnset() && values._value == 0) return false;
+ sendLogCountEvent(
+ fullName, static_cast<uint64_t>(values._value));
+ return true;
+}
+
+template <typename T, bool SumOnAdd>
+void
+CountMetric<T, SumOnAdd>::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 <typename T, bool SumOnAdd>
+void
+CountMetric<T, SumOnAdd>::addMemoryUsage(MemoryConsumption& mc) const
+{
+ ++mc._countMetricCount;
+ mc._countMetricValues += _values.getMemoryUsageAllocatedInternally();
+ mc._countMetricMeta += sizeof(CountMetric<T, SumOnAdd>)
+ - sizeof(Metric);
+ Metric::addMemoryUsage(mc);
+}
+
+template <typename T, bool SumOnAdd>
+void
+CountMetric<T, SumOnAdd>::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<uint64_t>;
+
+} // 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 <vespa/metrics/metricvalueset.h>
+#include <atomic>
+
+namespace metrics {
+
+template <typename T>
+struct CountMetricValues : public MetricValueClass {
+ T _value;
+
+ struct AtomicImpl {
+ std::atomic<T> _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 <sstream>
+
+namespace metrics {
+
+template <typename T>
+std::string
+CountMetricValues<T>::toString() const {
+ std::ostringstream ost;
+ ost << _value;
+ return ost.str();
+}
+template <typename T>
+double
+CountMetricValues<T>::getDoubleValue(const stringref &) const {
+ return static_cast<double>(_value);
+}
+template <typename T>
+uint64_t
+CountMetricValues<T>::getLongValue(const stringref &) const {
+ return static_cast<uint64_t>(_value);
+}
+template <typename T>
+void
+CountMetricValues<T>::output(const std::string&, std::ostream& out) const {
+ out << _value;
+}
+template <typename T>
+void
+CountMetricValues<T>::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 <vespa/vespalib/util/stringfmt.h>
+
+namespace metrics {
+
+vespalib::string
+LoadType::toString() const {
+ return vespalib::make_string("%s(%u)", _name.c_str(), _id);
+}
+
+template class LoadMetric<ValueMetric<int64_t, int64_t, false>>;
+template class LoadMetric<ValueMetric<int64_t, int64_t, true>>;
+template class LoadMetric<ValueMetric<double, double, false>>;
+template class LoadMetric<ValueMetric<double, double, true>>;
+template class LoadMetric<CountMetric<uint64_t, true>>;
+
+}
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 <vespa/metrics/metricset.h>
-#include <vespa/metrics/summetric.h>
-#include <vespa/vespalib/util/linkedptr.h>
-#include <vespa/vespalib/util/stringfmt.h>
+#include "metricset.h"
+#include "summetric.h"
#include <vespa/vespalib/stllike/hash_map.h>
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<LoadType> LoadTypeSet;
template<typename MetricType>
-class LoadMetric : public metrics::MetricSet {
- std::vector<metrics::Metric::LP> _ownerList;
+class LoadMetric : public MetricSet {
+ std::vector<Metric::LP> _ownerList;
typedef vespalib::LinkedPtr<MetricType> MetricTypeLP;
vespalib::hash_map<uint32_t, MetricTypeLP> _metrics;
- metrics::SumMetric<MetricType> _sum;
+ SumMetric<MetricType> _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<loadTypes.size(); ++i) {
- MetricTypeLP copy(
- dynamic_cast<MetricType*>(
- 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<MetricType>& 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<uint32_t, MetricTypeLP>::const_iterator
- it = other._metrics.begin(); it != other._metrics.end(); ++it)
- {
- MetricTypeLP copy(dynamic_cast<MetricType*>(
- 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<Metric::LP>& ownerList,
- CopyType copyType, MetricSet* owner,
- bool includeUnused = false) const
- {
- if (copyType == INACTIVE) {
- return MetricSet::clone(ownerList, INACTIVE, owner, includeUnused);
- }
- return new LoadMetric<MetricType>(*this, owner);
- }
+ LoadMetric(const LoadMetric<MetricType>& other, MetricSet* owner);
+ Metric* clone(std::vector<Metric::LP>& 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<uint32_t, MetricTypeLP>::const_iterator
- it = _metrics.begin(); it != _metrics.end(); ++it)
- {
- mc._loadMetricMeta += sizeof(uint32_t) + sizeof(MetricTypeLP);
- }
- _sum.addMemoryUsage(mc);
- mc._loadMetricMeta += sizeof(LoadMetric<MetricType>)
- - sizeof(metrics::MetricSet)
- - sizeof(metrics::SumMetric<MetricType>);
- 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<typename MetricType>
+LoadMetric<MetricType>::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<loadTypes.size(); ++i) {
+ MetricTypeLP copy(dynamic_cast<MetricType*>(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<typename MetricType>
+LoadMetric<MetricType>::LoadMetric(const LoadMetric<MetricType>& 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<MetricType*>(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<typename MetricType>
+Metric*
+LoadMetric<MetricType>::clone(std::vector<Metric::LP>& ownerList,
+ CopyType copyType, MetricSet* owner,
+ bool includeUnused) const
+{
+ if (copyType == INACTIVE) {
+ return MetricSet::clone(ownerList, INACTIVE, owner, includeUnused);
+ }
+ return new LoadMetric<MetricType>(*this, owner);
+}
+
+template<typename MetricType>
+void
+LoadMetric<MetricType>::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<MetricType>)
+ - sizeof(MetricSet)
+ - sizeof(SumMetric<MetricType>);
+ 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 <sstream>
+
+namespace metrics {
+
+MemoryConsumption::MemoryConsumption() {
+ memset(&_consumerCount, 0, reinterpret_cast<size_t>(&_seenStrings) - reinterpret_cast<size_t>(&_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<std::string, uint32_t>(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<const void*> _seenStrings;
std::vector<std::pair<std::string, uint32_t> > _snapShotUsage;
- MemoryConsumption() {
- memset(&_consumerCount, 0,
- reinterpret_cast<size_t>(&_seenStrings)
- - reinterpret_cast<size_t>(&_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<std::string, uint32_t>(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 <vespa/fastos/fastos.h>
-#include <vespa/metrics/metric.h>
+#include "metric.h"
-#include <vespa/metrics/countmetric.h>
-#include <vespa/metrics/valuemetric.h>
+#include "countmetric.h"
+#include "valuemetric.h"
+#include "metricset.h"
+#include "namehash.h"
#include <vespa/vespalib/text/stringtokenizer.h>
#include <vespa/vespalib/util/exceptions.h>
-#include <vespa/metrics/metricset.h>
#include <algorithm>
#include <iterator>
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 <vespa/vespalib/util/printable.h>
-#include <map>
-#include <vespa/metrics/config-metricsmanager.h>
-#include <vespa/metrics/memoryconsumption.h>
-#include <vespa/metrics/namehash.h>
-#include <string>
-#include <vespa/vespalib/objects/cloneable.h>
#include <vespa/vespalib/stllike/string.h>
#include <vespa/vespalib/util/linkedptr.h>
-#include <vespa/vespalib/util/jsonwriter.h>
#include <vespa/vespalib/util/regexp.h>
-#include <vespa/vespalib/text/stringtokenizer.h>
namespace metrics {
@@ -22,6 +14,8 @@ class Metric;
class MetricSet;
class MetricSnapshot;
class XmlWriterMetricVisitor;
+class MemoryConsumption;
+class NameHash;
template<typename T>
void trim(std::vector<T>& 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 <vespa/fastos/fastos.h>
-#include <vespa/metrics/metricset.h>
+#include "metricset.h"
+#include "memoryconsumption.h"
#include <vespa/vespalib/stllike/hash_map.h>
#include <vespa/vespalib/util/exceptions.h>
#include <list>
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<CountMetricValues<uint64_t>>;
+template class MetricValueSet<ValueMetricValues<int64_t, int64_t>>;
+template class MetricValueSet<ValueMetricValues<double, double>>;
+
+} // 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 <sstream>
#include <vector>
#include <atomic>
#include <vespa/vespalib/stllike/string.h>
@@ -36,18 +35,15 @@
namespace metrics {
struct MetricValueClass {
- typedef std::unique_ptr<MetricValueClass> UP;
+ using UP = std::unique_ptr<MetricValueClass>;
+ 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<typename ValueClass>
@@ -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 <sstream>
+
+namespace metrics {
+
+template<typename ValueClass>
+MetricValueSet<ValueClass>::MetricValueSet(uint32_t copyCount)
+ : _values(copyCount),
+ _activeValueIndex(0),
+ _flags(0)
+{ }
+
+template<typename ValueClass>
+MetricValueSet<ValueClass>::MetricValueSet(const MetricValueSet& other, uint32_t copyCount)
+ : _values(copyCount),
+ _activeValueIndex(0),
+ _flags(other._flags.load(std::memory_order_relaxed))
+{
+ setValues(other.getValues());
+}
+
+template<typename ValueClass>
+MetricValueSet<ValueClass> & MetricValueSet<ValueClass>::operator=(const MetricValueSet& other)
+{
+ setValues(other.getValues());
+ return *this;
+}
+
+template<typename ValueClass>
+ValueClass
+MetricValueSet<ValueClass>::getValues() const {
+ ValueClass v{};
+ if (!isReset()) {
+ // Must load with acquire to match release store in setValues.
+ // Note that despite being atomic on _individual fields_, this
+ // does not guarantee reading a consistent snapshot _across_
+ // fields for any given metric.
+ const size_t readIndex(_activeValueIndex.load(std::memory_order_acquire));
+ v.relaxedLoadFrom(_values[readIndex]);
+ }
+ return v;
+}
+
+template<typename ValueClass>
+bool
+MetricValueSet<ValueClass>::setValues(const ValueClass& values) {
+ 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<typename ValueClass>
+ValueClass
+MetricValueSet<ValueClass>::getValuesAndReset() {
+ ValueClass result(getValues());
+ setFlag(RESET);
+ return result;
+}
+
+template<typename ValueClass>
+std::string
+MetricValueSet<ValueClass>::toString() {
+ std::ostringstream ost;
+ ost << "MetricValueSet(reset=" << (isReset() ? "true" : "false")
+ << ", active " << _activeValueIndex;
+#if 0
+ ost << "\n empty: " << ValueClass().toString("unknown");
+ for (uint32_t i=0; i<_values.size(); ++i) {
+ ost << "\n " << _values[i].toString("unknown");
+ }
+#endif
+ ost << "\n)";
+ return ost.str();
+}
+
+} // metrics
+
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<ValueMetric<int64_t, int64_t, false>>;
+template class SumMetric<ValueMetric<int64_t, int64_t, true>>;
+template class SumMetric<ValueMetric<double, double, false>>;
+template class SumMetric<ValueMetric<double, double, true>>;
+template class SumMetric<CountMetric<uint64_t, true>>;
+
+} // 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 <vespa/vespalib/util/sync.h>
-#include <vespa/vespalib/util/exceptions.h>
-#include <vespa/metrics/metric.h>
-#include <vespa/metrics/metricset.h>
+#include "metric.h"
namespace metrics {
+class MetricSet;
+
template<typename AddendMetric>
class SumMetric : public Metric
{
@@ -43,14 +42,10 @@ private:
std::vector<const AddendMetric*> _metricsToSum;
public:
- SumMetric(const String& name, const String& tags,
- const String& description, MetricSet* owner = 0);
- SumMetric(const SumMetric<AddendMetric>& other,
- std::vector<Metric::LP>& ownerList, MetricSet* owner = 0);
+ SumMetric(const String& name, const String& tags, const String& description, MetricSet* owner = 0);
+ SumMetric(const SumMetric<AddendMetric>& other, std::vector<Metric::LP>& ownerList, MetricSet* owner = 0);
- virtual Metric* clone(
- std::vector<Metric::LP>&, CopyType, MetricSet* owner,
- bool includeUnused = false) const;
+ virtual Metric* clone( std::vector<Metric::LP>&, 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<Metric::LP>&) const;
+ virtual void addToPart(Metric&) const;
+ virtual void addToSnapshot(Metric&, std::vector<Metric::LP>&) const;
private:
friend class MetricManagerTest;
std::pair<std::vector<Metric::LP>, Metric::LP> generateSum() const;
- virtual void addTo(metrics::Metric&,
- std::vector<Metric::LP>* ownerList) const;
+ virtual void addTo(Metric&, std::vector<Metric::LP>* ownerList) const;
bool isAddendType(const Metric* m) const;
};
-template<typename AddendMetric>
-bool
-SumMetric<AddendMetric>::visit(MetricVisitor& visitor,
- bool tagAsAutoGenerated) const
-{
- (void) tagAsAutoGenerated;
- if (_metricsToSum.empty()) return true;
- std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
- return sum.second->visit(visitor, true);
-}
-
-template<typename AddendMetric>
-SumMetric<AddendMetric>::SumMetric(const String& name, const String& tags,
- const String& description, MetricSet* owner)
- : Metric(name, tags, description, owner),
- _startValue(),
- _metricsToSum()
-{
-}
-
-template<typename AddendMetric>
-SumMetric<AddendMetric>::SumMetric(const SumMetric<AddendMetric>& other,
- std::vector<Metric::LP>& 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<String> parentPath(other._owner->getPathVector());
- _metricsToSum.reserve(other._metricsToSum.size());
- for (typename std::vector<const AddendMetric*>::const_iterator it
- = other._metricsToSum.begin();
- it != other._metricsToSum.end(); ++it)
- {
- std::vector<String> addendPath((**it).getPathVector());
- MetricSet* newAddendParent = owner;
- for (uint32_t i=parentPath.size(), n=addendPath.size() - 1; i<n; ++i) {
- Metric* child = newAddendParent->getMetric(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<MetricSet*>(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<AddendMetric*>(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<typename AddendMetric>
-Metric*
-SumMetric<AddendMetric>::clone(std::vector<Metric::LP>& 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<AddendMetric>(*this, ownerList, owner);
- }
- // Else we're generating an inactive copy by evaluating sum
- typename std::vector<const AddendMetric*>::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<typename AddendMetric>
-void
-SumMetric<AddendMetric>::addToPart(metrics::Metric& m) const
-{
- std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
- sum.second->addToPart(m);
-}
-
-template<typename AddendMetric>
-void
-SumMetric<AddendMetric>::addToSnapshot(
- metrics::Metric& m, std::vector<Metric::LP>& 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<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
- sum.second->addToSnapshot(m, ownerList);
- }
-}
-
-template<typename AddendMetric>
-void
-SumMetric<AddendMetric>::addTo(metrics::Metric& m,
- std::vector<Metric::LP>* ownerList) const
-{
- if (ownerList == 0) {
- std::pair<std::vector<Metric::LP>, 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<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
- sum.second->addToSnapshot(m, *ownerList);
- }
- }
-}
-
-template<typename AddendMetric>
-void
-SumMetric<AddendMetric>::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<String> sumParentPath(_owner->getPathVector());
- std::vector<String> addedPath(metric.getPathVector());
- bool error = false;
- if (addedPath.size() <= sumParentPath.size()) {
- error = true;
- } else for (uint32_t i=0; i<sumParentPath.size(); ++i) {
- if (sumParentPath[i] != addedPath[i]) {
- error = true;
- break;
- }
- }
- if (error) {
- throw vespalib::IllegalStateException(
- "Metric added to sum is required to be a child of the sum's "
- "direct parent metric set. (Need not be a direct child) "
- "Metric set " + metric.getPath() + " is not a child of "
- + _owner->getPath(), VESPA_STRLOC);
- }
- std::vector<const AddendMetric*> 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<typename AddendMetric>
-void
-SumMetric<AddendMetric>::removeMetricFromSum(const AddendMetric &metric)
-{
- _metricsToSum.erase(remove(_metricsToSum.begin(), _metricsToSum.end(),
- &metric));
-}
-
-template<typename AddendMetric>
-std::pair<std::vector<Metric::LP>, Metric::LP>
-SumMetric<AddendMetric>::generateSum() const
-{
- std::pair<std::vector<Metric::LP>, Metric::LP> retVal;
- Metric* m = clone(retVal.first, INACTIVE, 0, true);
- m->setRegistered(_owner);
- retVal.second.reset(m);
- return retVal;
-}
-
-template<typename AddendMetric>
-int64_t
-SumMetric<AddendMetric>::getLongValue(const stringref & id) const
-{
- std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
- if (sum.second.get() == 0) return 0;
- return sum.second->getLongValue(id);
-}
-
-template<typename AddendMetric>
-double
-SumMetric<AddendMetric>::getDoubleValue(const stringref & id) const
-{
- std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
- if (sum.second.get() == 0) return 0.0;
- return sum.second->getDoubleValue(id);
-}
-
-template<typename AddendMetric>
-bool
-SumMetric<AddendMetric>::logEvent(const String & fullName) const
-{
- std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
- if (sum.second.get() == 0) return false;
- return sum.second->logEvent(fullName);
-}
-
-template<typename AddendMetric>
-void
-SumMetric<AddendMetric>::print(std::ostream& out, bool verbose,
- const std::string& indent,
- uint64_t secondsPassed) const
-{
- std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
- if (sum.second.get() == 0) return;
- sum.second->print(out, verbose, indent, secondsPassed);
-}
-
-template<typename AddendMetric>
-bool
-SumMetric<AddendMetric>::used() const
-{
- for(typename std::vector<const AddendMetric*>::const_iterator it(
- _metricsToSum.begin()); it != _metricsToSum.end(); ++it)
- {
- if ((**it).used()) return true;
- }
- return false;
-}
-
-template<typename AddendMetric>
-void
-SumMetric<AddendMetric>::addMemoryUsage(MemoryConsumption& mc) const
-{
- ++mc._sumMetricCount;
- mc._sumMetricMeta += sizeof(SumMetric<AddendMetric>) - sizeof(Metric)
- + _metricsToSum.capacity() * sizeof(Metric*);
- Metric::addMemoryUsage(mc);
-}
-
-template<typename AddendMetric>
-void
-SumMetric<AddendMetric>::printDebug(std::ostream& out,
- const std::string& indent) const
-{
- out << "sum ";
- Metric::printDebug(out, indent);
- out << " {";
- for(typename std::vector<const AddendMetric*>::const_iterator it(
- _metricsToSum.begin()); it != _metricsToSum.end(); ++it)
- {
- out << "\n" << indent << " ";
- (**it).printDebug(out, indent + " ");
- }
- out << "}";
-}
-
-template<typename AddendMetric>
-bool
-SumMetric<AddendMetric>::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<const AddendMetric*>(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 <vespa/vespalib/util/exceptions.h>
+
+namespace metrics {
+
+template<typename AddendMetric>
+bool
+SumMetric<AddendMetric>::visit(MetricVisitor& visitor,
+ bool tagAsAutoGenerated) const
+{
+ (void) tagAsAutoGenerated;
+ if (_metricsToSum.empty()) return true;
+ std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
+ return sum.second->visit(visitor, true);
+}
+
+template<typename AddendMetric>
+SumMetric<AddendMetric>::SumMetric(const String& name, const String& tags,
+ const String& description, MetricSet* owner)
+ : Metric(name, tags, description, owner),
+ _startValue(),
+ _metricsToSum()
+{
+}
+
+template<typename AddendMetric>
+SumMetric<AddendMetric>::SumMetric(const SumMetric<AddendMetric>& other,
+ std::vector<Metric::LP>& 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<String> parentPath(other._owner->getPathVector());
+ _metricsToSum.reserve(other._metricsToSum.size());
+ for (typename std::vector<const AddendMetric*>::const_iterator it
+ = other._metricsToSum.begin();
+ it != other._metricsToSum.end(); ++it)
+ {
+ std::vector<String> addendPath((**it).getPathVector());
+ MetricSet* newAddendParent = owner;
+ for (uint32_t i=parentPath.size(), n=addendPath.size() - 1; i<n; ++i) {
+ Metric* child = newAddendParent->getMetric(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<MetricSet*>(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<AddendMetric*>(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<typename AddendMetric>
+Metric*
+SumMetric<AddendMetric>::clone(std::vector<Metric::LP>& 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<AddendMetric>(*this, ownerList, owner);
+ }
+ // Else we're generating an inactive copy by evaluating sum
+ typename std::vector<const AddendMetric*>::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<typename AddendMetric>
+void
+SumMetric<AddendMetric>::addToPart(Metric& m) const
+{
+ std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
+ sum.second->addToPart(m);
+}
+
+template<typename AddendMetric>
+void
+SumMetric<AddendMetric>::addToSnapshot(
+ Metric& m, std::vector<Metric::LP>& 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<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
+ sum.second->addToSnapshot(m, ownerList);
+ }
+}
+
+template<typename AddendMetric>
+void
+SumMetric<AddendMetric>::addTo(Metric& m,
+ std::vector<Metric::LP>* ownerList) const
+{
+ if (ownerList == 0) {
+ std::pair<std::vector<Metric::LP>, 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<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
+ sum.second->addToSnapshot(m, *ownerList);
+ }
+ }
+}
+
+template<typename AddendMetric>
+void
+SumMetric<AddendMetric>::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<String> sumParentPath(_owner->getPathVector());
+ std::vector<String> addedPath(metric.getPathVector());
+ bool error = false;
+ if (addedPath.size() <= sumParentPath.size()) {
+ error = true;
+ } else for (uint32_t i=0; i<sumParentPath.size(); ++i) {
+ if (sumParentPath[i] != addedPath[i]) {
+ error = true;
+ break;
+ }
+ }
+ if (error) {
+ throw vespalib::IllegalStateException(
+ "Metric added to sum is required to be a child of the sum's "
+ "direct parent metric set. (Need not be a direct child) "
+ "Metric set " + metric.getPath() + " is not a child of "
+ + _owner->getPath(), VESPA_STRLOC);
+ }
+ std::vector<const AddendMetric*> 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<typename AddendMetric>
+void
+SumMetric<AddendMetric>::removeMetricFromSum(const AddendMetric &metric)
+{
+ _metricsToSum.erase(remove(_metricsToSum.begin(), _metricsToSum.end(),
+ &metric));
+}
+
+template<typename AddendMetric>
+std::pair<std::vector<Metric::LP>, Metric::LP>
+SumMetric<AddendMetric>::generateSum() const
+{
+ std::pair<std::vector<Metric::LP>, Metric::LP> retVal;
+ Metric* m = clone(retVal.first, INACTIVE, 0, true);
+ m->setRegistered(_owner);
+ retVal.second.reset(m);
+ return retVal;
+}
+
+template<typename AddendMetric>
+int64_t
+SumMetric<AddendMetric>::getLongValue(const stringref & id) const
+{
+ std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
+ if (sum.second.get() == 0) return 0;
+ return sum.second->getLongValue(id);
+}
+
+template<typename AddendMetric>
+double
+SumMetric<AddendMetric>::getDoubleValue(const stringref & id) const
+{
+ std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
+ if (sum.second.get() == 0) return 0.0;
+ return sum.second->getDoubleValue(id);
+}
+
+template<typename AddendMetric>
+bool
+SumMetric<AddendMetric>::logEvent(const String & fullName) const
+{
+ std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
+ if (sum.second.get() == 0) return false;
+ return sum.second->logEvent(fullName);
+}
+
+template<typename AddendMetric>
+void
+SumMetric<AddendMetric>::print(std::ostream& out, bool verbose,
+ const std::string& indent,
+ uint64_t secondsPassed) const
+{
+ std::pair<std::vector<Metric::LP>, Metric::LP> sum(generateSum());
+ if (sum.second.get() == 0) return;
+ sum.second->print(out, verbose, indent, secondsPassed);
+}
+
+template<typename AddendMetric>
+bool
+SumMetric<AddendMetric>::used() const
+{
+ for(typename std::vector<const AddendMetric*>::const_iterator it(
+ _metricsToSum.begin()); it != _metricsToSum.end(); ++it)
+ {
+ if ((**it).used()) return true;
+ }
+ return false;
+}
+
+template<typename AddendMetric>
+void
+SumMetric<AddendMetric>::addMemoryUsage(MemoryConsumption& mc) const
+{
+ ++mc._sumMetricCount;
+ mc._sumMetricMeta += sizeof(SumMetric<AddendMetric>) - sizeof(Metric)
+ + _metricsToSum.capacity() * sizeof(Metric*);
+ Metric::addMemoryUsage(mc);
+}
+
+template<typename AddendMetric>
+void
+SumMetric<AddendMetric>::printDebug(std::ostream& out,
+ const std::string& indent) const
+{
+ out << "sum ";
+ Metric::printDebug(out, indent);
+ out << " {";
+ for(typename std::vector<const AddendMetric*>::const_iterator it(
+ _metricsToSum.begin()); it != _metricsToSum.end(); ++it)
+ {
+ out << "\n" << indent << " ";
+ (**it).printDebug(out, indent + " ");
+ }
+ out << "}";
+}
+
+template<typename AddendMetric>
+bool
+SumMetric<AddendMetric>::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<const AddendMetric*>(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 <vespa/metrics/textwriter.h>
-
-#include <vespa/metrics/countmetric.h>
-#include <vespa/metrics/metricset.h>
-#include <vespa/metrics/metricsnapshot.h>
-#include <vespa/metrics/valuemetric.h>
+#include "textwriter.h"
+#include "countmetric.h"
+#include "metricset.h"
+#include "metricsnapshot.h"
+#include "valuemetric.h"
+#include <sstream>
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 <vespa/vespalib/util/regexp.h>
-#include <vespa/metrics/metric.h>
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 <vespa/fastos/fastos.h>
-#include <vespa/metrics/valuemetric.h>
-#include <atomic>
-
+#include "valuemetric.hpp"
#include <vespa/log/log.h>
LOG_SETUP(".metrics.metric.value");
@@ -46,4 +44,9 @@ AbstractValueMetric::logNonFiniteValueWarning() const
}
}
+template class ValueMetric<double, double, true>;
+template class ValueMetric<double, double, false>;
+template class ValueMetric<int64_t, int64_t, true>;
+template class ValueMetric<int64_t, int64_t, false>;
+
} // 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 <vespa/vespalib/util/sync.h>
-#include <vespa/vespalib/util/exceptions.h>
-#include <sstream>
-#include <type_traits>
-#include <cmath>
-#include <vespa/metrics/metric.h>
-#include <vespa/metrics/metricvalueset.h>
-#include <vespa/vespalib/util/jsonstream.h>
-#include <vespa/vespalib/util/stringfmt.h>
-#include <atomic>
+#include "valuemetricvalues.h"
+#include "metric.h"
namespace metrics {
@@ -54,98 +46,10 @@ protected:
};
template<typename AvgVal, typename TotVal, bool SumOnAdd>
-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<uint32_t> _count {0};
- std::atomic<AvgVal> _min {std::numeric_limits<AvgVal>::max()};
- std::atomic<AvgVal> _max {std::numeric_limits<AvgVal>::min()};
- std::atomic<AvgVal> _last {0};
- std::atomic<TotVal> _total {0};
- };
-
- Values()
- : _count(0),
- _min(std::numeric_limits<AvgVal>::max()),
- _max(std::numeric_limits<AvgVal>::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<AvgVal>::is_signed
- && !std::numeric_limits<AvgVal>::is_integer)
- {
- _max = -1 * std::numeric_limits<AvgVal>::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<typename T>
- T getValue(const stringref & id) const {
- if (id == "last") return static_cast<T>(_last);
- if (id == "count") return static_cast<T>(_count);
- if (id == "total") return static_cast<T>(_total);
- if (id == "min") return static_cast<T>(_count > 0 ? _min : 0);
- if (id == "max") return static_cast<T>( _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<double>(id);
- }
- uint64_t getLongValue(const stringref & id) const {
- return getValue<uint64_t>(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<AvgVal, TotVal>;
MetricValueSet<Values> _values;
@@ -251,282 +155,5 @@ typedef ValueMetric<double, double, false> DoubleAverageMetric;
typedef ValueMetric<int64_t, int64_t, true> LongValueMetric;
typedef ValueMetric<int64_t, int64_t, false> LongAverageMetric;
-template<typename AvgVal, typename TotVal, bool SumOnAdd>
-ValueMetric<AvgVal, TotVal, SumOnAdd>::ValueMetric(
- const String& name, const String& tags,
- const String& description, MetricSet* owner)
- : AbstractValueMetric(name, tags, description, owner),
- _values()
-{
- _values.setFlag(LOG_IF_UNSET);
-}
-
-template<typename AvgVal, typename TotVal, bool SumOnAdd>
-ValueMetric<AvgVal, TotVal, SumOnAdd>::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<typename AvgVal, typename TotVal, bool SumOnAdd>
-ValueMetric<AvgVal, TotVal, SumOnAdd>::ValueMetric(
- const ValueMetric<AvgVal, TotVal, SumOnAdd>& other,
- CopyType copyType, MetricSet* owner)
- : AbstractValueMetric(other, owner),
- _values(other._values, copyType == CLONE ? other._values.size() : 1)
-{
-}
-
-template<typename AvgVal, typename TotVal, bool SumOnAdd>
-void ValueMetric<AvgVal, TotVal, SumOnAdd>::inc(AvgVal incVal)
-{
- if (!checkFinite(incVal, std::is_floating_point<AvgVal>())) {
- 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<typename AvgVal, typename TotVal, bool SumOnAdd>
-void ValueMetric<AvgVal, TotVal, SumOnAdd>::dec(AvgVal decVal)
-{
- if (!checkFinite(decVal, std::is_floating_point<AvgVal>())) {
- 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<typename AvgVal, typename TotVal, bool SumOnAdd>
-void
-ValueMetric<AvgVal, TotVal, SumOnAdd>::addToSnapshot(
- Metric& other, std::vector<Metric::LP>&) const
-{
- ValueMetric<AvgVal, TotVal, SumOnAdd>& o(
- reinterpret_cast<ValueMetric<AvgVal, TotVal, SumOnAdd>&>(other));
- if (_values.getValues()._count == 0) return; // Don't add if not set
- o.add(_values.getValues(), false);
-}
-
-template<typename AvgVal, typename TotVal, bool SumOnAdd>
-void
-ValueMetric<AvgVal, TotVal, SumOnAdd>::addToPart(Metric& other) const
-{
- ValueMetric<AvgVal, TotVal, SumOnAdd>& o(
- reinterpret_cast<ValueMetric<AvgVal, TotVal, SumOnAdd>&>(
- other));
- o.add(_values.getValues(), SumOnAdd);
-}
-
-template<typename AvgVal, typename TotVal, bool SumOnAdd>
-void
-ValueMetric<AvgVal, TotVal, SumOnAdd>::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<double>(values._total) / values._count
- + static_cast<double>(values2._total) / values2._count;
- values._count += values2._count;
- values._total = static_cast<TotVal>(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<typename AvgVal, typename TotVal, bool SumOnAdd>
-void
-ValueMetric<AvgVal, TotVal, SumOnAdd>::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<typename AvgVal, typename TotVal, bool SumOnAdd>
-void ValueMetric<AvgVal, TotVal, SumOnAdd>::addValueWithCount(
- AvgVal avg, TotVal tot, uint32_t count)
-{
- if (!checkFinite(avg, std::is_floating_point<AvgVal>())) {
- 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<typename AvgVal, typename TotVal, bool SumOnAdd>
-ValueMetric<AvgVal, TotVal, SumOnAdd>&
-ValueMetric<AvgVal, TotVal, SumOnAdd>::operator+=(
- const ValueMetric<AvgVal, TotVal, SumOnAdd>& other)
-{
- add(other._values.getValues(), SumOnAdd);
- return *this;
-}
-
-template<typename AvgVal, typename TotVal, bool SumOnAdd>
-double
-ValueMetric<AvgVal, TotVal, SumOnAdd>::getAverage() const
-{
- Values values(_values.getValues());
- if (values._count == 0) return 0;
- return static_cast<double>(values._total) / values._count;
-}
-
-template<typename AvgVal, typename TotVal, bool SumOnAdd>
-bool
-ValueMetric<AvgVal, TotVal, SumOnAdd>::logEvent(const String& fullName) const
-{
- Values values(_values.getValues());
- if (!logIfUnset() && !inUse(values)) return false;
- sendLogEvent(fullName, SumOnAdd
- ? static_cast<double>(values._last)
- : static_cast<double>(values._total) / values._count);
- return true;
-}
-
-template<typename AvgVal, typename TotVal, bool SumOnAdd>
-void
-ValueMetric<AvgVal, TotVal, SumOnAdd>::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<double>(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<typename AvgVal, typename TotVal, bool SumOnAdd>
-int64_t
-ValueMetric<AvgVal, TotVal, SumOnAdd>::getLongValue(const stringref & id) const
-{
- Values values(_values.getValues());
- if (id == "last" || (SumOnAdd && id == "value"))
- return static_cast<int64_t>(values._last);
- if (id == "average" || (!SumOnAdd && id == "value"))
- return static_cast<int64_t>(getAverage());
- if (id == "count") return static_cast<int64_t>(values._count);
- if (id == "total") return static_cast<int64_t>(values._total);
- if (id == "min") return static_cast<int64_t>(
- values._count > 0 ? values._min : 0);
- if (id == "max") return static_cast<int64_t>(
- values._count > 0 ? values._max : 0);
- throw vespalib::IllegalArgumentException(
- "No value " + id + " in average metric.", VESPA_STRLOC);
-}
-
-template<typename AvgVal, typename TotVal, bool SumOnAdd>
-double
-ValueMetric<AvgVal, TotVal, SumOnAdd>::getDoubleValue(const stringref & id) const
-{
- Values values(_values.getValues());
- if (id == "last" || (SumOnAdd && id == "value"))
- return static_cast<double>(values._last);
- if (id == "average" || (!SumOnAdd && id == "value"))
- return getAverage();
- if (id == "count") return static_cast<double>(values._count);
- if (id == "total") return static_cast<double>(values._total);
- if (id == "min") return static_cast<double>(
- values._count > 0 ? values._min : 0);
- if (id == "max") return static_cast<double>(
- values._count > 0 ? values._max : 0);
- throw vespalib::IllegalArgumentException(
- "No value " + vespalib::string(id) + " in average metric.", VESPA_STRLOC);
-}
-
-template<typename AvgVal, typename TotVal, bool SumOnAdd>
-void
-ValueMetric<AvgVal, TotVal, SumOnAdd>::addMemoryUsage(
- MemoryConsumption& mc) const
-{
- ++mc._valueMetricCount;
- mc._valueMetricValues += _values.getMemoryUsageAllocatedInternally();
- mc._valueMetricMeta += sizeof(ValueMetric<AvgVal, TotVal, SumOnAdd>)
- - sizeof(Metric);
- Metric::addMemoryUsage(mc);
-}
-
-template<typename AvgVal, typename TotVal, bool SumOnAdd>
-void
-ValueMetric<AvgVal, TotVal, SumOnAdd>::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 <vespa/vespalib/util/exceptions.h>
+#include <sstream>
+
+namespace metrics {
+
+template<typename AvgVal, typename TotVal, bool SumOnAdd>
+ValueMetric<AvgVal, TotVal, SumOnAdd>::ValueMetric(
+ const String& name, const String& tags,
+ const String& description, MetricSet* owner)
+ : AbstractValueMetric(name, tags, description, owner),
+ _values()
+{
+ _values.setFlag(LOG_IF_UNSET);
+}
+
+template<typename AvgVal, typename TotVal, bool SumOnAdd>
+ValueMetric<AvgVal, TotVal, SumOnAdd>::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<typename AvgVal, typename TotVal, bool SumOnAdd>
+ValueMetric<AvgVal, TotVal, SumOnAdd>::ValueMetric(
+ const ValueMetric<AvgVal, TotVal, SumOnAdd>& other,
+ CopyType copyType, MetricSet* owner)
+ : AbstractValueMetric(other, owner),
+ _values(other._values, copyType == CLONE ? other._values.size() : 1)
+{
+}
+
+template<typename AvgVal, typename TotVal, bool SumOnAdd>
+void ValueMetric<AvgVal, TotVal, SumOnAdd>::inc(AvgVal incVal)
+{
+ if (!checkFinite(incVal, std::is_floating_point<AvgVal>())) {
+ 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<typename AvgVal, typename TotVal, bool SumOnAdd>
+void ValueMetric<AvgVal, TotVal, SumOnAdd>::dec(AvgVal decVal)
+{
+ if (!checkFinite(decVal, std::is_floating_point<AvgVal>())) {
+ 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<typename AvgVal, typename TotVal, bool SumOnAdd>
+void
+ValueMetric<AvgVal, TotVal, SumOnAdd>::addToSnapshot(
+ Metric& other, std::vector<Metric::LP>&) const
+{
+ ValueMetric<AvgVal, TotVal, SumOnAdd>& o(
+ reinterpret_cast<ValueMetric<AvgVal, TotVal, SumOnAdd>&>(other));
+ if (_values.getValues()._count == 0) return; // Don't add if not set
+ o.add(_values.getValues(), false);
+}
+
+template<typename AvgVal, typename TotVal, bool SumOnAdd>
+void
+ValueMetric<AvgVal, TotVal, SumOnAdd>::addToPart(Metric& other) const
+{
+ ValueMetric<AvgVal, TotVal, SumOnAdd>& o(
+ reinterpret_cast<ValueMetric<AvgVal, TotVal, SumOnAdd>&>(
+ other));
+ o.add(_values.getValues(), SumOnAdd);
+}
+
+template<typename AvgVal, typename TotVal, bool SumOnAdd>
+void
+ValueMetric<AvgVal, TotVal, SumOnAdd>::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<double>(values._total) / values._count
+ + static_cast<double>(values2._total) / values2._count;
+ values._count += values2._count;
+ values._total = static_cast<TotVal>(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<typename AvgVal, typename TotVal, bool SumOnAdd>
+void
+ValueMetric<AvgVal, TotVal, SumOnAdd>::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<typename AvgVal, typename TotVal, bool SumOnAdd>
+void ValueMetric<AvgVal, TotVal, SumOnAdd>::addValueWithCount(
+ AvgVal avg, TotVal tot, uint32_t count)
+{
+ if (!checkFinite(avg, std::is_floating_point<AvgVal>())) {
+ 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<typename AvgVal, typename TotVal, bool SumOnAdd>
+ValueMetric<AvgVal, TotVal, SumOnAdd>&
+ValueMetric<AvgVal, TotVal, SumOnAdd>::operator+=(
+ const ValueMetric<AvgVal, TotVal, SumOnAdd>& other)
+{
+ add(other._values.getValues(), SumOnAdd);
+ return *this;
+}
+
+template<typename AvgVal, typename TotVal, bool SumOnAdd>
+double
+ValueMetric<AvgVal, TotVal, SumOnAdd>::getAverage() const
+{
+ Values values(_values.getValues());
+ if (values._count == 0) return 0;
+ return static_cast<double>(values._total) / values._count;
+}
+
+template<typename AvgVal, typename TotVal, bool SumOnAdd>
+bool
+ValueMetric<AvgVal, TotVal, SumOnAdd>::logEvent(const String& fullName) const
+{
+ Values values(_values.getValues());
+ if (!logIfUnset() && !inUse(values)) return false;
+ sendLogEvent(fullName, SumOnAdd
+ ? static_cast<double>(values._last)
+ : static_cast<double>(values._total) / values._count);
+ return true;
+}
+
+template<typename AvgVal, typename TotVal, bool SumOnAdd>
+void
+ValueMetric<AvgVal, TotVal, SumOnAdd>::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<double>(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<typename AvgVal, typename TotVal, bool SumOnAdd>
+int64_t
+ValueMetric<AvgVal, TotVal, SumOnAdd>::getLongValue(const stringref & id) const
+{
+ Values values(_values.getValues());
+ if (id == "last" || (SumOnAdd && id == "value"))
+ return static_cast<int64_t>(values._last);
+ if (id == "average" || (!SumOnAdd && id == "value"))
+ return static_cast<int64_t>(getAverage());
+ if (id == "count") return static_cast<int64_t>(values._count);
+ if (id == "total") return static_cast<int64_t>(values._total);
+ if (id == "min") return static_cast<int64_t>(
+ values._count > 0 ? values._min : 0);
+ if (id == "max") return static_cast<int64_t>(
+ values._count > 0 ? values._max : 0);
+ throw vespalib::IllegalArgumentException(
+ "No value " + id + " in average metric.", VESPA_STRLOC);
+}
+
+template<typename AvgVal, typename TotVal, bool SumOnAdd>
+double
+ValueMetric<AvgVal, TotVal, SumOnAdd>::getDoubleValue(const stringref & id) const
+{
+ Values values(_values.getValues());
+ if (id == "last" || (SumOnAdd && id == "value"))
+ return static_cast<double>(values._last);
+ if (id == "average" || (!SumOnAdd && id == "value"))
+ return getAverage();
+ if (id == "count") return static_cast<double>(values._count);
+ if (id == "total") return static_cast<double>(values._total);
+ if (id == "min") return static_cast<double>(
+ values._count > 0 ? values._min : 0);
+ if (id == "max") return static_cast<double>(
+ values._count > 0 ? values._max : 0);
+ throw vespalib::IllegalArgumentException(
+ "No value " + vespalib::string(id) + " in average metric.", VESPA_STRLOC);
+}
+
+template<typename AvgVal, typename TotVal, bool SumOnAdd>
+void
+ValueMetric<AvgVal, TotVal, SumOnAdd>::addMemoryUsage(
+ MemoryConsumption& mc) const
+{
+ ++mc._valueMetricCount;
+ mc._valueMetricValues += _values.getMemoryUsageAllocatedInternally();
+ mc._valueMetricMeta += sizeof(ValueMetric<AvgVal, TotVal, SumOnAdd>)
+ - sizeof(Metric);
+ Metric::addMemoryUsage(mc);
+}
+
+template<typename AvgVal, typename TotVal, bool SumOnAdd>
+void
+ValueMetric<AvgVal, TotVal, SumOnAdd>::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<int64_t, int64_t>;
+template std::ostream & operator << (std::ostream & os, const ValueMetricValues<int64_t, int64_t> & v);
+
+template class ValueMetricValues<double, double>;
+template std::ostream & operator << (std::ostream & os, const ValueMetricValues<double, double> & 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<typename AvgVal, typename TotVal>
+struct ValueMetricValues : MetricValueClass {
+ uint32_t _count;
+ AvgVal _min, _max, _last;
+ TotVal _total;
+
+ struct AtomicImpl {
+ std::atomic<uint32_t> _count {0};
+ std::atomic<AvgVal> _min {std::numeric_limits<AvgVal>::max()};
+ std::atomic<AvgVal> _max {std::numeric_limits<AvgVal>::min()};
+ std::atomic<AvgVal> _last {0};
+ std::atomic<TotVal> _total {0};
+ };
+
+ ValueMetricValues();
+ void relaxedStoreInto(AtomicImpl& target) const noexcept;
+ void relaxedLoadFrom(const AtomicImpl& source) noexcept;
+
+ template<typename T>
+ 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<typename A, typename T>
+ friend std::ostream & operator << (std::ostream & os, const ValueMetricValues<A, T> & 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 <ostream>
+
+namespace metrics {
+
+using vespalib::IllegalArgumentException;
+
+template<typename AvgVal, typename TotVal>
+ValueMetricValues<AvgVal, TotVal>::ValueMetricValues()
+ : _count(0),
+ _min(std::numeric_limits<AvgVal>::max()),
+ _max(std::numeric_limits<AvgVal>::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<AvgVal>::is_signed
+ && !std::numeric_limits<AvgVal>::is_integer)
+ {
+ _max = -1 * std::numeric_limits<AvgVal>::max();
+ }
+}
+
+template<typename AvgVal, typename TotVal>
+void ValueMetricValues<AvgVal, TotVal>::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<typename AvgVal, typename TotVal>
+void ValueMetricValues<AvgVal, TotVal>::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<typename AvgVal, typename TotVal>
+template<typename T>
+T ValueMetricValues<AvgVal, TotVal>::getValue(const stringref & id) const {
+ if (id == "last") return static_cast<T>(_last);
+ if (id == "count") return static_cast<T>(_count);
+ if (id == "total") return static_cast<T>(_total);
+ if (id == "min") return static_cast<T>(_count > 0 ? _min : 0);
+ if (id == "max") return static_cast<T>( _count > 0 ? _max : 0);
+ throw IllegalArgumentException("No value " + vespalib::string(id) + " in value metric.", VESPA_STRLOC);
+}
+
+template<typename AvgVal, typename TotVal>
+double ValueMetricValues<AvgVal, TotVal>::getDoubleValue(const stringref & id) const {
+ return getValue<double>(id);
+}
+template<typename AvgVal, typename TotVal>
+uint64_t ValueMetricValues<AvgVal, TotVal>::getLongValue(const stringref & id) const {
+ return getValue<uint64_t>(id);
+}
+template<typename AvgVal, typename TotVal>
+void ValueMetricValues<AvgVal, TotVal>::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<typename AvgVal, typename TotVal>
+void ValueMetricValues<AvgVal, TotVal>::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<typename AvgVal, typename TotVal>
+std::ostream & operator << (std::ostream & os, const ValueMetricValues<AvgVal, TotVal> & v) {
+ os << "count=" << v._count;
+ os << ", total=" << v._total;
+ return os;
+}
+
+} // metrics
+