benchmark/test/benchmark_random_interleaving_gtest.cc
haih-g a6a738c1cc
Implementation of random interleaving. (#1105)
* Implementation of random interleaving. See
http://github.com/google/benchmark/issues/1051 for the feature requests.

Committer: Hai Huang (http://github.com/haih-g)

On branch fr-1051
Changes to be committed:
modified:   include/benchmark/benchmark.h
modified:   src/benchmark.cc
new file:   src/benchmark_adjust_repetitions.cc
new file:   src/benchmark_adjust_repetitions.h
modified:   src/benchmark_api_internal.cc
modified:   src/benchmark_api_internal.h
modified:   src/benchmark_register.cc
modified:   src/benchmark_runner.cc
modified:   src/benchmark_runner.h
modified:   test/CMakeLists.txt
new file:   test/benchmark_random_interleaving_gtest.cc

* Fix benchmark_random_interleaving_gtest.cc for fr-1051

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark.cc
modified:   src/benchmark_runner.cc
modified:   test/benchmark_random_interleaving_gtest.cc

* Fix macos build for fr-1051

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark_api_internal.cc
modified:   src/benchmark_api_internal.h
modified:   src/benchmark_runner.cc

* Fix macos and windows build for fr-1051.

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark_runner.cc

* Fix benchmark_random_interleaving_test.cc for macos and windows in fr-1051

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   test/benchmark_random_interleaving_gtest.cc

* Fix int type benchmark_random_interleaving_gtest for macos in fr-1051

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   test/benchmark_random_interleaving_gtest.cc

* Address dominichamon's comments 03/29 for fr-1051

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark.cc
modified:   src/benchmark_api_internal.cc
modified:   src/benchmark_api_internal.h
modified:   test/benchmark_random_interleaving_gtest.cc

* Address dominichamon's comment on default min_time / repetitions for fr-1051.
Also change sentinel of random_interleaving_repetitions to -1. Hopefully it
fixes the failures on Windows.

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark.cc
modified:   src/benchmark_api_internal.cc
modified:   src/benchmark_api_internal.h

* Fix windows test failures for fr-1051

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark_api_internal.cc
modified:   src/benchmark_runner.cc

* Add license blurb for fr-1051.

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark_adjust_repetitions.cc
modified:   src/benchmark_adjust_repetitions.h

* Switch to std::shuffle() for fr-1105.

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark.cc

* Change to 1e-9 in fr-1105

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark_adjust_repetitions.cc

* Fix broken build caused by bad merge for fr-1105.

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark_api_internal.cc
modified:   src/benchmark_runner.cc

* Fix build breakage for fr-1051.

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark.cc
modified:   src/benchmark_api_internal.cc
modified:   src/benchmark_api_internal.h
modified:   src/benchmark_register.cc
modified:   src/benchmark_runner.cc

* Print out reports as they come in if random interleaving is disabled (fr-1051)

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark.cc

* size_t, int64_t --> int in benchmark_runner for fr-1051.

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark_runner.cc
modified:   src/benchmark_runner.h

* Address comments from dominichamon for fr-1051

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark.cc
modified:   src/benchmark_adjust_repetitions.cc
modified:   src/benchmark_adjust_repetitions.h
modified:   src/benchmark_api_internal.cc
modified:   src/benchmark_api_internal.h
modified:   test/benchmark_random_interleaving_gtest.cc

* benchmar_indices --> size_t to make CI pass: fr-1051

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark.cc

* Fix min_time not initialized issue for fr-1051.

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark_api_internal.cc
modified:   src/benchmark_api_internal.h

* min_time --> MinTime in fr-1051.

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   src/benchmark_api_internal.cc
modified:   src/benchmark_api_internal.h
modified:   src/benchmark_runner.cc

* Add doc for random interleaving for fr-1051

Committer: Hai Huang <haih@google.com>

On branch fr-1051
Your branch is up to date with 'origin/fr-1051'.

Changes to be committed:
modified:   README.md
new file:   docs/random_interleaving.md

Co-authored-by: Dominic Hamon <dominichamon@users.noreply.github.com>
2021-05-20 17:09:16 +01:00

272 lines
9.0 KiB
C++

#include <queue>
#include <string>
#include <vector>
#include "../src/benchmark_adjust_repetitions.h"
#include "../src/string_util.h"
#include "benchmark/benchmark.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
DECLARE_bool(benchmark_enable_random_interleaving);
DECLARE_string(benchmark_filter);
DECLARE_double(benchmark_random_interleaving_max_overhead);
namespace do_not_read_flag_directly {
DECLARE_int32(benchmark_repetitions);
} // namespace do_not_read_flag_directly
namespace benchmark {
namespace internal {
namespace {
class EventQueue : public std::queue<std::string> {
public:
void Put(const std::string& event) {
push(event);
}
void Clear() {
while (!empty()) {
pop();
}
}
std::string Get() {
std::string event = front();
pop();
return event;
}
};
static EventQueue* queue = new EventQueue;
class NullReporter : public BenchmarkReporter {
public:
bool ReportContext(const Context& /*context*/) override {
return true;
}
void ReportRuns(const std::vector<Run>& /* report */) override {}
};
class BenchmarkTest : public testing::Test {
public:
static void SetupHook(int /* num_threads */) { queue->push("Setup"); }
static void TeardownHook(int /* num_threads */) { queue->push("Teardown"); }
void Execute(const std::string& pattern) {
queue->Clear();
BenchmarkReporter* reporter = new NullReporter;
FLAGS_benchmark_filter = pattern;
RunSpecifiedBenchmarks(reporter);
delete reporter;
queue->Put("DONE"); // End marker
}
};
static void BM_Match1(benchmark::State& state) {
const int64_t arg = state.range(0);
for (auto _ : state) {}
queue->Put(StrFormat("BM_Match1/%d", static_cast<int>(arg)));
}
BENCHMARK(BM_Match1)
->Iterations(100)
->Arg(1)
->Arg(2)
->Arg(3)
->Range(10, 80)
->Args({90})
->Args({100});
static void BM_MatchOverhead(benchmark::State& state) {
const int64_t arg = state.range(0);
for (auto _ : state) {}
queue->Put(StrFormat("BM_MatchOverhead/%d", static_cast<int>(arg)));
}
BENCHMARK(BM_MatchOverhead)
->Iterations(100)
->Arg(64)
->Arg(80);
TEST_F(BenchmarkTest, Match1) {
Execute("BM_Match1");
ASSERT_EQ("BM_Match1/1", queue->Get());
ASSERT_EQ("BM_Match1/2", queue->Get());
ASSERT_EQ("BM_Match1/3", queue->Get());
ASSERT_EQ("BM_Match1/10", queue->Get());
ASSERT_EQ("BM_Match1/64", queue->Get());
ASSERT_EQ("BM_Match1/80", queue->Get());
ASSERT_EQ("BM_Match1/90", queue->Get());
ASSERT_EQ("BM_Match1/100", queue->Get());
ASSERT_EQ("DONE", queue->Get());
}
TEST_F(BenchmarkTest, Match1WithRepetition) {
do_not_read_flag_directly::FLAGS_benchmark_repetitions = 2;
Execute("BM_Match1/(64|80)");
ASSERT_EQ("BM_Match1/64", queue->Get());
ASSERT_EQ("BM_Match1/64", queue->Get());
ASSERT_EQ("BM_Match1/80", queue->Get());
ASSERT_EQ("BM_Match1/80", queue->Get());
ASSERT_EQ("DONE", queue->Get());
}
TEST_F(BenchmarkTest, Match1WithRandomInterleaving) {
FLAGS_benchmark_enable_random_interleaving = true;
do_not_read_flag_directly::FLAGS_benchmark_repetitions = 100;
FLAGS_benchmark_random_interleaving_max_overhead =
std::numeric_limits<double>::infinity();
std::vector<std::string> expected({"BM_Match1/64", "BM_Match1/80"});
std::map<std::string, int> interleaving_count;
Execute("BM_Match1/(64|80)");
for (int i = 0; i < 100; ++i) {
std::vector<std::string> interleaving;
interleaving.push_back(queue->Get());
interleaving.push_back(queue->Get());
EXPECT_THAT(interleaving, testing::UnorderedElementsAreArray(expected));
interleaving_count[StrFormat("%s,%s", interleaving[0].c_str(),
interleaving[1].c_str())]++;
}
EXPECT_GE(interleaving_count.size(), 2) << "Interleaving was not randomized.";
ASSERT_EQ("DONE", queue->Get());
}
TEST_F(BenchmarkTest, Match1WithRandomInterleavingAndZeroOverhead) {
FLAGS_benchmark_enable_random_interleaving = true;
do_not_read_flag_directly::FLAGS_benchmark_repetitions = 100;
FLAGS_benchmark_random_interleaving_max_overhead = 0;
// ComputeRandomInterleavingRepetitions() will kick in and rerun each
// benchmark once with increased iterations. Then number of repetitions will
// be reduced to < 100. The first 4 executions should be
// 2 x BM_MatchOverhead/64 and 2 x BM_MatchOverhead/80.
std::vector<std::string> expected(
{"BM_MatchOverhead/64", "BM_MatchOverhead/80", "BM_MatchOverhead/64",
"BM_MatchOverhead/80"});
std::map<std::string, int> interleaving_count;
Execute("BM_MatchOverhead/(64|80)");
std::vector<std::string> interleaving;
interleaving.push_back(queue->Get());
interleaving.push_back(queue->Get());
interleaving.push_back(queue->Get());
interleaving.push_back(queue->Get());
EXPECT_THAT(interleaving, testing::UnorderedElementsAreArray(expected));
ASSERT_LT(queue->size(), 100) << "# Repetitions was not reduced to < 100.";
}
InternalRandomInterleavingRepetitionsInput CreateInput(
double total, double time, double real_time, double min_time,
double overhead, int repetitions) {
InternalRandomInterleavingRepetitionsInput input;
input.total_execution_time_per_repetition = total;
input.time_used_per_repetition = time;
input.real_time_used_per_repetition = real_time;
input.min_time_per_repetition = min_time;
input.max_overhead = overhead;
input.max_repetitions = repetitions;
return input;
}
TEST(Benchmark, ComputeRandomInterleavingRepetitions) {
// On wall clock time.
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.05, 0.05, 0.05, 0.05, 0.0, 10)),
10);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.05, 0.05, 0.05, 0.05, 0.4, 10)),
10);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.06, 0.05, 0.05, 0.05, 0.0, 10)),
8);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.06, 0.05, 0.05, 0.05, 0.4, 10)),
10);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.08, 0.05, 0.05, 0.05, 0.0, 10)),
6);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.08, 0.05, 0.05, 0.05, 0.4, 10)),
9);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.26, 0.25, 0.25, 0.05, 0.0, 10)),
2);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.25, 0.25, 0.25, 0.05, 0.4, 10)),
3);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.26, 0.25, 0.25, 0.05, 0.0, 10)),
2);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.26, 0.25, 0.25, 0.05, 0.4, 10)),
3);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.38, 0.25, 0.25, 0.05, 0.0, 10)),
2);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.38, 0.25, 0.25, 0.05, 0.4, 10)),
3);
// On CPU time.
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.1, 0.05, 0.1, 0.05, 0.0, 10)),
10);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.1, 0.05, 0.1, 0.05, 0.4, 10)),
10);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.11, 0.05, 0.1, 0.05, 0.0, 10)),
9);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.11, 0.05, 0.1, 0.05, 0.4, 10)),
10);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.15, 0.05, 0.1, 0.05, 0.0, 10)),
7);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.15, 0.05, 0.1, 0.05, 0.4, 10)),
9);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.5, 0.25, 0.5, 0.05, 0.0, 10)),
2);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.5, 0.25, 0.5, 0.05, 0.4, 10)),
3);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.51, 0.25, 0.5, 0.05, 0.0, 10)),
2);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.51, 0.25, 0.5, 0.05, 0.4, 10)),
3);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.8, 0.25, 0.5, 0.05, 0.0, 10)),
2);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.8, 0.25, 0.5, 0.05, 0.4, 10)),
2);
// Corner cases.
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.0, 0.25, 0.5, 0.05, 0.4, 10)),
3);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.8, 0.0, 0.5, 0.05, 0.4, 10)),
9);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.8, 0.25, 0.0, 0.05, 0.4, 10)),
1);
EXPECT_EQ(ComputeRandomInterleavingRepetitions(
CreateInput(0.8, 0.25, 0.5, 0.0, 0.4, 10)),
1);
}
} // namespace
} // namespace internal
} // namespace benchmark