diff options
6 files changed, 166 insertions, 33 deletions
diff --git a/metrics/src/tests/valuemetrictest.cpp b/metrics/src/tests/valuemetrictest.cpp index 745edf44081..e8c144c96aa 100644 --- a/metrics/src/tests/valuemetrictest.cpp +++ b/metrics/src/tests/valuemetrictest.cpp @@ -187,10 +187,10 @@ void ValueMetricTest::testSmallAverage() void ValueMetricTest::testAddValueBatch() { DoubleValueMetric m("test", "tag", "description"); - m.addValueBatch(100, 3); - ASSERT_AVERAGE(m, 100, 100, 100, 3, 100); - m.addValueBatch(0, 0); - ASSERT_AVERAGE(m, 100, 100, 100, 3, 100); + m.addValueBatch(100, 3, 80, 120); + ASSERT_AVERAGE(m, 100, 80, 120, 3, 100); + m.addValueBatch(123, 0, 12, 1234); + ASSERT_AVERAGE(m, 100, 80, 120, 3, 100); } namespace { diff --git a/metrics/src/vespa/metrics/valuemetric.h b/metrics/src/vespa/metrics/valuemetric.h index 3a9e90be721..0c40a0fa5ea 100644 --- a/metrics/src/vespa/metrics/valuemetric.h +++ b/metrics/src/vespa/metrics/valuemetric.h @@ -65,7 +65,10 @@ class ValueMetric : public AbstractValueMetric { void dec(const Values &values); - void addValueWithCount(AvgVal avg, TotVal tot, uint32_t count); + void addValueWithCount(AvgVal avg, TotVal tot, uint32_t count, AvgVal min, AvgVal max); + void addValueWithCount(AvgVal avg, TotVal tot, uint32_t count) { + addValueWithCount(avg, tot, count, avg, avg); + } // Finite number (not infinity/NaN) check using type trait tag dispatch. // 2nd param is instance of std::true_type iff AvgVal is floating point. @@ -110,12 +113,20 @@ public: ValueMetric t(a); t += b; return t; } - void addAvgValueWithCount(AvgVal avg, uint32_t count) - { if (count) { addValueWithCount(avg, avg * count, count); } } - void addTotalValueWithCount(TotVal tot, uint32_t count) - { if (count) { addValueWithCount(tot / count, tot, count); } } - void addValueBatch(AvgVal avg, uint32_t count) { - addAvgValueWithCount(avg, count); + void addAvgValueWithCount(AvgVal avg, uint32_t count) { + if (count > 0) { + addValueWithCount(avg, avg * count, count); + } + } + void addTotalValueWithCount(TotVal tot, uint32_t count) { + if (count > 0) { + addValueWithCount(tot / count, tot, count); + } + } + void addValueBatch(AvgVal avg, uint32_t count, AvgVal min, AvgVal max) { + if (count > 0) { + addValueWithCount(avg, avg * count, count, min, max); + } } virtual void addValue(AvgVal avg) { addAvgValueWithCount(avg, 1); } virtual void set(AvgVal avg) { addValue(avg); } diff --git a/metrics/src/vespa/metrics/valuemetric.hpp b/metrics/src/vespa/metrics/valuemetric.hpp index 18c7837efb8..f8b4d1626ab 100644 --- a/metrics/src/vespa/metrics/valuemetric.hpp +++ b/metrics/src/vespa/metrics/valuemetric.hpp @@ -157,7 +157,7 @@ ValueMetric<AvgVal, TotVal, SumOnAdd>::dec(const Values& values2) template<typename AvgVal, typename TotVal, bool SumOnAdd> void ValueMetric<AvgVal, TotVal, SumOnAdd>::addValueWithCount( - AvgVal avg, TotVal tot, uint32_t count) + AvgVal avg, TotVal tot, uint32_t count, AvgVal min, AvgVal max) { if (!checkFinite(avg, std::is_floating_point<AvgVal>())) { return; @@ -167,8 +167,8 @@ void ValueMetric<AvgVal, TotVal, SumOnAdd>::addValueWithCount( values = _values.getValues(); values._count += count; values._total += tot; - if (avg < values._min) values._min = avg; - if (avg > values._max) values._max = avg; + if (min < values._min) values._min = min; + if (max > values._max) values._max = max; values._last = avg; } while (!_values.setValues(values)); } diff --git a/searchcore/src/tests/proton/matching/matching_stats_test.cpp b/searchcore/src/tests/proton/matching/matching_stats_test.cpp index cc256e0c729..8b58a9e271c 100644 --- a/searchcore/src/tests/proton/matching/matching_stats_test.cpp +++ b/searchcore/src/tests/proton/matching/matching_stats_test.cpp @@ -88,6 +88,62 @@ TEST("requireThatAverageTimesAreRecorded") { EXPECT_EQUAL(4u, stats.queryLatencyCount()); } +TEST("requireThatMinMaxTimesAreRecorded") { + MatchingStats stats; + EXPECT_APPROX(0.0, stats.matchTimeMin(), 0.00001); + EXPECT_APPROX(0.0, stats.groupingTimeMin(), 0.00001); + EXPECT_APPROX(0.0, stats.rerankTimeMin(), 0.00001); + EXPECT_APPROX(0.0, stats.queryCollateralTimeMin(), 0.00001); + EXPECT_APPROX(0.0, stats.queryLatencyMin(), 0.00001); + EXPECT_APPROX(0.0, stats.matchTimeMax(), 0.00001); + EXPECT_APPROX(0.0, stats.groupingTimeMax(), 0.00001); + EXPECT_APPROX(0.0, stats.rerankTimeMax(), 0.00001); + EXPECT_APPROX(0.0, stats.queryCollateralTimeMax(), 0.00001); + EXPECT_APPROX(0.0, stats.queryLatencyMax(), 0.00001); + stats.matchTime(0.01).groupingTime(0.1).rerankTime(0.5).queryCollateralTime(2.0).queryLatency(1.0); + EXPECT_APPROX(0.01, stats.matchTimeMin(), 0.00001); + EXPECT_APPROX(0.1, stats.groupingTimeMin(), 0.00001); + EXPECT_APPROX(0.5, stats.rerankTimeMin(), 0.00001); + EXPECT_APPROX(2.0, stats.queryCollateralTimeMin(), 0.00001); + EXPECT_APPROX(1.0, stats.queryLatencyMin(), 0.00001); + EXPECT_APPROX(0.01, stats.matchTimeMax(), 0.00001); + EXPECT_APPROX(0.1, stats.groupingTimeMax(), 0.00001); + EXPECT_APPROX(0.5, stats.rerankTimeMax(), 0.00001); + EXPECT_APPROX(2.0, stats.queryCollateralTimeMax(), 0.00001); + EXPECT_APPROX(1.0, stats.queryLatencyMax(), 0.00001); + stats.add(MatchingStats().matchTime(0.03).groupingTime(0.3).rerankTime(1.5).queryCollateralTime(6.0).queryLatency(3.0)); + EXPECT_APPROX(0.01, stats.matchTimeMin(), 0.00001); + EXPECT_APPROX(0.1, stats.groupingTimeMin(), 0.00001); + EXPECT_APPROX(0.5, stats.rerankTimeMin(), 0.00001); + EXPECT_APPROX(2.0, stats.queryCollateralTimeMin(), 0.00001); + EXPECT_APPROX(1.0, stats.queryLatencyMin(), 0.00001); + EXPECT_APPROX(0.03, stats.matchTimeMax(), 0.00001); + EXPECT_APPROX(0.3, stats.groupingTimeMax(), 0.00001); + EXPECT_APPROX(1.5, stats.rerankTimeMax(), 0.00001); + EXPECT_APPROX(6.0, stats.queryCollateralTimeMax(), 0.00001); + EXPECT_APPROX(3.0, stats.queryLatencyMax(), 0.00001); + stats.add(MatchingStats().matchTime(0.05) + .groupingTime(0.5) + .rerankTime(2.5) + .queryCollateralTime(10.0) + .queryLatency(5.0)); + stats.add(MatchingStats().matchTime(0.05).matchTime(0.03) + .groupingTime(0.5).groupingTime(0.3) + .rerankTime(2.5).rerankTime(1.5) + .queryCollateralTime(10.0).queryCollateralTime(6.0) + .queryLatency(5.0).queryLatency(3.0)); + EXPECT_APPROX(0.01, stats.matchTimeMin(), 0.00001); + EXPECT_APPROX(0.1, stats.groupingTimeMin(), 0.00001); + EXPECT_APPROX(0.5, stats.rerankTimeMin(), 0.00001); + EXPECT_APPROX(2.0, stats.queryCollateralTimeMin(), 0.00001); + EXPECT_APPROX(1.0, stats.queryLatencyMin(), 0.00001); + EXPECT_APPROX(0.05, stats.matchTimeMax(), 0.00001); + EXPECT_APPROX(0.5, stats.groupingTimeMax(), 0.00001); + EXPECT_APPROX(2.5, stats.rerankTimeMax(), 0.00001); + EXPECT_APPROX(10.0, stats.queryCollateralTimeMax(), 0.00001); + EXPECT_APPROX(5.0, stats.queryLatencyMax(), 0.00001); +} + TEST("requireThatPartitionsAreAddedCorrectly") { MatchingStats all1; EXPECT_EQUAL(0u, all1.docidSpaceCovered()); @@ -105,6 +161,10 @@ TEST("requireThatPartitionsAreAddedCorrectly") { EXPECT_EQUAL(0.5, subPart.wait_time_avg()); EXPECT_EQUAL(1u, subPart.active_time_count()); EXPECT_EQUAL(1u, subPart.wait_time_count()); + EXPECT_EQUAL(1.0, subPart.active_time_min()); + EXPECT_EQUAL(0.5, subPart.wait_time_min()); + EXPECT_EQUAL(1.0, subPart.active_time_max()); + EXPECT_EQUAL(0.5, subPart.wait_time_max()); all1.merge_partition(subPart, 0); EXPECT_EQUAL(7u, all1.docidSpaceCovered()); @@ -120,8 +180,15 @@ TEST("requireThatPartitionsAreAddedCorrectly") { EXPECT_EQUAL(0.5, all1.getPartition(0).wait_time_avg()); EXPECT_EQUAL(1u, all1.getPartition(0).active_time_count()); EXPECT_EQUAL(1u, all1.getPartition(0).wait_time_count()); - - all1.merge_partition(subPart, 1); + EXPECT_EQUAL(1.0, all1.getPartition(0).active_time_min()); + EXPECT_EQUAL(0.5, all1.getPartition(0).wait_time_min()); + EXPECT_EQUAL(1.0, all1.getPartition(0).active_time_max()); + EXPECT_EQUAL(0.5, all1.getPartition(0).wait_time_max()); + + MatchingStats::Partition otherSubPart; + otherSubPart.docsCovered(7).docsMatched(3).docsRanked(2).docsReRanked(1) + .active_time(0.5).wait_time(1.0); + all1.merge_partition(otherSubPart, 1); EXPECT_EQUAL(14u, all1.docidSpaceCovered()); EXPECT_EQUAL(6u, all1.docsMatched()); EXPECT_EQUAL(4u, all1.docsRanked()); @@ -130,12 +197,20 @@ TEST("requireThatPartitionsAreAddedCorrectly") { EXPECT_EQUAL(3u, all1.getPartition(1).docsMatched()); EXPECT_EQUAL(2u, all1.getPartition(1).docsRanked()); EXPECT_EQUAL(1u, all1.getPartition(1).docsReRanked()); - EXPECT_EQUAL(1.0, all1.getPartition(1).active_time_avg()); - EXPECT_EQUAL(0.5, all1.getPartition(1).wait_time_avg()); + EXPECT_EQUAL(0.5, all1.getPartition(1).active_time_avg()); + EXPECT_EQUAL(1.0, all1.getPartition(1).wait_time_avg()); EXPECT_EQUAL(1u, all1.getPartition(1).active_time_count()); EXPECT_EQUAL(1u, all1.getPartition(1).wait_time_count()); + EXPECT_EQUAL(0.5, all1.getPartition(1).active_time_min()); + EXPECT_EQUAL(1.0, all1.getPartition(1).wait_time_min()); + EXPECT_EQUAL(0.5, all1.getPartition(1).active_time_max()); + EXPECT_EQUAL(1.0, all1.getPartition(1).wait_time_max()); + + MatchingStats all2; + all2.merge_partition(otherSubPart, 0); + all2.merge_partition(subPart, 1); - all1.add(all1); + all1.add(all2); EXPECT_EQUAL(28u, all1.docidSpaceCovered()); EXPECT_EQUAL(12u, all1.docsMatched()); EXPECT_EQUAL(8u, all1.docsRanked()); @@ -144,17 +219,25 @@ TEST("requireThatPartitionsAreAddedCorrectly") { EXPECT_EQUAL(6u, all1.getPartition(0).docsMatched()); EXPECT_EQUAL(4u, all1.getPartition(0).docsRanked()); EXPECT_EQUAL(2u, all1.getPartition(0).docsReRanked()); - EXPECT_EQUAL(1.0, all1.getPartition(0).active_time_avg()); - EXPECT_EQUAL(0.5, all1.getPartition(0).wait_time_avg()); + EXPECT_EQUAL(0.75, all1.getPartition(0).active_time_avg()); + EXPECT_EQUAL(0.75, all1.getPartition(0).wait_time_avg()); EXPECT_EQUAL(2u, all1.getPartition(0).active_time_count()); EXPECT_EQUAL(2u, all1.getPartition(0).wait_time_count()); + EXPECT_EQUAL(0.5, all1.getPartition(0).active_time_min()); + EXPECT_EQUAL(0.5, all1.getPartition(0).wait_time_min()); + EXPECT_EQUAL(1.0, all1.getPartition(0).active_time_max()); + EXPECT_EQUAL(1.0, all1.getPartition(0).wait_time_max()); EXPECT_EQUAL(6u, all1.getPartition(1).docsMatched()); EXPECT_EQUAL(4u, all1.getPartition(1).docsRanked()); EXPECT_EQUAL(2u, all1.getPartition(1).docsReRanked()); - EXPECT_EQUAL(1.0, all1.getPartition(1).active_time_avg()); - EXPECT_EQUAL(0.5, all1.getPartition(1).wait_time_avg()); + EXPECT_EQUAL(0.75, all1.getPartition(1).active_time_avg()); + EXPECT_EQUAL(0.75, all1.getPartition(1).wait_time_avg()); EXPECT_EQUAL(2u, all1.getPartition(1).active_time_count()); EXPECT_EQUAL(2u, all1.getPartition(1).wait_time_count()); + EXPECT_EQUAL(0.5, all1.getPartition(1).active_time_min()); + EXPECT_EQUAL(0.5, all1.getPartition(1).wait_time_min()); + EXPECT_EQUAL(1.0, all1.getPartition(1).active_time_max()); + EXPECT_EQUAL(1.0, all1.getPartition(1).wait_time_max()); } TEST_MAIN() { diff --git a/searchcore/src/vespa/searchcore/proton/matching/matching_stats.h b/searchcore/src/vespa/searchcore/proton/matching/matching_stats.h index 6df01afaa4d..b58468fe1bc 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/matching_stats.h +++ b/searchcore/src/vespa/searchcore/proton/matching/matching_stats.h @@ -19,12 +19,30 @@ private: class Avg { double _value; size_t _count; + double _min; + double _max; public: - Avg() : _value(0.0), _count(0) {} - void set(double value) { _value = value; _count = 1; } - double avg() const { return !_count ? 0 : _value / _count; } + Avg() : _value(0.0), _count(0), _min(0.0), _max(0.0) {} + void set(double value) { + _value = value; + _count = 1; + _min = value; + _max = value; + } + double avg() const { + return (_count > 0) ? (_value / _count) : 0; + } size_t count() const { return _count; } + double min() const { return _min; } + double max() const { return _max; } void add(const Avg &other) { + if (_count == 0) { + _min = other._min; + _max = other._max; + } else if (other._count > 0) { + _min = std::min(_min, other._min); + _max = std::max(_max, other._max); + } _value += other._value; _count += other._count; } @@ -68,9 +86,13 @@ public: Partition &active_time(double time_s) { _active_time.set(time_s); return *this; } double active_time_avg() const { return _active_time.avg(); } size_t active_time_count() const { return _active_time.count(); } + double active_time_min() const { return _active_time.min(); } + double active_time_max() const { return _active_time.max(); } Partition &wait_time(double time_s) { _wait_time.set(time_s); return *this; } double wait_time_avg() const { return _wait_time.avg(); } size_t wait_time_count() const { return _wait_time.count(); } + double wait_time_min() const { return _wait_time.min(); } + double wait_time_max() const { return _wait_time.max(); } Partition &add(const Partition &rhs) { _docsCovered += rhs.docsCovered(); @@ -136,22 +158,32 @@ public: MatchingStats &queryCollateralTime(double time_s) { _queryCollateralTime.set(time_s); return *this; } double queryCollateralTimeAvg() const { return _queryCollateralTime.avg(); } size_t queryCollateralTimeCount() const { return _queryCollateralTime.count(); } + double queryCollateralTimeMin() const { return _queryCollateralTime.min(); } + double queryCollateralTimeMax() const { return _queryCollateralTime.max(); } MatchingStats &queryLatency(double time_s) { _queryLatency.set(time_s); return *this; } double queryLatencyAvg() const { return _queryLatency.avg(); } size_t queryLatencyCount() const { return _queryLatency.count(); } + double queryLatencyMin() const { return _queryLatency.min(); } + double queryLatencyMax() const { return _queryLatency.max(); } MatchingStats &matchTime(double time_s) { _matchTime.set(time_s); return *this; } double matchTimeAvg() const { return _matchTime.avg(); } size_t matchTimeCount() const { return _matchTime.count(); } + double matchTimeMin() const { return _matchTime.min(); } + double matchTimeMax() const { return _matchTime.max(); } MatchingStats &groupingTime(double time_s) { _groupingTime.set(time_s); return *this; } double groupingTimeAvg() const { return _groupingTime.avg(); } size_t groupingTimeCount() const { return _groupingTime.count(); } + double groupingTimeMin() const { return _groupingTime.min(); } + double groupingTimeMax() const { return _groupingTime.max(); } MatchingStats &rerankTime(double time_s) { _rerankTime.set(time_s); return *this; } double rerankTimeAvg() const { return _rerankTime.avg(); } size_t rerankTimeCount() const { return _rerankTime.count(); } + double rerankTimeMin() const { return _rerankTime.min(); } + double rerankTimeMax() const { return _rerankTime.max(); } // used to merge in stats from each match thread MatchingStats &merge_partition(const Partition &partition, size_t id); diff --git a/searchcore/src/vespa/searchcore/proton/metrics/legacy_documentdb_metrics.cpp b/searchcore/src/vespa/searchcore/proton/metrics/legacy_documentdb_metrics.cpp index 2c753d24c69..4d23c3f1603 100644 --- a/searchcore/src/vespa/searchcore/proton/metrics/legacy_documentdb_metrics.cpp +++ b/searchcore/src/vespa/searchcore/proton/metrics/legacy_documentdb_metrics.cpp @@ -41,8 +41,10 @@ LegacyDocumentDBMetrics::MatchingMetrics::update(const MatchingStats &stats) docsReRanked.inc(stats.docsReRanked()); softDoomFactor.set(stats.softDoomFactor()); queries.inc(stats.queries()); - queryCollateralTime.addValueBatch(stats.queryCollateralTimeAvg(), stats.queryCollateralTimeCount()); - queryLatency.addValueBatch(stats.queryLatencyAvg(), stats.queryLatencyCount()); + queryCollateralTime.addValueBatch(stats.queryCollateralTimeAvg(), stats.queryCollateralTimeCount(), + stats.queryCollateralTimeMin(), stats.queryCollateralTimeMax()); + queryLatency.addValueBatch(stats.queryLatencyAvg(), stats.queryLatencyCount(), + stats.queryLatencyMin(), stats.queryLatencyMax()); } LegacyDocumentDBMetrics::MatchingMetrics::MatchingMetrics(MetricSet *parent) @@ -92,8 +94,10 @@ LegacyDocumentDBMetrics::MatchingMetrics::RankProfileMetrics::DocIdPartition::up docsMatched.inc(stats.docsMatched()); docsRanked.inc(stats.docsRanked()); docsReRanked.inc(stats.docsReRanked()); - active_time.addValueBatch(stats.active_time_avg(), stats.active_time_count()); - wait_time.addValueBatch(stats.wait_time_avg(), stats.wait_time_count()); + active_time.addValueBatch(stats.active_time_avg(), stats.active_time_count(), + stats.active_time_min(), stats.active_time_max()); + wait_time.addValueBatch(stats.wait_time_avg(), stats.wait_time_count(), + stats.wait_time_min(), stats.wait_time_max()); } void @@ -101,9 +105,12 @@ LegacyDocumentDBMetrics::MatchingMetrics::RankProfileMetrics::update(const Match { queries.inc(stats.queries()); limited_queries.inc(stats.limited_queries()); - matchTime.addValueBatch(stats.matchTimeAvg(), stats.matchTimeCount()); - groupingTime.addValueBatch(stats.groupingTimeAvg(), stats.groupingTimeCount()); - rerankTime.addValueBatch(stats.rerankTimeAvg(), stats.rerankTimeCount()); + matchTime.addValueBatch(stats.matchTimeAvg(), stats.matchTimeCount(), + stats.matchTimeMin(), stats.matchTimeMax()); + groupingTime.addValueBatch(stats.groupingTimeAvg(), stats.groupingTimeCount(), + stats.groupingTimeMin(), stats.groupingTimeMax()); + rerankTime.addValueBatch(stats.rerankTimeAvg(), stats.rerankTimeCount(), + stats.rerankTimeMin(), stats.rerankTimeMax()); if (stats.getNumPartitions() > 0) { if (stats.getNumPartitions() <= partitions.size()) { for (size_t i(0), m(stats.getNumPartitions()); i < m; i++) { |