Skip to content

Commit f2b59c0

Browse files
committed
Run microbenchmarks in Evergreen
1 parent 8c81c21 commit f2b59c0

File tree

11 files changed

+175
-66
lines changed

11 files changed

+175
-66
lines changed

.mci.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,16 @@ functions:
360360
CXX: ${cxx_compiler}
361361
script: .evergreen/compile.sh
362362

363+
"compile_benchmarks":
364+
- command: shell.exec
365+
params:
366+
shell: bash
367+
working_dir: "mongo-cxx-driver"
368+
script: |
369+
cd build
370+
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$(pwd)/../mongoc" -DCMAKE_CXX_STANDARD=20 ..
371+
make microbenchmarks -j64
372+
363373
"test":
364374
- command: shell.exec
365375
params:
@@ -510,6 +520,30 @@ functions:
510520
echo "Building Red Hat UBI Docker image"
511521
make -C extras/docker/redhat-ubi-9.3 nocachebuild test
512522
523+
"download benchmark data":
524+
- command: shell.exec
525+
params:
526+
shell: bash
527+
working_dir: "mongo-cxx-driver"
528+
script: |
529+
./etc/microbenchmark-test-data.sh
530+
531+
"run benchmarks":
532+
- command: shell.exec
533+
params:
534+
shell: bash
535+
working_dir: "mongo-cxx-driver"
536+
script: |
537+
echo "Starting benchmarks"
538+
./build/benchmark/microbenchmarks all
539+
540+
"send benchmarks":
541+
- command: perf.send
542+
params:
543+
name: perf
544+
file: mongo-cxx-driver/results.json
545+
546+
513547
#######################################
514548
# Post Task #
515549
#######################################
@@ -620,6 +654,16 @@ tasks:
620654
vars:
621655
ENABLE_TESTS: OFF
622656

657+
- name: compile_and_run_benchmarks
658+
commands:
659+
- func: "setup"
660+
- func: "start_mongod"
661+
- func: "fetch_c_driver_source"
662+
- func: "compile_benchmarks"
663+
- func: "download benchmark data"
664+
- func: "run benchmarks"
665+
- func: "send benchmarks"
666+
623667
- name: compile_macro_guard_tests
624668
commands:
625669
- func: "setup"
@@ -1303,6 +1347,15 @@ buildvariants:
13031347
- name: compile_and_test_with_shared_libs_sharded_cluster_with_libmongocrypt
13041348
- name: build_example_with_add_subdirectory
13051349

1350+
- name: benchmarks-rhel9
1351+
display_name: "Benchmarks (RHEL 9.2)"
1352+
expansions:
1353+
mongodb_version: "v6.0-perf"
1354+
run_on:
1355+
- rhel90-dbx-perf-large
1356+
tasks:
1357+
- name: compile_and_run_benchmarks
1358+
13061359
- name: arm-rhel9-release-latest
13071360
display_name: "arm64 RHEL 9 Release (MongoDB Latest)"
13081361
expansions:

benchmark/benchmark_runner.cpp

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414

1515
#include "benchmark_runner.hpp"
1616

17+
#include <chrono>
18+
#include <cstdint>
19+
#include <fstream>
20+
#include <iomanip>
21+
#include <iostream>
22+
#include <memory>
23+
#include <sstream>
24+
1725
#include "bson/bson_encoding.hpp"
1826
#include "multi_doc/bulk_insert.hpp"
1927
#include "multi_doc/find_many.hpp"
@@ -26,7 +34,13 @@
2634
#include "single_doc/find_one_by_id.hpp"
2735
#include "single_doc/insert_one.hpp"
2836
#include "single_doc/run_command.hpp"
37+
#include <bsoncxx/builder/basic/array.hpp>
38+
#include <bsoncxx/builder/basic/document.hpp>
39+
#include <bsoncxx/builder/basic/kvp.hpp>
40+
#include <bsoncxx/builder/basic/sub_document.hpp>
41+
#include <bsoncxx/json.hpp>
2942
#include <bsoncxx/stdx/make_unique.hpp>
43+
#include <bsoncxx/types.hpp>
3044

3145
namespace benchmark {
3246

@@ -47,26 +61,27 @@ benchmark_runner::benchmark_runner(std::set<benchmark_type> types) : _types{type
4761
_microbenches.push_back(make_unique<run_command>());
4862
_microbenches.push_back(make_unique<find_one_by_id>("single_and_multi_document/tweet.json"));
4963
_microbenches.push_back(make_unique<insert_one>(
50-
"TestSmallDocInsertOne", 2.75, 10000, "single_and_multi_document/small_doc.json"));
64+
"TestSmallDocInsertOne", 2.75, iterations, "single_and_multi_document/small_doc.json"));
5165
_microbenches.push_back(make_unique<insert_one>(
5266
"TestLargeDocInsertOne", 27.31, 10, "single_and_multi_document/large_doc.json"));
5367

5468
// Multi doc microbenchmarks
5569
_microbenches.push_back(make_unique<find_many>("single_and_multi_document/tweet.json"));
5670
_microbenches.push_back(make_unique<bulk_insert>(
57-
"TestSmallDocBulkInsert", 2.75, 10000, "single_and_multi_document/small_doc.json"));
71+
"TestSmallDocBulkInsert", 2.75, iterations, "single_and_multi_document/small_doc.json"));
5872
_microbenches.push_back(make_unique<bulk_insert>(
5973
"TestLargeDocBulkInsert", 27.31, 10, "single_and_multi_document/large_doc.json"));
60-
_microbenches.push_back(
61-
make_unique<gridfs_upload>("single_and_multi_document/gridfs_large.bin"));
62-
_microbenches.push_back(
63-
make_unique<gridfs_download>("single_and_multi_document/gridfs_large.bin"));
74+
// CXX-2794: Disable GridFS benchmarks due to long runtime
75+
// _microbenches.push_back(
76+
// make_unique<gridfs_upload>("single_and_multi_document/gridfs_large.bin"));
77+
// _microbenches.push_back(
78+
// make_unique<gridfs_download>("single_and_multi_document/gridfs_large.bin"));
6479

6580
// Parallel microbenchmarks
6681
_microbenches.push_back(make_unique<json_multi_import>("parallel/ldjson_multi"));
6782
_microbenches.push_back(make_unique<json_multi_export>("parallel/ldjson_multi"));
68-
_microbenches.push_back(make_unique<gridfs_multi_import>("parallel/gridfs_multi"));
69-
_microbenches.push_back(make_unique<gridfs_multi_export>("parallel/gridfs_multi"));
83+
// _microbenches.push_back(make_unique<gridfs_multi_import>("parallel/gridfs_multi"));
84+
// _microbenches.push_back(make_unique<gridfs_multi_export>("parallel/gridfs_multi"));
7085

7186
// Need to remove some
7287
if (!_types.empty()) {
@@ -89,8 +104,6 @@ benchmark_runner::benchmark_runner(std::set<benchmark_type> types) : _types{type
89104
}
90105

91106
void benchmark_runner::run_microbenches() {
92-
mongocxx::instance instance{};
93-
94107
for (std::unique_ptr<microbench>& bench : _microbenches) {
95108
std::cout << "Starting " << bench->get_name() << "..." << std::endl;
96109

@@ -145,20 +158,50 @@ double benchmark_runner::calculate_driver_bench_score() {
145158
return (calculate_read_bench_score() + calculate_write_bench_score()) / 2.0;
146159
}
147160

148-
void benchmark_runner::print_scores() {
161+
void benchmark_runner::write_scores(
162+
const std::chrono::time_point<std::chrono::system_clock> start_time) {
149163
double read = -1;
150164
double write = -1;
165+
const auto end_time = std::chrono::system_clock::now();
166+
167+
using namespace bsoncxx;
168+
using builder::basic::sub_document;
169+
170+
auto doc = builder::basic::document{};
171+
doc.append(kvp("info", [](sub_document subdoc) {
172+
subdoc.append(kvp("test_name", "C++ microbenchmarks"));
173+
}));
174+
175+
auto write_time =
176+
[](const std::chrono::time_point<std::chrono::system_clock> t) -> std::string {
177+
std::time_t t1 = std::chrono::system_clock::to_time_t(t);
178+
std::ostringstream oss;
179+
oss << std::put_time(std::gmtime(&t1), "%Y-%m-%dT%H:%M:%S") << "+00:00";
180+
return oss.str();
181+
};
182+
doc.append(kvp("created_at", write_time(start_time)));
183+
doc.append(kvp("completed_at", write_time(end_time)));
184+
doc.append(kvp("artifacts", builder::basic::make_array()));
185+
186+
auto metrics_array = builder::basic::array{};
187+
std::cout << std::endl << "Composite benchmarks:" << std::endl << "===========" << std::endl;
151188

152189
std::cout << "Individual microbenchmark scores:" << std::endl << "===========" << std::endl;
153190
for (auto&& bench : _microbenches) {
154191
auto& score = bench->get_results();
192+
const auto bench_time = static_cast<double>(score.get_percentile(50).count()) / 1000.0;
155193

156-
std::cout << bench->get_name() << ": "
157-
<< static_cast<double>(score.get_percentile(50).count()) / 1000.0
158-
<< " second(s) | " << score.get_score() << " MB/s" << std::endl;
159-
}
194+
std::cout << bench->get_name() << ": " << bench_time << " seconds | " << score.get_score()
195+
<< " MB/s" << std::endl;
160196

161-
std::cout << std::endl << "Composite benchmarks:" << std::endl << "===========" << std::endl;
197+
auto metric_doc = builder::basic::document{};
198+
metric_doc.append(kvp("name", bench->get_name()));
199+
metric_doc.append(kvp("type", "THROUGHPUT"));
200+
metric_doc.append(kvp("value", score.get_score()));
201+
metrics_array.append(metric_doc);
202+
}
203+
doc.append(kvp("metrics", metrics_array));
204+
doc.append(kvp("sub_tests", builder::basic::make_array()));
162205

163206
auto print_comp = [this, &read, &write](benchmark_type type) {
164207
double avg = calculate_average(type);
@@ -169,7 +212,7 @@ void benchmark_runner::print_scores() {
169212
write = avg;
170213
}
171214

172-
std::cout << type_names[type] << " " << avg << " MB/s" << std::endl;
215+
std::cout << type_names.at(type) << " " << avg << " MB/s" << std::endl;
173216
};
174217

175218
if (!_types.empty()) {
@@ -185,5 +228,8 @@ void benchmark_runner::print_scores() {
185228
if (read > 0 && write > 0) {
186229
std::cout << "DriverBench: " << (read + write) / 2.0 << " MB/s" << std::endl;
187230
}
231+
232+
std::ofstream os{"results.json"};
233+
os << '[' << bsoncxx::to_json(doc.view()) << ']';
188234
}
189235
} // namespace benchmark

benchmark/benchmark_runner.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414

1515
#pragma once
1616

17-
#include <bsoncxx/stdx/optional.hpp>
18-
#include <mongocxx/instance.hpp>
17+
#include <chrono>
1918

2019
#include "microbench.hpp"
20+
#include <bsoncxx/stdx/optional.hpp>
21+
#include <mongocxx/instance.hpp>
2122

2223
namespace benchmark {
2324

@@ -27,7 +28,7 @@ class benchmark_runner {
2728

2829
void run_microbenches();
2930

30-
void print_scores();
31+
void write_scores(const std::chrono::time_point<std::chrono::system_clock> start_time);
3132

3233
double calculate_bson_bench_score();
3334

benchmark/bson/bson_decoding.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ void bson_decoding::setup() {
4242
}
4343

4444
void bson_decoding::task() {
45-
for (std::uint32_t i = 0; i < 10000; i++) {
45+
for (std::uint32_t i = 0; i < iterations; i++) {
4646
// TODO CXX-1241: call bson_as_extended json on _json.
4747
}
4848
}

benchmark/bson/bson_encoding.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616

1717
#include <iostream>
1818

19+
#include "../microbench.hpp"
1920
#include <bsoncxx/json.hpp>
2021
#include <bsoncxx/types.hpp>
2122

22-
#include "../microbench.hpp"
23-
2423
namespace benchmark {
2524

2625
class bson_encoding : public microbench {
@@ -58,7 +57,7 @@ void visit_document(bsoncxx::document::view doc) {
5857

5958
// Mirroring mongo-c-driver's interpretation of the spec.
6059
void bson_encoding::task() {
61-
for (std::uint32_t i = 0; i < 10000; i++) {
60+
for (std::uint32_t i = 0; i < iterations; i++) {
6261
visit_document(_doc->view());
6362
}
6463
}

benchmark/main.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,34 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
#include <chrono>
1516
#include <iostream>
1617

1718
#include "benchmark_runner.hpp"
19+
#include <bsoncxx/stdx/string_view.hpp>
20+
#include <mongocxx/instance.hpp>
1821

1922
using namespace benchmark;
2023

2124
int main(int argc, char* argv[]) {
25+
mongocxx::instance instance{};
2226
std::set<benchmark_type> types;
2327

2428
if (argc > 1) {
25-
for (int x = 1; x < argc; ++x) {
26-
std::string type{argv[x]};
27-
auto it = names_types.find(type);
28-
29-
if (it != names_types.end()) {
30-
types.insert(it->second);
31-
} else {
32-
std::cerr << "Invalid benchmark: " << type << std::endl;
29+
if (bsoncxx::stdx::string_view(argv[1]) == "all") {
30+
for (const auto& [name, type] : names_types) {
31+
types.insert(type);
32+
}
33+
} else {
34+
for (int x = 1; x < argc; ++x) {
35+
std::string type{argv[x]};
36+
auto it = names_types.find(type);
37+
38+
if (it != names_types.end()) {
39+
types.insert(it->second);
40+
} else {
41+
std::cerr << "Invalid benchmark: " << type << std::endl;
42+
}
3343
}
3444
}
3545

@@ -40,6 +50,8 @@ int main(int argc, char* argv[]) {
4050
}
4151

4252
benchmark_runner runner{types};
53+
54+
const auto start_time = std::chrono::system_clock::now();
4355
runner.run_microbenches();
44-
runner.print_scores();
56+
runner.write_scores(start_time);
4557
}

benchmark/microbench.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace benchmark {
2323

2424
bool finished_running(const std::chrono::duration<std::uint32_t, std::milli>& curr_time,
2525
std::uint32_t iter) {
26-
return (curr_time > maxtime || (curr_time > mintime && iter > MAX_ITER));
26+
return (curr_time > maxtime || (curr_time > mintime && iter > max_iter));
2727
}
2828

2929
void microbench::run() {

0 commit comments

Comments
 (0)