Skip to content

Commit f8eae6f

Browse files
yfeldblumfacebook-github-bot
authored andcommitted
address sporadic timing-related failures in benchmark test
Summary: Testing that some elapsed time period has an upper bound can have flaky results. Try multiple times, take the median of elapsed time periods, and then test that the median has an upper bound. The intention is reduce the likelihood of flakiness. Reviewed By: Orvid Differential Revision: D78906079 fbshipit-source-id: ad6ee41b35674b133f3ac70a7332731d5cdf2857
1 parent 9d8387e commit f8eae6f

File tree

1 file changed

+75
-23
lines changed

1 file changed

+75
-23
lines changed

fatal/benchmark/test/benchmark_test.cpp

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <iostream>
1616
#include <map>
1717
#include <string>
18+
#include <sstream>
1819
#include <thread>
1920

2021
#include <cassert>
@@ -84,41 +85,92 @@ FATAL_BENCHMARK(group_2, benchmark_2_4) {
8485
}
8586

8687
FATAL_TEST(benchmark, sanity_check) {
87-
std::map<std::string, std::map<std::string, duration>> metrics;
88+
struct state {
89+
std::ostringstream cout;
90+
results metrics;
91+
std::thread thread;
8892

89-
for (auto const &i: run(std::cout)) {
90-
auto &group = metrics[i.first];
93+
void run_one() {
94+
metrics = run(cout);
95+
}
96+
};
97+
auto states = std::vector<state>(12);
9198

92-
for (auto const &j: i.second) {
93-
FATAL_ASSERT_EQ(group.end(), group.find(j.name()));
99+
for (auto &st : states) {
100+
st.thread = std::thread(std::bind(&state::run_one, std::ref(st)));
101+
}
102+
for (auto &st : states) {
103+
st.thread.join();
104+
}
94105

95-
group[j.name()] = j.period();
106+
for (auto &st : states) {
107+
std::cout << st.cout.str();
108+
109+
for (auto const &i: st.metrics) {
110+
auto const &grp = i.second;
111+
std::vector<std::string> names;
112+
auto const txfm = std::bind(&result_entry::name, std::placeholders::_1);
113+
std::transform(grp.begin(), grp.end(), std::back_inserter(names), txfm);
114+
std::sort(names.begin(), names.end());
115+
auto const adj = std::adjacent_find(names.begin(), names.end());
116+
FATAL_ASSERT_EQ(adj, names.end());
96117
}
97118
}
98119

99-
auto get = [&](std::string group, std::string name) {
100-
auto i = metrics.find(group);
101-
assert(i != metrics.end());
120+
auto get_min = [&](std::string const &group, std::string const &name) {
121+
auto min = duration{};
122+
for (auto const &st : states) {
123+
auto const i = st.metrics.find(group);
124+
assert(i != st.metrics.end());
125+
auto const &grp = i->second;
126+
127+
auto const pred = [&](auto const &it) { return it.name() == name; };
128+
auto const j = std::find_if(grp.begin(), grp.end(), pred);
129+
assert(j != i->second.end());
130+
131+
min = std::max(min, j->period());
132+
}
133+
return min;
134+
};
135+
136+
auto get_med = [&](std::string const &group, std::string const &name) {
137+
std::vector<duration> periods;
138+
for (auto const &st : states) {
139+
auto const i = st.metrics.find(group);
140+
assert(i != st.metrics.end());
141+
auto const &grp = i->second;
102142

103-
auto j = i->second.find(name);
104-
assert(j != i->second.end());
143+
auto const pred = [&](auto const &it) { return it.name() == name; };
144+
auto const j = std::find_if(grp.begin(), grp.end(), pred);
145+
assert(j != i->second.end());
105146

106-
return j->second;
147+
periods.push_back(j->period());
148+
}
149+
150+
assert(!periods.empty());
151+
std::sort(periods.begin(), periods.end());
152+
if (periods.size() % 2 == 1) {
153+
return periods[periods.size() / 2];
154+
} else {
155+
auto const m0 = periods[periods.size() / 2 - 1];
156+
auto const m1 = periods[periods.size() / 2 - 0];
157+
return (m0 + m1) / 2;
158+
}
107159
};
108160

109161
FATAL_ASSERT_LT(small_delay, big_delay);
110162

111-
FATAL_EXPECT_LT(get("group_1", "benchmark_1_1"), small_delay);
112-
FATAL_EXPECT_GE(get("group_1", "benchmark_1_2"), big_delay);
113-
FATAL_EXPECT_LT(get("group_1", "benchmark_1_3"), small_delay);
114-
FATAL_EXPECT_GE(get("group_1", "benchmark_1_4"), big_delay);
115-
FATAL_EXPECT_LT(get("group_1", "benchmark_1_5"), small_delay);
116-
117-
FATAL_EXPECT_LT(get("group_2", "benchmark_2_1"), big_delay);
118-
FATAL_EXPECT_GE(get("group_2", "benchmark_2_1"), small_delay);
119-
FATAL_EXPECT_LT(get("group_2", "benchmark_2_2"), small_delay);
120-
FATAL_EXPECT_GE(get("group_2", "benchmark_2_3"), big_delay);
121-
FATAL_EXPECT_LT(get("group_2", "benchmark_2_4"), small_delay);
163+
FATAL_EXPECT_LT(get_med("group_1", "benchmark_1_1"), small_delay);
164+
FATAL_EXPECT_GE(get_min("group_1", "benchmark_1_2"), big_delay);
165+
FATAL_EXPECT_LT(get_med("group_1", "benchmark_1_3"), small_delay);
166+
FATAL_EXPECT_GE(get_min("group_1", "benchmark_1_4"), big_delay);
167+
FATAL_EXPECT_LT(get_med("group_1", "benchmark_1_5"), small_delay);
168+
169+
FATAL_EXPECT_LT(get_med("group_2", "benchmark_2_1"), big_delay);
170+
FATAL_EXPECT_GE(get_min("group_2", "benchmark_2_1"), small_delay);
171+
FATAL_EXPECT_LT(get_med("group_2", "benchmark_2_2"), small_delay);
172+
FATAL_EXPECT_GE(get_min("group_2", "benchmark_2_3"), big_delay);
173+
FATAL_EXPECT_LT(get_med("group_2", "benchmark_2_4"), small_delay);
122174
}
123175

124176
} // namespace benchmark {

0 commit comments

Comments
 (0)