aboutsummaryrefslogtreecommitdiffstats
path: root/searchcore/src/tests/proton/matching/matching_stats_test.cpp
blob: b8bc4eaa7e62296c4744dd70a668720514e10db0 (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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/vespalib/testkit/test_kit.h>
#include <vespa/searchcore/proton/matching/matching_stats.h>

#include <vespa/log/log.h>
LOG_SETUP("matching_stats_test");

using namespace proton::matching;

TEST("requireThatDocCountsAddUp") {
    MatchingStats stats;
    EXPECT_EQUAL(0u, stats.docidSpaceCovered());
    EXPECT_EQUAL(0u, stats.docsMatched());
    EXPECT_EQUAL(0u, stats.docsRanked());
    EXPECT_EQUAL(0u, stats.docsReRanked());
    EXPECT_EQUAL(0u, stats.queries());
    EXPECT_EQUAL(0u, stats.limited_queries());
    {
        MatchingStats rhs;
        EXPECT_EQUAL(&rhs.docidSpaceCovered(10000), &rhs);
        EXPECT_EQUAL(&rhs.docsMatched(1000), &rhs);
        EXPECT_EQUAL(&rhs.docsRanked(100), &rhs);
        EXPECT_EQUAL(&rhs.docsReRanked(10), &rhs);
        EXPECT_EQUAL(&rhs.queries(2), &rhs);
        EXPECT_EQUAL(&rhs.limited_queries(1), &rhs);
        EXPECT_EQUAL(&stats.add(rhs), &stats);
    }
    EXPECT_EQUAL(10000u, stats.docidSpaceCovered());
    EXPECT_EQUAL(1000u, stats.docsMatched());
    EXPECT_EQUAL(100u, stats.docsRanked());
    EXPECT_EQUAL(10u, stats.docsReRanked());
    EXPECT_EQUAL(2u, stats.queries());
    EXPECT_EQUAL(1u, stats.limited_queries());
    EXPECT_EQUAL(&stats.add(MatchingStats().docidSpaceCovered(10000).docsMatched(1000).docsRanked(100)
                            .docsReRanked(10).queries(2).limited_queries(1)), &stats);
    EXPECT_EQUAL(20000u, stats.docidSpaceCovered());
    EXPECT_EQUAL(2000u, stats.docsMatched());
    EXPECT_EQUAL(200u, stats.docsRanked());
    EXPECT_EQUAL(20u, stats.docsReRanked());
    EXPECT_EQUAL(4u, stats.queries());
    EXPECT_EQUAL(2u, stats.limited_queries());
}

TEST("requireThatAverageTimesAreRecorded") {
    MatchingStats stats;
    EXPECT_APPROX(0.0, stats.matchTimeAvg(), 0.00001);
    EXPECT_APPROX(0.0, stats.groupingTimeAvg(), 0.00001);
    EXPECT_APPROX(0.0, stats.rerankTimeAvg(), 0.00001);
    EXPECT_APPROX(0.0, stats.querySetupTimeAvg(), 0.00001);
    EXPECT_APPROX(0.0, stats.queryLatencyAvg(), 0.00001);
    EXPECT_EQUAL(0u, stats.matchTimeCount());
    EXPECT_EQUAL(0u, stats.groupingTimeCount());
    EXPECT_EQUAL(0u, stats.rerankTimeCount());
    EXPECT_EQUAL(0u, stats.querySetupTimeCount());
    EXPECT_EQUAL(0u, stats.queryLatencyCount());
    stats.matchTime(0.01).groupingTime(0.1).rerankTime(0.5).querySetupTime(2.0).queryLatency(1.0);
    EXPECT_APPROX(0.01, stats.matchTimeAvg(), 0.00001);
    EXPECT_APPROX(0.1, stats.groupingTimeAvg(), 0.00001);
    EXPECT_APPROX(0.5, stats.rerankTimeAvg(), 0.00001);
    EXPECT_APPROX(2.0, stats.querySetupTimeAvg(), 0.00001);
    EXPECT_APPROX(1.0, stats.queryLatencyAvg(), 0.00001);
    stats.add(MatchingStats().matchTime(0.03).groupingTime(0.3).rerankTime(1.5).querySetupTime(6.0).queryLatency(3.0));
    EXPECT_APPROX(0.02, stats.matchTimeAvg(), 0.00001);
    EXPECT_APPROX(0.2, stats.groupingTimeAvg(), 0.00001);
    EXPECT_APPROX(1.0, stats.rerankTimeAvg(), 0.00001);
    EXPECT_APPROX(4.0, stats.querySetupTimeAvg(), 0.00001);
    EXPECT_APPROX(2.0, stats.queryLatencyAvg(), 0.00001);
    stats.add(MatchingStats().matchTime(0.05)
              .groupingTime(0.5)
              .rerankTime(2.5)
              .querySetupTime(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)
              .querySetupTime(10.0).querySetupTime(6.0)
              .queryLatency(5.0).queryLatency(3.0));
    EXPECT_APPROX(0.03, stats.matchTimeAvg(), 0.00001);
    EXPECT_APPROX(0.3, stats.groupingTimeAvg(), 0.00001);
    EXPECT_APPROX(1.5, stats.rerankTimeAvg(), 0.00001);
    EXPECT_APPROX(6.0, stats.querySetupTimeAvg(), 0.00001);
    EXPECT_APPROX(3.0, stats.queryLatencyAvg(), 0.00001);
    EXPECT_EQUAL(4u, stats.matchTimeCount());
    EXPECT_EQUAL(4u, stats.groupingTimeCount());
    EXPECT_EQUAL(4u, stats.rerankTimeCount());
    EXPECT_EQUAL(4u, stats.querySetupTimeCount());
    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.querySetupTimeMin(), 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.querySetupTimeMax(), 0.00001);
    EXPECT_APPROX(0.0, stats.queryLatencyMax(), 0.00001);
    stats.matchTime(0.01).groupingTime(0.1).rerankTime(0.5).querySetupTime(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.querySetupTimeMin(), 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.querySetupTimeMax(), 0.00001);
    EXPECT_APPROX(1.0, stats.queryLatencyMax(), 0.00001);
    stats.add(MatchingStats().matchTime(0.03).groupingTime(0.3).rerankTime(1.5).querySetupTime(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.querySetupTimeMin(), 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.querySetupTimeMax(), 0.00001);
    EXPECT_APPROX(3.0, stats.queryLatencyMax(), 0.00001);
    stats.add(MatchingStats().matchTime(0.05)
              .groupingTime(0.5)
              .rerankTime(2.5)
              .querySetupTime(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)
              .querySetupTime(10.0).querySetupTime(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.querySetupTimeMin(), 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.querySetupTimeMax(), 0.00001);
    EXPECT_APPROX(5.0, stats.queryLatencyMax(), 0.00001);
}

TEST("requireThatPartitionsAreAddedCorrectly") {
    MatchingStats all1;
    EXPECT_EQUAL(0u, all1.docidSpaceCovered());
    EXPECT_EQUAL(0u, all1.docsMatched());
    EXPECT_EQUAL(0u, all1.getNumPartitions());
    EXPECT_EQUAL(0u, all1.softDoomed());
    EXPECT_EQUAL(vespalib::duration::zero(), all1.doomOvertime());

    MatchingStats::Partition subPart;
    subPart.docsCovered(7).docsMatched(3).docsRanked(2).docsReRanked(1)
        .active_time(1.0).wait_time(0.5);
    EXPECT_EQUAL(0u, subPart.softDoomed());
    EXPECT_EQUAL(0u, subPart.softDoomed(false).softDoomed());
    EXPECT_EQUAL(1u, subPart.softDoomed(true).softDoomed());
    EXPECT_EQUAL(vespalib::duration::zero(), subPart.doomOvertime());
    EXPECT_EQUAL(1000ns, subPart.doomOvertime(1000ns).doomOvertime());
    EXPECT_EQUAL(7u, subPart.docsCovered());
    EXPECT_EQUAL(3u, subPart.docsMatched());
    EXPECT_EQUAL(2u, subPart.docsRanked());
    EXPECT_EQUAL(1u, subPart.docsReRanked());
    EXPECT_EQUAL(1.0, subPart.active_time_avg());
    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());
    EXPECT_EQUAL(3u, all1.docsMatched());
    EXPECT_EQUAL(2u, all1.docsRanked());
    EXPECT_EQUAL(1u, all1.docsReRanked());
    EXPECT_EQUAL(1u, all1.getNumPartitions());
    EXPECT_EQUAL(1u, all1.softDoomed());
    EXPECT_EQUAL(1000ns, all1.doomOvertime());
    EXPECT_EQUAL(7u, all1.getPartition(0).docsCovered());
    EXPECT_EQUAL(3u, all1.getPartition(0).docsMatched());
    EXPECT_EQUAL(2u, all1.getPartition(0).docsRanked());
    EXPECT_EQUAL(1u, 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(1u, all1.getPartition(0).active_time_count());
    EXPECT_EQUAL(1u, all1.getPartition(0).wait_time_count());
    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());
    EXPECT_EQUAL(1u, all1.getPartition(0).softDoomed());
    EXPECT_EQUAL(1000ns, all1.getPartition(0).doomOvertime());

    MatchingStats::Partition otherSubPart;
    otherSubPart.docsCovered(7).docsMatched(3).docsRanked(2).docsReRanked(1)
            .active_time(0.5).wait_time(1.0).softDoomed(true).doomOvertime(300ns);
    all1.merge_partition(otherSubPart, 1);
    EXPECT_EQUAL(1u, all1.softDoomed());
    EXPECT_EQUAL(1000ns, all1.doomOvertime());
    EXPECT_EQUAL(14u, all1.docidSpaceCovered());
    EXPECT_EQUAL(6u, all1.docsMatched());
    EXPECT_EQUAL(4u, all1.docsRanked());
    EXPECT_EQUAL(2u, all1.docsReRanked());
    EXPECT_EQUAL(2u, all1.getNumPartitions());
    EXPECT_EQUAL(3u, all1.getPartition(1).docsMatched());
    EXPECT_EQUAL(2u, all1.getPartition(1).docsRanked());
    EXPECT_EQUAL(1u, all1.getPartition(1).docsReRanked());
    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());
    EXPECT_EQUAL(1u, all1.getPartition(1).softDoomed());
    EXPECT_EQUAL(300ns, all1.getPartition(1).doomOvertime());

    MatchingStats all2;
    all2.merge_partition(otherSubPart, 0);
    all2.merge_partition(subPart, 1);

    all1.add(all2);
    EXPECT_EQUAL(2u, all1.softDoomed());
    EXPECT_EQUAL(1000ns, all1.doomOvertime());
    EXPECT_EQUAL(28u, all1.docidSpaceCovered());
    EXPECT_EQUAL(12u, all1.docsMatched());
    EXPECT_EQUAL(8u, all1.docsRanked());
    EXPECT_EQUAL(4u, all1.docsReRanked());
    EXPECT_EQUAL(2u, all1.getNumPartitions());
    EXPECT_EQUAL(6u, all1.getPartition(0).docsMatched());
    EXPECT_EQUAL(4u, all1.getPartition(0).docsRanked());
    EXPECT_EQUAL(2u, all1.getPartition(0).docsReRanked());
    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(2u, all1.getPartition(0).softDoomed());
    EXPECT_EQUAL(1000ns, all1.getPartition(0).doomOvertime());
    EXPECT_EQUAL(6u, all1.getPartition(1).docsMatched());
    EXPECT_EQUAL(4u, all1.getPartition(1).docsRanked());
    EXPECT_EQUAL(2u, all1.getPartition(1).docsReRanked());
    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());
    EXPECT_EQUAL(2u, all1.getPartition(1).softDoomed());
    EXPECT_EQUAL(1000ns, all1.getPartition(1).doomOvertime());
}

TEST("requireThatSoftDoomIsSetAndAdded") {
    MatchingStats stats;
    MatchingStats stats2;
    EXPECT_EQUAL(0ul, stats.softDoomed());
    EXPECT_EQUAL(0.5, stats.softDoomFactor());
    stats.softDoomFactor(0.7);
    stats.softDoomed(3);
    EXPECT_EQUAL(3ul, stats.softDoomed());
    EXPECT_EQUAL(0.7, stats.softDoomFactor());
    stats2.add(stats);
    EXPECT_EQUAL(3ul, stats2.softDoomed());
    EXPECT_EQUAL(0.5, stats2.softDoomFactor());  // Not affected by add
}

TEST("requireThatSoftDoomFacorIsComputedCorrectlyForDownAdjustment") {
    MatchingStats stats;
    EXPECT_EQUAL(0ul, stats.softDoomed());
    EXPECT_EQUAL(0.5, stats.softDoomFactor());
    stats.softDoomed(1);
    stats.updatesoftDoomFactor(1000ms, 500ms, 2000ms);
    EXPECT_EQUAL(1ul, stats.softDoomed());
    EXPECT_EQUAL(0.47, stats.softDoomFactor());
    stats.updatesoftDoomFactor(1000ms, 500ms, 2000ms);
    EXPECT_EQUAL(1ul, stats.softDoomed());
    EXPECT_EQUAL(0.44, stats.softDoomFactor());
    stats.updatesoftDoomFactor(900us, 500ms, 2000ms);   // hard limits less than 1ms should be ignored
    EXPECT_EQUAL(1ul, stats.softDoomed());
    EXPECT_EQUAL(0.44, stats.softDoomFactor());
    stats.updatesoftDoomFactor(1000ms, 900us, 2000ms);   // soft limits less than 1ms should be ignored
    EXPECT_EQUAL(1ul, stats.softDoomed());
    EXPECT_EQUAL(0.44, stats.softDoomFactor());
    stats.updatesoftDoomFactor(1000ms, 500ms, 10s);      // Prevent changes above 10%
    EXPECT_EQUAL(1ul, stats.softDoomed());
    EXPECT_EQUAL(0.396, stats.softDoomFactor());
}

TEST("requireThatSoftDoomFacorIsComputedCorrectlyForUpAdjustment") {
    MatchingStats stats;
    EXPECT_EQUAL(0ul, stats.softDoomed());
    EXPECT_EQUAL(0.5, stats.softDoomFactor());
    stats.softDoomed(1);
    stats.updatesoftDoomFactor(1s, 900ms, 100ms);
    EXPECT_EQUAL(1ul, stats.softDoomed());
    EXPECT_EQUAL(0.508, stats.softDoomFactor());
    stats.updatesoftDoomFactor(1s, 900ms, 100ms);
    EXPECT_EQUAL(1ul, stats.softDoomed());
    EXPECT_EQUAL(0.516, stats.softDoomFactor());
    stats.updatesoftDoomFactor(900us, 900ms, 100ms);   // hard limits less than 1ms should be ignored
    EXPECT_EQUAL(1ul, stats.softDoomed());
    EXPECT_EQUAL(0.516, stats.softDoomFactor());
    stats.updatesoftDoomFactor(1s, 900us, 100ms);   // soft limits less than 1ms should be ignored
    EXPECT_EQUAL(1ul, stats.softDoomed());
    EXPECT_EQUAL(0.516, stats.softDoomFactor());
    stats.softDoomFactor(0.1);
    stats.updatesoftDoomFactor(1s, 900ms, 1ms);      // Prevent changes above 5%
    EXPECT_EQUAL(1ul, stats.softDoomed());
    EXPECT_EQUAL(0.105, stats.softDoomFactor());
}

TEST("requireThatFactor is capped at minimum 1%") {
    MatchingStats stats;
    stats.softDoomFactor(0.01001);
    EXPECT_EQUAL(0.01001, stats.softDoomFactor());
    stats.updatesoftDoomFactor(1s, 500ms, 900ms);
    EXPECT_EQUAL(0.01, stats.softDoomFactor());
    stats.updatesoftDoomFactor(1s, 900ms, 1ms);
    EXPECT_EQUAL(0.0105, stats.softDoomFactor());
}

TEST_MAIN() {
    TEST_RUN_ALL();
}