Skip to content

Commit a9f0ce4

Browse files
committed
[benchmark] Fix quantile estimation type
The correct quantile estimation type for printing all measurements in the summary report while `quantile == num-samples - 1` is R-1, SAS-3. It's the inverse of empirical distribution function. References: * https://en.wikipedia.org/wiki/Quantile#Estimating_quantiles_from_a_sample * discussion in #19097 (comment)
1 parent 541c48f commit a9f0ce4

File tree

3 files changed

+21
-16
lines changed

3 files changed

+21
-16
lines changed

benchmark/scripts/compare_perf_tests.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ class `ReportFormatter` creates the test comparison report in specified format.
3434
import sys
3535
from bisect import bisect, bisect_left, bisect_right
3636
from collections import namedtuple
37-
from decimal import Decimal, ROUND_HALF_EVEN
38-
from math import sqrt
37+
from math import ceil, sqrt
3938

4039

4140
class Sample(namedtuple('Sample', 'i num_iters runtime')):
@@ -143,15 +142,12 @@ def max(self):
143142
return self.samples[-1].runtime
144143

145144
def quantile(self, q):
146-
"""Return runtime of a sample nearest to the quantile.
145+
"""Return runtime for given quantile.
147146
148-
Explicitly uses round-half-to-even rounding algorithm to match the
149-
behavior of numpy's quantile(interpolation='nearest') and quantile
150-
estimate type R-3, SAS-2. See:
147+
Equivalent to quantile estimate type R-1, SAS-3. See:
151148
https://en.wikipedia.org/wiki/Quantile#Estimating_quantiles_from_a_sample
152149
"""
153-
index = int(Decimal((self.count - 1) * Decimal(q))
154-
.quantize(0, ROUND_HALF_EVEN))
150+
index = max(0, int(ceil(self.count * float(q))) - 1)
155151
return self.samples[index].runtime
156152

157153
@property

benchmark/scripts/test_compare_perf_tests.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,17 @@ def test_stores_samples(self):
6262
self.assertEquals(s.num_iters, 42)
6363
self.assertEquals(s.runtime, 1000)
6464

65+
def test_quantile(self):
66+
self.assertEquals(self.samples.quantile(1), 1000)
67+
self.assertEquals(self.samples.quantile(0), 1000)
68+
self.samples.add(Sample(2, 1, 1100))
69+
self.assertEquals(self.samples.quantile(0), 1000)
70+
self.assertEquals(self.samples.quantile(1), 1100)
71+
self.samples.add(Sample(3, 1, 1050))
72+
self.assertEquals(self.samples.quantile(0), 1000)
73+
self.assertEquals(self.samples.quantile(.5), 1050)
74+
self.assertEquals(self.samples.quantile(1), 1100)
75+
6576
def assertEqualFiveNumberSummary(self, ss, expected_fns):
6677
e_min, e_q1, e_median, e_q3, e_max = expected_fns
6778
self.assertEquals(ss.min, e_min)
@@ -81,7 +92,7 @@ def test_computes_five_number_summary(self):
8192
self.samples, (1000, 1000, 1050, 1100, 1100))
8293
self.samples.add(Sample(4, 1, 1025))
8394
self.assertEqualFiveNumberSummary(
84-
self.samples, (1000, 1025, 1050, 1050, 1100))
95+
self.samples, (1000, 1000, 1025, 1050, 1100))
8596
self.samples.add(Sample(5, 1, 1075))
8697
self.assertEqualFiveNumberSummary(
8798
self.samples, (1000, 1025, 1050, 1075, 1100))
@@ -447,7 +458,7 @@ def test_results_from_merge_verbose(self):
447458
self.assertTrue(isinstance(result, PerformanceTestResult))
448459
self.assertEquals(result.min, 350815)
449460
self.assertEquals(result.max, 376131)
450-
self.assertEquals(result.median, 363094)
461+
self.assertEquals(result.median, 358817)
451462
self.assertAlmostEquals(result.sd, 8443.37, places=2)
452463
self.assertAlmostEquals(result.mean, 361463.25, places=2)
453464
self.assertEquals(result.num_samples, 8)

benchmark/utils/DriverUtils.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,13 @@ struct BenchResults {
3131
self.stats = self.samples.reduce(into: Stats(), Stats.collect)
3232
}
3333

34-
/// Return sample at index nearest to the `quantile`.
34+
/// Return measured value for given `quantile`.
3535
///
36-
/// Explicitly uses round-half-to-even rounding algorithm to match the
37-
/// behavior of numpy's quantile(interpolation='nearest') and quantile
38-
/// estimate type R-3, SAS-2. See:
36+
/// Equivalent to quantile estimate type R-1, SAS-3. See:
3937
/// https://en.wikipedia.org/wiki/Quantile#Estimating_quantiles_from_a_sample
4038
subscript(_ quantile: Double) -> T {
41-
let index = Int(
42-
(Double(samples.count - 1) * quantile).rounded(.toNearestOrEven))
39+
let index = Swift.max(0,
40+
Int((Double(samples.count) * quantile).rounded(.up)) - 1)
4341
return samples[index]
4442
}
4543

0 commit comments

Comments
 (0)