summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Fefer <ivan.fefer@mongodb.com>2022-09-21 15:57:14 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-09-21 17:25:41 +0000
commit3aa324accc64c532f53983258b4c7624b0b0158c (patch)
tree51fc3643aa0d4c14d79b55196964a4f37c665b63
parent6f450a3cea6287612329f44e90536d72fe7c16c5 (diff)
downloadmongo-3aa324accc64c532f53983258b4c7624b0b0158c.tar.gz
SERVER-69798: Add benchmark for SBE expressions
-rw-r--r--buildscripts/resmokeconfig/suites/benchmarks.yml3
-rw-r--r--buildscripts/resmokeconfig/suites/benchmarks_expression.yml14
-rw-r--r--buildscripts/resmokeconfig/suites/benchmarks_expression_sbe.yml14
-rw-r--r--etc/evergreen_yml_components/definitions.yml24
-rw-r--r--src/mongo/db/pipeline/SConscript19
-rw-r--r--src/mongo/db/pipeline/expression_bm.cpp499
-rw-r--r--src/mongo/db/pipeline/expression_bm_fixture.cpp446
-rw-r--r--src/mongo/db/pipeline/expression_bm_fixture.h251
-rw-r--r--src/mongo/db/query/SConscript16
-rw-r--r--src/mongo/db/query/sbe_expression_bm.cpp147
10 files changed, 957 insertions, 476 deletions
diff --git a/buildscripts/resmokeconfig/suites/benchmarks.yml b/buildscripts/resmokeconfig/suites/benchmarks.yml
index 5bbd6e460ef..e4cb3c6b7aa 100644
--- a/buildscripts/resmokeconfig/suites/benchmarks.yml
+++ b/buildscripts/resmokeconfig/suites/benchmarks.yml
@@ -18,6 +18,9 @@ selector:
- build/install/bin/simple8b_bm*
# Hash table benchmark is really slow, don't run on evergreen
- build/install/bin/hash_table_bm*
+ # These benchmarks are being run as part of the benchmarks_expression*.yml
+ - build/install/bin/expression_bm*
+ - build/install/bin/sbe_expression_bm*
executor:
diff --git a/buildscripts/resmokeconfig/suites/benchmarks_expression.yml b/buildscripts/resmokeconfig/suites/benchmarks_expression.yml
new file mode 100644
index 00000000000..809ab75b036
--- /dev/null
+++ b/buildscripts/resmokeconfig/suites/benchmarks_expression.yml
@@ -0,0 +1,14 @@
+# This benchmark measures the performance of expressions in classic engine.
+test_kind: benchmark_test
+
+selector:
+ root: build/benchmarks.txt
+ include_files:
+ # The trailing asterisk is for handling the .exe extension on Windows.
+ - build/**/system_resource_canary_bm*
+ - build/install/bin/expression_bm*
+
+executor:
+ config: {}
+ hooks:
+ - class: CombineBenchmarkResults
diff --git a/buildscripts/resmokeconfig/suites/benchmarks_expression_sbe.yml b/buildscripts/resmokeconfig/suites/benchmarks_expression_sbe.yml
new file mode 100644
index 00000000000..3661db88c3d
--- /dev/null
+++ b/buildscripts/resmokeconfig/suites/benchmarks_expression_sbe.yml
@@ -0,0 +1,14 @@
+# This benchmark measures the performance of expressions in SBE.
+test_kind: benchmark_test
+
+selector:
+ root: build/benchmarks.txt
+ include_files:
+ # The trailing asterisk is for handling the .exe extension on Windows.
+ - build/**/system_resource_canary_bm*
+ - build/install/bin/sbe_expression_bm*
+
+executor:
+ config: {}
+ hooks:
+ - class: CombineBenchmarkResults
diff --git a/etc/evergreen_yml_components/definitions.yml b/etc/evergreen_yml_components/definitions.yml
index b89ac1a9fba..7d61b70bac7 100644
--- a/etc/evergreen_yml_components/definitions.yml
+++ b/etc/evergreen_yml_components/definitions.yml
@@ -3456,6 +3456,30 @@ tasks:
# - func: "send benchmark results"
# - func: "analyze benchmark results"
+- <<: *benchmark_template
+ name: benchmarks_expression
+ tags: ["benchmarks"]
+ commands:
+ - func: "do benchmark setup"
+ - func: "run tests"
+ vars:
+ suite: benchmarks_expression
+ exec_timeout_secs: 18000 # 5 hour timeout.
+ resmoke_jobs_max: 1
+ - func: "send benchmark results"
+
+- <<: *benchmark_template
+ name: benchmarks_expression_sbe
+ tags: ["benchmarks"]
+ commands:
+ - func: "do benchmark setup"
+ - func: "run tests"
+ vars:
+ suite: benchmarks_expression_sbe
+ exec_timeout_secs: 18000 # 5 hour timeout.
+ resmoke_jobs_max: 1
+ - func: "send benchmark results"
+
- <<: *run_jepsen_template
name: jepsen_register_findAndModify
tags: ["jepsen"]
diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript
index bca0ed04164..e3ef1f3b6e6 100644
--- a/src/mongo/db/pipeline/SConscript
+++ b/src/mongo/db/pipeline/SConscript
@@ -647,6 +647,21 @@ env.CppUnitTest(
],
)
+bmEnv = env.Clone()
+bmEnv.InjectThirdParty(libraries=["benchmark"])
+
+bmEnv.Library(
+ target='expression_bm_fixture',
+ source=[
+ 'expression_bm_fixture.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/exec/document_value/document_value',
+ '$BUILD_DIR/third_party/shim_benchmark',
+ ],
+)
+
env.Benchmark(
target='expression_bm',
source=[
@@ -654,7 +669,7 @@ env.Benchmark(
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/query/query_test_service_context',
- '$BUILD_DIR/mongo/db/query_expressions',
- '$BUILD_DIR/mongo/db/service_context_test_fixture',
+ '$BUILD_DIR/mongo/db/query_expressions', '$BUILD_DIR/mongo/db/service_context_test_fixture',
+ 'expression_bm_fixture'
],
)
diff --git a/src/mongo/db/pipeline/expression_bm.cpp b/src/mongo/db/pipeline/expression_bm.cpp
index 0d2a2e798c3..001d0d9b6f8 100644
--- a/src/mongo/db/pipeline/expression_bm.cpp
+++ b/src/mongo/db/pipeline/expression_bm.cpp
@@ -33,487 +33,42 @@
#include "mongo/db/matcher/expression_parser.h"
#include "mongo/db/pipeline/expression.h"
+#include "mongo/db/pipeline/expression_bm_fixture.h"
#include "mongo/db/pipeline/expression_context_for_test.h"
#include "mongo/db/query/query_test_service_context.h"
namespace mongo {
namespace {
-void benchmarkExpression(BSONObj expressionSpec,
- benchmark::State& state,
- const std::vector<Document>& documents) {
- QueryTestServiceContext testServiceContext;
- auto opContext = testServiceContext.makeOperationContext();
- NamespaceString nss("test.bm");
- auto exprContext = make_intrusive<ExpressionContextForTest>(opContext.get(), nss);
- // Build an expression.
- auto expression = Expression::parseExpression(
- exprContext.get(), expressionSpec, exprContext->variablesParseState);
-
- expression = expression->optimize();
-
- // Prepare parameters for the 'evaluate()' call.
- auto variables = &(exprContext->variables);
-
- // Run the test.
- for (auto keepRunning : state) {
- for (const auto& document : documents) {
- benchmark::DoNotOptimize(expression->evaluate(document, variables));
+class ClassicExpressionBenchmarkFixture : public ExpressionBenchmarkFixture {
+ void benchmarkExpression(BSONObj expressionSpec,
+ benchmark::State& state,
+ const std::vector<Document>& documents) override final {
+ QueryTestServiceContext testServiceContext;
+ auto opContext = testServiceContext.makeOperationContext();
+ NamespaceString nss("test.bm");
+ auto exprContext = make_intrusive<ExpressionContextForTest>(opContext.get(), nss);
+
+ // Build an expression.
+ auto expression = Expression::parseExpression(
+ exprContext.get(), expressionSpec, exprContext->variablesParseState);
+
+ expression = expression->optimize();
+
+ // Prepare parameters for the 'evaluate()' call.
+ auto variables = &(exprContext->variables);
+
+ // Run the test.
+ for (auto keepRunning : state) {
+ for (const auto& document : documents) {
+ benchmark::DoNotOptimize(expression->evaluate(document, variables));
+ }
+ benchmark::ClobberMemory();
}
- benchmark::ClobberMemory();
- }
-}
-
-void benchmarkExpression(BSONObj expressionSpec, benchmark::State& state) {
- std::vector<Document> documents = {{}};
- benchmarkExpression(expressionSpec, state, documents);
-}
-
-/**
- * Tests performance of 'evaluate()' of $dateDiff expression.
- *
- * startDate - start date in milliseconds from the UNIX epoch.
- * endDate - end date in milliseconds from the UNIX epoch.
- * unit - a string expression of units to use for date difference calculation.
- * timezone - a string representation of timezone to use for date difference calculation.
- * startOfWeek - a string representation of the first day of the week to use for date difference
- * calculation when unit is a week.
- * state - benchmarking state.
- */
-void testDateDiffExpression(long long startDate,
- long long endDate,
- std::string unit,
- boost::optional<std::string> timezone,
- boost::optional<std::string> startOfWeek,
- benchmark::State& state) {
- // Build a $dateDiff expression.
- BSONObjBuilder objBuilder;
- objBuilder << "startDate" << Date_t::fromMillisSinceEpoch(startDate) << "endDate"
- << "$endDate"
- << "unit" << unit;
- if (timezone) {
- objBuilder << "timezone" << *timezone;
- }
- if (startOfWeek) {
- objBuilder << "startOfWeek" << *startOfWeek;
}
- benchmarkExpression(
- BSON("$dateDiff" << objBuilder.obj()),
- state,
- std::vector<Document>(1, {{"endDate"_sd, Date_t::fromMillisSinceEpoch(endDate)}}));
-}
-
-void BM_DateDiffEvaluateMinute300Years(benchmark::State& state) {
- testDateDiffExpression(-1640989478000LL /* 1918-01-01*/,
- 7826117722000LL /* 2218-01-01*/,
- "minute",
- boost::none /*timezone*/,
- boost::none /*startOfWeek*/,
- state);
-}
-
-void BM_DateDiffEvaluateMinute2Years(benchmark::State& state) {
- testDateDiffExpression(1542448721000LL /* 2018-11-17*/,
- 1605607121000LL /* 2020-11-17*/,
- "minute",
- boost::none /*timezone*/,
- boost::none /*startOfWeek*/,
- state);
-}
-
-void BM_DateDiffEvaluateMinute2YearsWithTimezone(benchmark::State& state) {
- testDateDiffExpression(1542448721000LL /* 2018-11-17*/,
- 1605607121000LL /* 2020-11-17*/,
- "minute",
- std::string{"America/New_York"},
- boost::none /*startOfWeek*/,
- state);
-}
-
-void BM_DateDiffEvaluateWeek(benchmark::State& state) {
- testDateDiffExpression(7826117722000LL /* 2218-01-01*/,
- 4761280721000LL /*2120-11-17*/,
- "week",
- boost::none /*timezone*/,
- std::string("Sunday") /*startOfWeek*/,
- state);
-}
-
-BENCHMARK(BM_DateDiffEvaluateMinute300Years);
-BENCHMARK(BM_DateDiffEvaluateMinute2Years);
-BENCHMARK(BM_DateDiffEvaluateMinute2YearsWithTimezone);
-BENCHMARK(BM_DateDiffEvaluateWeek);
-
-/**
- * Tests performance of evaluate() method of $dateAdd
- */
-void testDateAddExpression(long long startDate,
- std::string unit,
- long long amount,
- boost::optional<std::string> timezone,
- benchmark::State& state) {
- BSONObjBuilder objBuilder;
- objBuilder << "startDate"
- << "$startDate"
- << "unit" << unit << "amount" << amount;
- if (timezone) {
- objBuilder << "timezone" << *timezone;
- }
- benchmarkExpression(
- BSON("$dateAdd" << objBuilder.obj()),
- state,
- std::vector<Document>(1, {{"startDate"_sd, Date_t::fromMillisSinceEpoch(startDate)}}));
-}
-
-void BM_DateAddEvaluate10Days(benchmark::State& state) {
- testDateAddExpression(1604131115000LL,
- "day",
- 10LL,
- boost::none, /* timezone */
- state);
-}
-
-void BM_DateAddEvaluate600Minutes(benchmark::State& state) {
- testDateAddExpression(1604131115000LL,
- "minute",
- 600LL,
- boost::none, /* timezone */
- state);
-}
-
-void BM_DateAddEvaluate100KSeconds(benchmark::State& state) {
- testDateAddExpression(1604131115000LL,
- "second",
- 100000LL,
- boost::none, /* timezone */
- state);
-}
-
-void BM_DateAddEvaluate100Years(benchmark::State& state) {
- testDateAddExpression(1604131115000LL,
- "year",
- 100LL,
- boost::none, /* timezone */
- state);
-}
-
-void BM_DateAddEvaluate12HoursWithTimezone(benchmark::State& state) {
- testDateAddExpression(1604131115000LL, "hour", 12LL, std::string{"America/New_York"}, state);
-}
-
-BENCHMARK(BM_DateAddEvaluate10Days);
-BENCHMARK(BM_DateAddEvaluate600Minutes);
-BENCHMARK(BM_DateAddEvaluate100KSeconds);
-BENCHMARK(BM_DateAddEvaluate100Years);
-BENCHMARK(BM_DateAddEvaluate12HoursWithTimezone);
-
-/**
- * Tests performance of 'evaluate()' of $dateTrunc expression.
- *
- * date - start date in milliseconds from the UNIX epoch.
- * unit - a string expression of units to use for date difference calculation.
- * timezone - a string representation of timezone to use for date difference calculation.
- * startOfWeek - a string representation of the first day of the week to use for date difference
- * calculation when unit is a week.
- * state - benchmarking state.
- */
-void testDateTruncExpression(long long date,
- std::string unit,
- unsigned long binSize,
- boost::optional<std::string> timezone,
- boost::optional<std::string> startOfWeek,
- benchmark::State& state) {
- // Build a $dateTrunc expression.
- BSONObjBuilder objBuilder;
- objBuilder << "date"
- << "$date"
- << "unit" << unit << "binSize" << static_cast<long long>(binSize);
- if (timezone) {
- objBuilder << "timezone" << *timezone;
- }
- if (startOfWeek) {
- objBuilder << "startOfWeek" << *startOfWeek;
- }
- benchmarkExpression(
- BSON("$dateTrunc" << objBuilder.obj()),
- state,
- std::vector<Document>(1, {{"date"_sd, Date_t::fromMillisSinceEpoch(date)}}));
-}
-
-void BM_DateTruncEvaluateMinute15NewYork(benchmark::State& state) {
- testDateTruncExpression(1615460825000LL /* year 2021*/,
- "minute",
- 15,
- std::string{"America/New_York"},
- boost::none /* startOfWeek */,
- state);
-}
-
-void BM_DateTruncEvaluateMinute15UTC(benchmark::State& state) {
- testDateTruncExpression(1615460825000LL /* year 2021*/,
- "minute",
- 15,
- boost::none,
- boost::none /* startOfWeek */,
- state);
-}
-
-void BM_DateTruncEvaluateHour1UTCMinus0700(benchmark::State& state) {
- testDateTruncExpression(1615460825000LL /* year 2021*/,
- "hour",
- 1,
- std::string{"-07:00"},
- boost::none /* startOfWeek */,
- state);
-}
-
-void BM_DateTruncEvaluateWeek2NewYorkValue2100(benchmark::State& state) {
- testDateTruncExpression(4108446425000LL /* year 2100*/,
- "week",
- 2,
- std::string{"America/New_York"},
- std::string{"monday"} /* startOfWeek */,
- state);
-}
-
-void BM_DateTruncEvaluateWeek2UTCValue2100(benchmark::State& state) {
- testDateTruncExpression(4108446425000LL /* year 2100*/,
- "week",
- 2,
- std::string{"UTC"},
- std::string{"monday"} /* startOfWeek */,
- state);
-}
-
-void BM_DateTruncEvaluateMonth6NewYorkValue2100(benchmark::State& state) {
- testDateTruncExpression(4108446425000LL /* year 2100*/,
- "month",
- 6,
- std::string{"America/New_York"},
- boost::none /* startOfWeek */,
- state);
-}
-
-void BM_DateTruncEvaluateMonth6NewYorkValue2030(benchmark::State& state) {
- testDateTruncExpression(1893466800000LL /* year 2030*/,
- "month",
- 6,
- std::string{"America/New_York"},
- boost::none /* startOfWeek */,
- state);
-}
-
-void BM_DateTruncEvaluateMonth6UTCValue2030(benchmark::State& state) {
- testDateTruncExpression(1893466800000LL /* year 2030*/,
- "month",
- 8,
- boost::none,
- boost::none /* startOfWeek */,
- state);
-}
-
-void BM_DateTruncEvaluateYear1NewYorkValue2020(benchmark::State& state) {
- testDateTruncExpression(1583924825000LL /* year 2020*/,
- "year",
- 1,
- std::string{"America/New_York"},
- boost::none /* startOfWeek */,
- state);
-}
-
-void BM_DateTruncEvaluateYear1UTCValue2020(benchmark::State& state) {
- testDateTruncExpression(1583924825000LL /* year 2020*/,
- "year",
- 1,
- boost::none,
- boost::none /* startOfWeek */,
- state);
-}
-
-void BM_DateTruncEvaluateYear1NewYorkValue2100(benchmark::State& state) {
- testDateTruncExpression(4108446425000LL /* year 2100*/,
- "year",
- 1,
- std::string{"America/New_York"},
- boost::none /* startOfWeek */,
- state);
-}
-
-BENCHMARK(BM_DateTruncEvaluateMinute15NewYork);
-BENCHMARK(BM_DateTruncEvaluateMinute15UTC);
-BENCHMARK(BM_DateTruncEvaluateHour1UTCMinus0700);
-BENCHMARK(BM_DateTruncEvaluateWeek2NewYorkValue2100);
-BENCHMARK(BM_DateTruncEvaluateWeek2UTCValue2100);
-BENCHMARK(BM_DateTruncEvaluateMonth6NewYorkValue2100);
-BENCHMARK(BM_DateTruncEvaluateMonth6NewYorkValue2030);
-BENCHMARK(BM_DateTruncEvaluateMonth6UTCValue2030);
-BENCHMARK(BM_DateTruncEvaluateYear1NewYorkValue2020);
-BENCHMARK(BM_DateTruncEvaluateYear1UTCValue2020);
-BENCHMARK(BM_DateTruncEvaluateYear1NewYorkValue2100);
-
-/**
- * Tests performance of 'evaluate()' of $getField expression.
- */
-void BM_GetFieldEvaluateExpression(benchmark::State& state) {
- BSONObjBuilder objBuilder;
- objBuilder << "field"
- << "x.y$z"
- << "input"
- << BSON("$const" << BSON("x.y$z"
- << "abc"));
-
- benchmarkExpression(BSON("$getField" << objBuilder.obj()), state);
-}
-
-void BM_GetFieldEvaluateShortSyntaxExpression(benchmark::State& state) {
- benchmarkExpression(BSON("$getField" << BSON("$const"
- << "$foo")),
- state);
-}
-
-void BM_GetFieldNestedExpression(benchmark::State& state) {
- BSONObjBuilder innerObjBuilder;
- innerObjBuilder << "field"
- << "a.b"
- << "input" << BSON("$const" << BSON("a.b" << BSON("c" << 123)));
- BSONObjBuilder outerObjBuilder;
- outerObjBuilder << "field"
- << "c"
- << "input" << BSON("$getField" << innerObjBuilder.obj());
- benchmarkExpression(BSON("$getField" << outerObjBuilder.obj()), state);
-}
-
-BENCHMARK(BM_GetFieldEvaluateExpression);
-BENCHMARK(BM_GetFieldEvaluateShortSyntaxExpression);
-BENCHMARK(BM_GetFieldNestedExpression);
-
-/**
- * Tests performance of 'evaluate()' of $setField and $unsetField expressions.
- */
-void testSetFieldExpression(std::string fieldname,
- std::string oldFieldValue,
- std::string newFieldValue,
- benchmark::State& state) {
- BSONObjBuilder objBuilder;
- objBuilder << "field" << fieldname << "input"
- << BSON("$const" << BSON(fieldname << oldFieldValue << "f1" << 1 << "f2" << 2))
- << "value" << newFieldValue;
-
- benchmarkExpression(BSON("$setField" << objBuilder.obj()), state);
-}
-
-void BM_SetFieldEvaluateExpression(benchmark::State& state) {
- testSetFieldExpression("a.b", "x", "y", state);
-}
-
-// The following two functions test different syntax for equivalent expressions:
-// $unsetField is an alias for $setField with $$REMOVE.
-void BM_SetFieldWithRemoveExpression(benchmark::State& state) {
- testSetFieldExpression("a$b", "x", "$$REMOVE", state);
-}
-
-void BM_UnsetFieldEvaluateExpression(benchmark::State& state) {
- BSONObjBuilder objBuilder;
- objBuilder << "field"
- << "a$b.c"
- << "input"
- << BSON("$const" << BSON("a$b.c"
- << "x"
- << "f1" << 1 << "f2" << 2));
-
- benchmarkExpression(BSON("$unsetField" << objBuilder.obj()), state);
-}
-
-BENCHMARK(BM_SetFieldEvaluateExpression);
-BENCHMARK(BM_SetFieldWithRemoveExpression);
-BENCHMARK(BM_UnsetFieldEvaluateExpression);
-
-BSONArray randomBSONArray(int count, int max, int offset = 0) {
- BSONArrayBuilder builder;
- auto rng = PseudoRandom(std::random_device()());
- for (int i = 0; i < count; i++) {
- builder.append(std::to_string(offset + rng.nextInt32(max)));
- }
- return builder.arr();
-}
-
-BSONArray rangeBSONArray(int count) {
- BSONArrayBuilder builder;
- for (int i = 0; i < count; i++) {
- builder.append(std::to_string(i));
- }
- return builder.arr();
-}
-
-/**
- * Tests performance of $set* expressions.
- */
-void BM_SetIsSubset_allPresent(benchmark::State& state) {
- const int kMax = 100000;
- BSONArray lhs = randomBSONArray(100000, kMax);
- BSONArray rhs = rangeBSONArray(kMax);
-
- benchmarkExpression(BSON("$setIsSubset" << BSON_ARRAY("$arr" << rhs)),
- state,
- std::vector<Document>(100, {{"arr"_sd, lhs}}));
-}
-
-void BM_SetIsSubset_nonePresent(benchmark::State& state) {
- const int kMax = 100000;
- BSONArray lhs = randomBSONArray(100000, kMax, kMax);
- BSONArray rhs = rangeBSONArray(kMax);
-
- benchmarkExpression(BSON("$setIsSubset" << BSON_ARRAY("$arr" << rhs)),
- state,
- std::vector<Document>(100, {{"arr"_sd, lhs}}));
-}
-
-void BM_SetIntersection(benchmark::State& state) {
- const int kMax = 100000;
- BSONArray lhs = randomBSONArray(100000, kMax);
- BSONArray rhs = randomBSONArray(100000, kMax);
-
- benchmarkExpression(BSON("$setIntersection" << BSON_ARRAY("$arr" << rhs)),
- state,
- std::vector<Document>(100, {{"arr"_sd, lhs}}));
-}
-
-void BM_SetDifference(benchmark::State& state) {
- const int kMax = 100000;
- BSONArray lhs = randomBSONArray(100000, kMax);
- BSONArray rhs = randomBSONArray(100000, kMax);
-
- benchmarkExpression(BSON("$setDifference" << BSON_ARRAY("$arr" << rhs)),
- state,
- std::vector<Document>(100, {{"arr"_sd, lhs}}));
-}
-
-void BM_SetEquals(benchmark::State& state) {
- const int kMax = 100000;
- BSONArray lhs = randomBSONArray(100000, kMax);
- BSONArray rhs = randomBSONArray(100000, kMax);
-
- benchmarkExpression(BSON("$setEquals" << BSON_ARRAY("$arr" << rhs)),
- state,
- std::vector<Document>(100, {{"arr"_sd, lhs}}));
-}
-
-void BM_SetUnion(benchmark::State& state) {
- const int kMax = 100000;
- BSONArray lhs = randomBSONArray(100000, kMax);
- BSONArray rhs = randomBSONArray(100000, kMax);
-
- benchmarkExpression(BSON("$setUnion" << BSON_ARRAY("$arr" << rhs)),
- state,
- std::vector<Document>(100, {{"arr"_sd, lhs}}));
-}
+};
-BENCHMARK(BM_SetIsSubset_allPresent);
-BENCHMARK(BM_SetIsSubset_nonePresent);
-BENCHMARK(BM_SetIntersection);
-BENCHMARK(BM_SetDifference);
-BENCHMARK(BM_SetEquals);
-BENCHMARK(BM_SetUnion);
+BENCHMARK_EXPRESSIONS(ClassicExpressionBenchmarkFixture)
} // namespace
} // namespace mongo
diff --git a/src/mongo/db/pipeline/expression_bm_fixture.cpp b/src/mongo/db/pipeline/expression_bm_fixture.cpp
new file mode 100644
index 00000000000..bf118030a7f
--- /dev/null
+++ b/src/mongo/db/pipeline/expression_bm_fixture.cpp
@@ -0,0 +1,446 @@
+/**
+ * Copyright (C) 2022-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/db/pipeline/expression_bm_fixture.h"
+
+namespace mongo {
+
+namespace {
+
+BSONArray rangeBSONArray(int count) {
+ BSONArrayBuilder builder;
+ for (int i = 0; i < count; i++) {
+ builder.append(std::to_string(i));
+ }
+ return builder.arr();
+}
+} // namespace
+
+void ExpressionBenchmarkFixture::benchmarkExpression(BSONObj expressionSpec,
+ benchmark::State& state) {
+ std::vector<Document> documents = {{}};
+ benchmarkExpression(expressionSpec, state, documents);
+}
+
+void ExpressionBenchmarkFixture::noOpBenchmark(benchmark::State& state) {
+ benchmarkExpression(BSON("$const" << 1), state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateDiffEvaluateMinute300Years(benchmark::State& state) {
+ testDateDiffExpression(-1640989478000LL /* 1918-01-01*/,
+ 7826117722000LL /* 2218-01-01*/,
+ "minute",
+ boost::none /*timezone*/,
+ boost::none /*startOfWeek*/,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateDiffEvaluateMinute2Years(benchmark::State& state) {
+ testDateDiffExpression(1542448721000LL /* 2018-11-17*/,
+ 1605607121000LL /* 2020-11-17*/,
+ "minute",
+ boost::none /*timezone*/,
+ boost::none /*startOfWeek*/,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateDiffEvaluateMinute2YearsWithTimezone(
+ benchmark::State& state) {
+ testDateDiffExpression(1542448721000LL /* 2018-11-17*/,
+ 1605607121000LL /* 2020-11-17*/,
+ "minute",
+ std::string{"America/New_York"},
+ boost::none /*startOfWeek*/,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateDiffEvaluateWeek(benchmark::State& state) {
+ testDateDiffExpression(7826117722000LL /* 2218-01-01*/,
+ 4761280721000LL /*2120-11-17*/,
+ "week",
+ boost::none /*timezone*/,
+ std::string("Sunday") /*startOfWeek*/,
+ state);
+}
+
+
+void ExpressionBenchmarkFixture::benchmarkDateAddEvaluate10Days(benchmark::State& state) {
+ testDateAddExpression(1604131115000LL,
+ "day",
+ 10LL,
+ boost::none, /* timezone */
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateAddEvaluate600Minutes(benchmark::State& state) {
+ testDateAddExpression(1604131115000LL,
+ "minute",
+ 600LL,
+ boost::none, /* timezone */
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateAddEvaluate100KSeconds(benchmark::State& state) {
+ testDateAddExpression(1604131115000LL,
+ "second",
+ 100000LL,
+ boost::none, /* timezone */
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateAddEvaluate100Years(benchmark::State& state) {
+ testDateAddExpression(1604131115000LL,
+ "year",
+ 100LL,
+ boost::none, /* timezone */
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateAddEvaluate12HoursWithTimezone(
+ benchmark::State& state) {
+ testDateAddExpression(1604131115000LL, "hour", 12LL, std::string{"America/New_York"}, state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateTruncEvaluateMinute15NewYork(
+ benchmark::State& state) {
+ testDateTruncExpression(1615460825000LL /* year 2021*/,
+ "minute",
+ 15,
+ std::string{"America/New_York"},
+ boost::none /* startOfWeek */,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateTruncEvaluateMinute15UTC(benchmark::State& state) {
+ testDateTruncExpression(1615460825000LL /* year 2021*/,
+ "minute",
+ 15,
+ boost::none,
+ boost::none /* startOfWeek */,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateTruncEvaluateHour1UTCMinus0700(
+ benchmark::State& state) {
+ testDateTruncExpression(1615460825000LL /* year 2021*/,
+ "hour",
+ 1,
+ std::string{"-07:00"},
+ boost::none /* startOfWeek */,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateTruncEvaluateWeek2NewYorkValue2100(
+ benchmark::State& state) {
+ testDateTruncExpression(4108446425000LL /* year 2100*/,
+ "week",
+ 2,
+ std::string{"America/New_York"},
+ std::string{"monday"} /* startOfWeek */,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateTruncEvaluateWeek2UTCValue2100(
+ benchmark::State& state) {
+ testDateTruncExpression(4108446425000LL /* year 2100*/,
+ "week",
+ 2,
+ std::string{"UTC"},
+ std::string{"monday"} /* startOfWeek */,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateTruncEvaluateMonth6NewYorkValue2100(
+ benchmark::State& state) {
+ testDateTruncExpression(4108446425000LL /* year 2100*/,
+ "month",
+ 6,
+ std::string{"America/New_York"},
+ boost::none /* startOfWeek */,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateTruncEvaluateMonth6NewYorkValue2030(
+ benchmark::State& state) {
+ testDateTruncExpression(1893466800000LL /* year 2030*/,
+ "month",
+ 6,
+ std::string{"America/New_York"},
+ boost::none /* startOfWeek */,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateTruncEvaluateMonth6UTCValue2030(
+ benchmark::State& state) {
+ testDateTruncExpression(1893466800000LL /* year 2030*/,
+ "month",
+ 8,
+ boost::none,
+ boost::none /* startOfWeek */,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateTruncEvaluateYear1NewYorkValue2020(
+ benchmark::State& state) {
+ testDateTruncExpression(1583924825000LL /* year 2020*/,
+ "year",
+ 1,
+ std::string{"America/New_York"},
+ boost::none /* startOfWeek */,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateTruncEvaluateYear1UTCValue2020(
+ benchmark::State& state) {
+ testDateTruncExpression(1583924825000LL /* year 2020*/,
+ "year",
+ 1,
+ boost::none,
+ boost::none /* startOfWeek */,
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkDateTruncEvaluateYear1NewYorkValue2100(
+ benchmark::State& state) {
+ testDateTruncExpression(4108446425000LL /* year 2100*/,
+ "year",
+ 1,
+ std::string{"America/New_York"},
+ boost::none /* startOfWeek */,
+ state);
+}
+
+/**
+ * Tests performance of $getField expression.
+ */
+void ExpressionBenchmarkFixture::benchmarkGetFieldEvaluateExpression(benchmark::State& state) {
+ BSONObjBuilder objBuilder;
+ objBuilder << "field"
+ << "x.y$z"
+ << "input"
+ << BSON("$const" << BSON("x.y$z"
+ << "abc"));
+
+ benchmarkExpression(BSON("$getField" << objBuilder.obj()), state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkGetFieldEvaluateShortSyntaxExpression(
+ benchmark::State& state) {
+ benchmarkExpression(BSON("$getField" << BSON("$const"
+ << "$foo")),
+ state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkGetFieldNestedExpression(benchmark::State& state) {
+ BSONObjBuilder innerObjBuilder;
+ innerObjBuilder << "field"
+ << "a.b"
+ << "input" << BSON("$const" << BSON("a.b" << BSON("c" << 123)));
+ BSONObjBuilder outerObjBuilder;
+ outerObjBuilder << "field"
+ << "c"
+ << "input" << BSON("$getField" << innerObjBuilder.obj());
+ benchmarkExpression(BSON("$getField" << outerObjBuilder.obj()), state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkSetFieldEvaluateExpression(benchmark::State& state) {
+ testSetFieldExpression("a.b", "x", "y", state);
+}
+
+// The following two functions test different syntax for equivalent expressions:
+// $unsetField is an alias for $setField with $$REMOVE.
+void ExpressionBenchmarkFixture::benchmarkSetFieldWithRemoveExpression(benchmark::State& state) {
+ testSetFieldExpression("a$b", "x", "$$REMOVE", state);
+}
+
+void ExpressionBenchmarkFixture::benchmarkUnsetFieldEvaluateExpression(benchmark::State& state) {
+ BSONObjBuilder objBuilder;
+ objBuilder << "field"
+ << "a$b.c"
+ << "input"
+ << BSON("$const" << BSON("a$b.c"
+ << "x"
+ << "f1" << 1 << "f2" << 2));
+
+ benchmarkExpression(BSON("$unsetField" << objBuilder.obj()), state);
+}
+
+/**
+ * Tests performance of $set* expressions.
+ */
+void ExpressionBenchmarkFixture::benchmarkSetIsSubset_allPresent(benchmark::State& state) {
+ const int kMax = 100000;
+ BSONArray lhs = randomBSONArray(100000, kMax);
+ BSONArray rhs = rangeBSONArray(kMax);
+
+ benchmarkExpression(BSON("$setIsSubset" << BSON_ARRAY("$arr" << rhs)),
+ state,
+ std::vector<Document>(100, {{"arr"_sd, lhs}}));
+}
+
+void ExpressionBenchmarkFixture::benchmarkSetIsSubset_nonePresent(benchmark::State& state) {
+ const int kMax = 100000;
+ BSONArray lhs = randomBSONArray(100000, kMax, kMax);
+ BSONArray rhs = rangeBSONArray(kMax);
+
+ benchmarkExpression(BSON("$setIsSubset" << BSON_ARRAY("$arr" << rhs)),
+ state,
+ std::vector<Document>(100, {{"arr"_sd, lhs}}));
+}
+
+void ExpressionBenchmarkFixture::benchmarkSetIntersection(benchmark::State& state) {
+ const int kMax = 100000;
+ BSONArray lhs = randomBSONArray(100000, kMax);
+ BSONArray rhs = randomBSONArray(100000, kMax);
+
+ benchmarkExpression(BSON("$setIntersection" << BSON_ARRAY("$lhs"
+ << "$rhs")),
+ state,
+ std::vector<Document>(100, {{"lhs", lhs}, {"rhs", rhs}}));
+}
+
+void ExpressionBenchmarkFixture::benchmarkSetDifference(benchmark::State& state) {
+ const int kMax = 100000;
+ BSONArray lhs = randomBSONArray(100000, kMax);
+ BSONArray rhs = randomBSONArray(100000, kMax);
+
+ benchmarkExpression(BSON("$setDifference" << BSON_ARRAY("$lhs"
+ << "$rhs")),
+ state,
+ std::vector<Document>(100, {{"lhs", lhs}, {"rhs", rhs}}));
+}
+
+void ExpressionBenchmarkFixture::benchmarkSetEquals(benchmark::State& state) {
+ const int kMax = 100000;
+ BSONArray lhs = randomBSONArray(100000, kMax);
+ BSONArray rhs = randomBSONArray(100000, kMax);
+
+ benchmarkExpression(BSON("$setEquals" << BSON_ARRAY("$lhs"
+ << "$rhs")),
+ state,
+ std::vector<Document>(100, {{"lhs", lhs}, {"rhs", rhs}}));
+}
+
+void ExpressionBenchmarkFixture::benchmarkSetUnion(benchmark::State& state) {
+ const int kMax = 100000;
+ BSONArray lhs = randomBSONArray(100000, kMax);
+ BSONArray rhs = randomBSONArray(100000, kMax);
+
+ benchmarkExpression(BSON("$setUnion" << BSON_ARRAY("$lhs"
+ << "$rhs")),
+ state,
+ std::vector<Document>(100, {{"lhs"_sd, lhs}, {"rhs"_sd, rhs}}));
+}
+
+void ExpressionBenchmarkFixture::testDateDiffExpression(long long startDate,
+ long long endDate,
+ std::string unit,
+ boost::optional<std::string> timezone,
+ boost::optional<std::string> startOfWeek,
+ benchmark::State& state) {
+ // Build a $dateDiff expression.
+ BSONObjBuilder objBuilder;
+ objBuilder << "startDate" << Date_t::fromMillisSinceEpoch(startDate) << "endDate"
+ << "$endDate"
+ << "unit" << unit;
+ if (timezone) {
+ objBuilder << "timezone" << *timezone;
+ }
+ if (startOfWeek) {
+ objBuilder << "startOfWeek" << *startOfWeek;
+ }
+ benchmarkExpression(
+ BSON("$dateDiff" << objBuilder.obj()),
+ state,
+ std::vector<Document>(1, {{"endDate"_sd, Date_t::fromMillisSinceEpoch(endDate)}}));
+}
+
+void ExpressionBenchmarkFixture::testDateTruncExpression(long long date,
+ std::string unit,
+ unsigned long binSize,
+ boost::optional<std::string> timezone,
+ boost::optional<std::string> startOfWeek,
+ benchmark::State& state) {
+ // Build a $dateTrunc expression.
+ BSONObjBuilder objBuilder;
+ objBuilder << "date"
+ << "$date"
+ << "unit" << unit << "binSize" << static_cast<long long>(binSize);
+ if (timezone) {
+ objBuilder << "timezone" << *timezone;
+ }
+ if (startOfWeek) {
+ objBuilder << "startOfWeek" << *startOfWeek;
+ }
+ benchmarkExpression(
+ BSON("$dateTrunc" << objBuilder.obj()),
+ state,
+ std::vector<Document>(1, {{"date"_sd, Date_t::fromMillisSinceEpoch(date)}}));
+}
+
+void ExpressionBenchmarkFixture::testDateAddExpression(long long startDate,
+ std::string unit,
+ long long amount,
+ boost::optional<std::string> timezone,
+ benchmark::State& state) {
+ BSONObjBuilder objBuilder;
+ objBuilder << "startDate"
+ << "$startDate"
+ << "unit" << unit << "amount" << amount;
+ if (timezone) {
+ objBuilder << "timezone" << *timezone;
+ }
+ benchmarkExpression(
+ BSON("$dateAdd" << objBuilder.obj()),
+ state,
+ std::vector<Document>(1, {{"startDate"_sd, Date_t::fromMillisSinceEpoch(startDate)}}));
+}
+
+void ExpressionBenchmarkFixture::testSetFieldExpression(std::string fieldname,
+ std::string oldFieldValue,
+ std::string newFieldValue,
+ benchmark::State& state) {
+ BSONObjBuilder objBuilder;
+ objBuilder << "field" << fieldname << "input"
+ << BSON("$const" << BSON(fieldname << oldFieldValue << "f1" << 1 << "f2" << 2))
+ << "value" << newFieldValue;
+
+ benchmarkExpression(BSON("$setField" << objBuilder.obj()), state);
+}
+
+BSONArray ExpressionBenchmarkFixture::randomBSONArray(int count, int max, int offset) {
+ BSONArrayBuilder builder;
+ for (int i = 0; i < count; i++) {
+ builder.append(std::to_string(offset + random.nextInt32(max)));
+ }
+ return builder.arr();
+}
+
+
+} // namespace mongo
diff --git a/src/mongo/db/pipeline/expression_bm_fixture.h b/src/mongo/db/pipeline/expression_bm_fixture.h
new file mode 100644
index 00000000000..a0a3b8ab116
--- /dev/null
+++ b/src/mongo/db/pipeline/expression_bm_fixture.h
@@ -0,0 +1,251 @@
+/**
+ * Copyright (C) 2022-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/platform/basic.h"
+
+#include <benchmark/benchmark.h>
+
+#include "mongo/bson/bsonobj.h"
+#include "mongo/db/exec/document_value/document.h"
+#include "mongo/platform/random.h"
+
+namespace mongo {
+
+class ExpressionBenchmarkFixture : public benchmark::Fixture {
+private:
+ static constexpr int32_t kSeed = 1;
+
+public:
+ ExpressionBenchmarkFixture() : random(kSeed){};
+
+ void benchmarkExpression(BSONObj expressionSpec, benchmark::State& benchmarkState);
+
+ virtual void benchmarkExpression(BSONObj expressionSpec,
+ benchmark::State& benchmarkState,
+ const std::vector<Document>& documents) = 0;
+
+ void noOpBenchmark(benchmark::State& state);
+
+ void benchmarkDateDiffEvaluateMinute300Years(benchmark::State& state);
+ void benchmarkDateDiffEvaluateMinute2Years(benchmark::State& state);
+ void benchmarkDateDiffEvaluateMinute2YearsWithTimezone(benchmark::State& state);
+ void benchmarkDateDiffEvaluateWeek(benchmark::State& state);
+
+ void benchmarkDateAddEvaluate10Days(benchmark::State& state);
+ void benchmarkDateAddEvaluate600Minutes(benchmark::State& state);
+ void benchmarkDateAddEvaluate100KSeconds(benchmark::State& state);
+ void benchmarkDateAddEvaluate100Years(benchmark::State& state);
+ void benchmarkDateAddEvaluate12HoursWithTimezone(benchmark::State& state);
+
+ void benchmarkDateTruncEvaluateMinute15NewYork(benchmark::State& state);
+ void benchmarkDateTruncEvaluateMinute15UTC(benchmark::State& state);
+ void benchmarkDateTruncEvaluateHour1UTCMinus0700(benchmark::State& state);
+ void benchmarkDateTruncEvaluateWeek2NewYorkValue2100(benchmark::State& state);
+ void benchmarkDateTruncEvaluateWeek2UTCValue2100(benchmark::State& state);
+ void benchmarkDateTruncEvaluateMonth6NewYorkValue2100(benchmark::State& state);
+ void benchmarkDateTruncEvaluateMonth6NewYorkValue2030(benchmark::State& state);
+ void benchmarkDateTruncEvaluateMonth6UTCValue2030(benchmark::State& state);
+ void benchmarkDateTruncEvaluateYear1NewYorkValue2020(benchmark::State& state);
+ void benchmarkDateTruncEvaluateYear1UTCValue2020(benchmark::State& state);
+ void benchmarkDateTruncEvaluateYear1NewYorkValue2100(benchmark::State& state);
+
+ void benchmarkGetFieldEvaluateExpression(benchmark::State& state);
+ void benchmarkGetFieldEvaluateShortSyntaxExpression(benchmark::State& state);
+ void benchmarkGetFieldNestedExpression(benchmark::State& state);
+ void benchmarkSetFieldEvaluateExpression(benchmark::State& state);
+ void benchmarkSetFieldWithRemoveExpression(benchmark::State& state);
+ void benchmarkUnsetFieldEvaluateExpression(benchmark::State& state);
+
+ void benchmarkSetIsSubset_allPresent(benchmark::State& state);
+ void benchmarkSetIsSubset_nonePresent(benchmark::State& state);
+ void benchmarkSetIntersection(benchmark::State& state);
+ void benchmarkSetDifference(benchmark::State& state);
+ void benchmarkSetEquals(benchmark::State& state);
+ void benchmarkSetUnion(benchmark::State& state);
+
+private:
+ void testDateDiffExpression(long long startDate,
+ long long endDate,
+ std::string unit,
+ boost::optional<std::string> timezone,
+ boost::optional<std::string> startOfWeek,
+ benchmark::State& state);
+ void testDateTruncExpression(long long date,
+ std::string unit,
+ unsigned long binSize,
+ boost::optional<std::string> timezone,
+ boost::optional<std::string> startOfWeek,
+ benchmark::State& state);
+ void testDateAddExpression(long long startDate,
+ std::string unit,
+ long long amount,
+ boost::optional<std::string> timezone,
+ benchmark::State& state);
+ void testSetFieldExpression(std::string fieldname,
+ std::string oldFieldValue,
+ std::string newFieldValue,
+ benchmark::State& state);
+
+ BSONArray randomBSONArray(int count, int max, int offset = 0);
+
+ PseudoRandom random;
+};
+
+#define BENCHMARK_EXPRESSIONS(Fixture) \
+ \
+ BENCHMARK_F(Fixture, NoOp) \
+ (benchmark::State & state) { \
+ noOpBenchmark(state); \
+ } \
+ \
+ BENCHMARK_F(Fixture, DateDiffEvaluateMinute300Years) \
+ (benchmark::State & state) { \
+ benchmarkDateDiffEvaluateMinute300Years(state); \
+ } \
+ BENCHMARK_F(Fixture, DateDiffEvaluateMinute2Years) \
+ (benchmark::State & state) { \
+ benchmarkDateDiffEvaluateMinute2Years(state); \
+ } \
+ BENCHMARK_F(Fixture, DateDiffEvaluateMinute2YearsWithTimezone) \
+ (benchmark::State & state) { \
+ benchmarkDateDiffEvaluateMinute2YearsWithTimezone(state); \
+ } \
+ BENCHMARK_F(Fixture, DateDiffEvaluateWeek)(benchmark::State & state) { \
+ benchmarkDateDiffEvaluateWeek(state); \
+ } \
+ \
+ BENCHMARK_F(Fixture, DateAddEvaluate10Days)(benchmark::State & state) { \
+ benchmarkDateAddEvaluate10Days(state); \
+ } \
+ BENCHMARK_F(Fixture, DateAddEvaluate600Minutes)(benchmark::State & state) { \
+ benchmarkDateAddEvaluate600Minutes(state); \
+ } \
+ BENCHMARK_F(Fixture, DateAddEvaluate100KSeconds) \
+ (benchmark::State & state) { \
+ benchmarkDateAddEvaluate100KSeconds(state); \
+ } \
+ BENCHMARK_F(Fixture, DateAddEvaluate100Years)(benchmark::State & state) { \
+ benchmarkDateAddEvaluate100Years(state); \
+ } \
+ BENCHMARK_F(Fixture, DateAddEvaluate12HoursWithTimezone) \
+ (benchmark::State & state) { \
+ benchmarkDateAddEvaluate12HoursWithTimezone(state); \
+ } \
+ \
+ BENCHMARK_F(Fixture, DateTruncEvaluateMinute15NewYork) \
+ (benchmark::State & state) { \
+ benchmarkDateTruncEvaluateMinute15NewYork(state); \
+ } \
+ BENCHMARK_F(Fixture, DateTruncEvaluateMinute15UTC) \
+ (benchmark::State & state) { \
+ benchmarkDateTruncEvaluateMinute15UTC(state); \
+ } \
+ BENCHMARK_F(Fixture, DateTruncEvaluateHour1UTCMinus0700) \
+ (benchmark::State & state) { \
+ benchmarkDateTruncEvaluateHour1UTCMinus0700(state); \
+ } \
+ BENCHMARK_F(Fixture, DateTruncEvaluateWeek2NewYorkValue2100) \
+ (benchmark::State & state) { \
+ benchmarkDateTruncEvaluateWeek2NewYorkValue2100(state); \
+ } \
+ BENCHMARK_F(Fixture, DateTruncEvaluateWeek2UTCValue2100) \
+ (benchmark::State & state) { \
+ benchmarkDateTruncEvaluateWeek2UTCValue2100(state); \
+ } \
+ BENCHMARK_F(Fixture, DateTruncEvaluateMonth6NewYorkValue2100) \
+ (benchmark::State & state) { \
+ benchmarkDateTruncEvaluateMonth6NewYorkValue2100(state); \
+ } \
+ BENCHMARK_F(Fixture, DateTruncEvaluateMonth6NewYorkValue2030) \
+ (benchmark::State & state) { \
+ benchmarkDateTruncEvaluateMonth6NewYorkValue2030(state); \
+ } \
+ BENCHMARK_F(Fixture, DateTruncEvaluateMonth6UTCValue2030) \
+ (benchmark::State & state) { \
+ benchmarkDateTruncEvaluateMonth6UTCValue2030(state); \
+ } \
+ BENCHMARK_F(Fixture, DateTruncEvaluateYear1NewYorkValue2020) \
+ (benchmark::State & state) { \
+ benchmarkDateTruncEvaluateYear1NewYorkValue2020(state); \
+ } \
+ BENCHMARK_F(Fixture, DateTruncEvaluateYear1UTCValue2020) \
+ (benchmark::State & state) { \
+ benchmarkDateTruncEvaluateYear1UTCValue2020(state); \
+ } \
+ BENCHMARK_F(Fixture, DateTruncEvaluateYear1NewYorkValue2100) \
+ (benchmark::State & state) { \
+ benchmarkDateTruncEvaluateYear1NewYorkValue2100(state); \
+ } \
+ \
+ BENCHMARK_F(Fixture, GetFieldEvaluateExpression) \
+ (benchmark::State & state) { \
+ benchmarkGetFieldEvaluateExpression(state); \
+ } \
+ BENCHMARK_F(Fixture, GetFieldEvaluateShortSyntaxExpression) \
+ (benchmark::State & state) { \
+ benchmarkGetFieldEvaluateShortSyntaxExpression(state); \
+ } \
+ BENCHMARK_F(Fixture, GetFieldNestedExpression)(benchmark::State & state) { \
+ benchmarkGetFieldNestedExpression(state); \
+ } \
+ BENCHMARK_F(Fixture, SetFieldEvaluateExpression) \
+ (benchmark::State & state) { \
+ benchmarkSetFieldEvaluateExpression(state); \
+ } \
+ BENCHMARK_F(Fixture, SetFieldWithRemoveExpression) \
+ (benchmark::State & state) { \
+ benchmarkSetFieldWithRemoveExpression(state); \
+ } \
+ BENCHMARK_F(Fixture, UnsetFieldEvaluateExpression) \
+ (benchmark::State & state) { \
+ benchmarkUnsetFieldEvaluateExpression(state); \
+ } \
+ \
+ BENCHMARK_F(Fixture, SetIsSubset_allPresent)(benchmark::State & state) { \
+ benchmarkSetIsSubset_allPresent(state); \
+ } \
+ BENCHMARK_F(Fixture, SetIsSubset_nonePresent)(benchmark::State & state) { \
+ benchmarkSetIsSubset_nonePresent(state); \
+ } \
+ BENCHMARK_F(Fixture, SetIntersection)(benchmark::State & state) { \
+ benchmarkSetIntersection(state); \
+ } \
+ BENCHMARK_F(Fixture, SetDifference)(benchmark::State & state) { \
+ benchmarkSetDifference(state); \
+ } \
+ BENCHMARK_F(Fixture, SetEquals)(benchmark::State & state) { \
+ benchmarkSetEquals(state); \
+ } \
+ BENCHMARK_F(Fixture, SetUnion)(benchmark::State & state) { \
+ benchmarkSetUnion(state); \
+ }
+
+} // namespace mongo
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript
index 890bf8e1615..548e73b0ba6 100644
--- a/src/mongo/db/query/SConscript
+++ b/src/mongo/db/query/SConscript
@@ -399,8 +399,8 @@ env.CppUnitTest(
"sbe_and_sorted_test.cpp",
"sbe_stage_builder_accumulator_test.cpp",
"sbe_stage_builder_lookup_test.cpp",
- "sbe_stage_builder_test_fixture.cpp",
"sbe_stage_builder_test.cpp",
+ "sbe_stage_builder_test_fixture.cpp",
"sbe_shard_filter_test.cpp",
"shard_filterer_factory_mock.cpp",
"view_response_formatter_test.cpp",
@@ -417,7 +417,6 @@ env.CppUnitTest(
"$BUILD_DIR/mongo/db/repl/replmocks",
"$BUILD_DIR/mongo/db/repl/storage_interface_impl",
"$BUILD_DIR/mongo/db/service_context_d_test_fixture",
- "$BUILD_DIR/mongo/db/service_context_test_fixture",
"$BUILD_DIR/mongo/dbtests/mocklib",
"$BUILD_DIR/mongo/rpc/rpc",
"$BUILD_DIR/mongo/util/clock_source_mock",
@@ -433,3 +432,16 @@ env.CppUnitTest(
"query_test_service_context",
],
)
+
+env.Benchmark(
+ target="sbe_expression_bm",
+ source=[
+ "sbe_expression_bm.cpp",
+ ],
+ LIBDEPS=[
+ "$BUILD_DIR/mongo/db/auth/authmocks",
+ "$BUILD_DIR/mongo/db/pipeline/expression_bm_fixture",
+ "$BUILD_DIR/mongo/db/query_exec",
+ "query_test_service_context",
+ ],
+)
diff --git a/src/mongo/db/query/sbe_expression_bm.cpp b/src/mongo/db/query/sbe_expression_bm.cpp
new file mode 100644
index 00000000000..867cbb5ca3a
--- /dev/null
+++ b/src/mongo/db/query/sbe_expression_bm.cpp
@@ -0,0 +1,147 @@
+/**
+ * Copyright (C) 2022-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include <benchmark/benchmark.h>
+
+#include "mongo/db/exec/sbe/util/debug_print.h"
+#include "mongo/db/pipeline/expression_bm_fixture.h"
+#include "mongo/db/pipeline/expression_context_for_test.h"
+#include "mongo/db/query/query_test_service_context.h"
+#include "mongo/db/query/sbe_stage_builder.h"
+#include "mongo/db/query/sbe_stage_builder_expression.h"
+
+#include "mongo/logv2/log.h"
+
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest
+
+namespace mongo {
+namespace {
+
+class SbeExpressionBenchmarkFixture : public ExpressionBenchmarkFixture {
+public:
+ SbeExpressionBenchmarkFixture() : _planStageData(std::make_unique<sbe::RuntimeEnvironment>()) {
+ _inputSlotId = _planStageData.env->registerSlot(
+ "input"_sd, sbe::value::TypeTags::Nothing, 0, false, &_slotIdGenerator);
+ _timeZoneDB = std::make_unique<TimeZoneDatabase>();
+ _planStageData.env->registerSlot(
+ "timeZoneDB"_sd,
+ sbe::value::TypeTags::timeZoneDB,
+ sbe::value::bitcastFrom<TimeZoneDatabase*>(_timeZoneDB.get()),
+ false,
+ &_slotIdGenerator);
+ }
+
+ void benchmarkExpression(BSONObj expressionSpec,
+ benchmark::State& benchmarkState,
+ const std::vector<Document>& documents) override final {
+ std::vector<BSONObj> bsonDocuments = convertToBson(documents);
+ QueryTestServiceContext serviceContext;
+
+ auto opContext = serviceContext.makeOperationContext();
+ auto exprContext = make_intrusive<ExpressionContextForTest>(opContext.get(), _nss);
+ auto expression = Expression::parseExpression(
+ exprContext.get(), expressionSpec, exprContext->variablesParseState);
+
+ if (!exprContext->sbeCompatible) {
+ benchmarkState.SkipWithError("expression is not supported by SBE");
+ return;
+ }
+
+ expression = expression->optimize();
+
+ stage_builder::StageBuilderState state{
+ opContext.get(),
+ &_planStageData,
+ _variables,
+ &_slotIdGenerator,
+ &_frameIdGenerator,
+ &_spoolIdGenerator,
+ false /* needsMerge */,
+ false /* allowDiskUse */
+ };
+
+ auto [evalExpr, evalStage] =
+ stage_builder::generateExpression(state,
+ expression.get(),
+ stage_builder::EvalStage{},
+ boost::make_optional(_inputSlotId),
+ kEmptyPlanNodeId);
+ tassert(6979800, "Unexpected: EvalStage.stage is not null", evalStage.stageIsNull());
+
+ auto expr = evalExpr.extractExpr();
+ auto compiledExpr = expr->compile(_planStageData.ctx);
+ sbe::vm::ByteCode _vm;
+
+ LOGV2_DEBUG(
+ 6979802,
+ 1,
+ "running sbe expression benchmark on expression {expression}, sbe representation {sbe}",
+ "expression"_attr = expression->serialize(true).toString(),
+ "sbe"_attr = sbe::DebugPrinter{true}.print(expr->debugPrint()));
+
+ for (auto keepRunning : benchmarkState) {
+ for (const auto& document : bsonDocuments) {
+ _planStageData.env->resetSlot(
+ _inputSlotId,
+ sbe::value::TypeTags::bsonObject,
+ sbe::value::bitcastFrom<const char*>(document.objdata()),
+ false);
+ benchmark::DoNotOptimize(_vm.run(compiledExpr.get()));
+ }
+ benchmark::ClobberMemory();
+ }
+ }
+
+private:
+ std::vector<BSONObj> convertToBson(const std::vector<Document>& documents) {
+ std::vector<BSONObj> result;
+ result.reserve(documents.size());
+ std::transform(documents.begin(),
+ documents.end(),
+ std::back_inserter(result),
+ [](const auto& doc) { return doc.toBson(); });
+ return result;
+ }
+
+ NamespaceString _nss{"test.bm"};
+
+ stage_builder::PlanStageData _planStageData;
+ Variables _variables;
+ sbe::value::SlotIdGenerator _slotIdGenerator;
+ sbe::value::FrameIdGenerator _frameIdGenerator;
+ sbe::value::SpoolIdGenerator _spoolIdGenerator;
+
+ sbe::value::SlotId _inputSlotId;
+ std::unique_ptr<TimeZoneDatabase> _timeZoneDB;
+};
+
+BENCHMARK_EXPRESSIONS(SbeExpressionBenchmarkFixture)
+
+} // namespace
+} // namespace mongo