aboutsummaryrefslogtreecommitdiffstats
path: root/searchcore/src/vespa/searchcore/proton/matching/matching_stats.cpp
blob: f2c2394a18f8ee6516dcab9312ea94a277c06177 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "matching_stats.h"
#include <cmath>

namespace proton::matching {

namespace {

MatchingStats::Partition &get_writable_partition(std::vector<MatchingStats::Partition> &state, size_t id) {
    if (state.size() <= id) {
        state.resize(id + 1);
    }
    return state[id];
}

constexpr vespalib::duration MIN_TIMEOUT = 1ms;
constexpr double MAX_CHANGE_FACTOR = 5;

} // namespace proton::matching::<unnamed>

MatchingStats::MatchingStats(double prev_soft_doom_factor) noexcept
    : _queries(0),
      _limited_queries(0),
      _docidSpaceCovered(0),
      _docsMatched(0),
      _docsRanked(0),
      _docsReRanked(0),
      _softDoomed(0),
      _doomOvertime(),
      _softDoomFactor(prev_soft_doom_factor),
      _querySetupTime(),
      _queryLatency(),
      _matchTime(),
      _groupingTime(),
      _rerankTime(),
      _partitions()
{ }

MatchingStats::~MatchingStats() = default;

MatchingStats &
MatchingStats::merge_partition(const Partition &partition, size_t id)
{
    get_writable_partition(_partitions, id) = partition;

    _docidSpaceCovered += partition.docsCovered();
    _docsMatched += partition.docsMatched();
    _docsRanked += partition.docsRanked();
    _docsReRanked += partition.docsReRanked();
    _doomOvertime.add(partition._doomOvertime);
    if (partition.softDoomed()) {
        _softDoomed = 1;
    }

    return *this;
}

MatchingStats &
MatchingStats::add(const MatchingStats &rhs) noexcept
{
    _queries += rhs._queries;
    _limited_queries += rhs._limited_queries;

    _docidSpaceCovered += rhs._docidSpaceCovered;
    _docsMatched += rhs._docsMatched;
    _docsRanked += rhs._docsRanked;
    _docsReRanked += rhs._docsReRanked;
    _softDoomed += rhs.softDoomed();
    _doomOvertime.add(rhs._doomOvertime);

    _querySetupTime.add(rhs._querySetupTime);
    _queryLatency.add(rhs._queryLatency);
    _matchTime.add(rhs._matchTime);
    _groupingTime.add(rhs._groupingTime);
    _rerankTime.add(rhs._rerankTime);
    for (size_t id = 0; id < rhs.getNumPartitions(); ++id) {
        get_writable_partition(_partitions, id).add(rhs.getPartition(id));
    }
    return *this;
}

MatchingStats &
MatchingStats::updatesoftDoomFactor(vespalib::duration hardLimit, vespalib::duration softLimit, vespalib::duration duration) {
    // The safety capping here should normally not be necessary as all input numbers
    // will normally be within reasonable values.
    // It is merely a safety measure to avoid overflow on bad input as can happen with time senstive stuff
    // in any soft real time system.
    if ((hardLimit >= MIN_TIMEOUT) && (softLimit >= MIN_TIMEOUT)) {
        double factor = softDoomFactor();
        double diff = vespalib::to_s(softLimit - duration)/vespalib::to_s(hardLimit);
        if (duration < softLimit) {
            // Since softdoom factor can become very small, allow a minimum change of some size
            diff = std::min(diff, factor*MAX_CHANGE_FACTOR);
            factor += 0.01*diff;
        } else {
            diff = std::max(diff, -factor*MAX_CHANGE_FACTOR);
            factor += 0.02*diff;
        }
        factor = std::max(factor, 0.01); // Never go below 1%
        softDoomFactor(factor);
    }
    return *this;
}

}