Skip to content

Commit eba490b

Browse files
authored
UT[bmqt::UriParser]: add multi-threading benchmark (#1013)
Signed-off-by: Evgeny Malygin <[email protected]>
1 parent c9a1fae commit eba490b

File tree

1 file changed

+168
-1
lines changed

1 file changed

+168
-1
lines changed

src/groups/bmq/bmqt/bmqt_uri.t.cpp

Lines changed: 168 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,23 @@
2222
// BDE
2323
#include <ball_log.h>
2424
#include <bdlf_bind.h>
25+
#include <bdlma_localsequentialallocator.h>
2526
#include <bsl_string.h>
2627
#include <bsl_utility.h>
2728
#include <bsl_vector.h>
2829
#include <bslh_defaulthashalgorithm.h>
2930
#include <bslh_hash.h>
3031
#include <bslmt_barrier.h>
32+
#include <bslmt_latch.h>
3133
#include <bslmt_threadgroup.h>
3234

3335
// TEST DRIVER
3436
#include <bmqtst_testhelper.h>
35-
#include <bsl_functional.h>
37+
38+
// BENCHMARKING LIBRARY
39+
#ifdef BMQTST_BENCHMARK_ENABLED
40+
#include <benchmark/benchmark.h>
41+
#endif
3642

3743
// CONVENIENCE
3844
using namespace BloombergLP;
@@ -647,6 +653,123 @@ static void test7_testLongUri()
647653
bmqt::UriParser::shutdown();
648654
}
649655

656+
#ifdef BMQTST_BENCHMARK_ENABLED
657+
658+
struct UriParserBenchmark {
659+
static void bench(bslmt::Latch* initLatch_p,
660+
bslmt::Barrier* startBarrier_p,
661+
bslmt::Latch* finishLatch_p)
662+
{
663+
// PRECONDITIONS
664+
BSLS_ASSERT_OPT(initLatch_p);
665+
BSLS_ASSERT_OPT(startBarrier_p);
666+
BSLS_ASSERT_OPT(finishLatch_p);
667+
668+
const size_t k_NUM_ITERATIONS = 100000;
669+
const bsl::string k_SAMPLE_URI(
670+
"bmq://my.sample.domain.~dev/my-queue-name?id=consumer123",
671+
bmqtst::TestHelperUtil::allocator());
672+
673+
bmqt::Uri uri(bmqtst::TestHelperUtil::allocator());
674+
bsl::string error(bmqtst::TestHelperUtil::allocator());
675+
676+
initLatch_p->arrive();
677+
startBarrier_p->wait();
678+
679+
for (size_t i = 0; i < k_NUM_ITERATIONS; ++i) {
680+
bmqt::UriParser::parse(&uri, &error, k_SAMPLE_URI);
681+
}
682+
683+
finishLatch_p->arrive();
684+
}
685+
};
686+
687+
struct UriConstructorBenchmark {
688+
static void bench(bslmt::Latch* initLatch_p,
689+
bslmt::Barrier* startBarrier_p,
690+
bslmt::Latch* finishLatch_p)
691+
{
692+
// PRECONDITIONS
693+
BSLS_ASSERT_OPT(initLatch_p);
694+
BSLS_ASSERT_OPT(startBarrier_p);
695+
BSLS_ASSERT_OPT(finishLatch_p);
696+
697+
const size_t k_NUM_ITERATIONS = 100000;
698+
const bsl::string k_SAMPLE_URI(
699+
"bmq://my.sample.domain.~dev/my-queue-name?id=consumer123",
700+
bmqtst::TestHelperUtil::allocator());
701+
702+
// Test allocator is slow and might skew the benchmarks
703+
bdlma::LocalSequentialAllocator<256> lsa(
704+
bmqtst::TestHelperUtil::allocator());
705+
706+
initLatch_p->arrive();
707+
startBarrier_p->wait();
708+
709+
for (size_t i = 0; i < k_NUM_ITERATIONS; ++i) {
710+
bmqt::Uri uri(k_SAMPLE_URI, &lsa);
711+
(void)uri;
712+
}
713+
714+
finishLatch_p->arrive();
715+
}
716+
};
717+
718+
template <size_t NUM_THREADS, typename BENCHMARK>
719+
static void testN1_benchmark(benchmark::State& state)
720+
// ------------------------------------------------------------------------
721+
// URI PERFORMANCE TEST
722+
//
723+
// Plan: spawn NUM_THREADS and measure the time taken for BENCHMARK::bench
724+
//
725+
// Testing:
726+
// Performance
727+
// ------------------------------------------------------------------------
728+
{
729+
bmqtst::TestHelper::printTestName("URI PERFORMANCE TEST");
730+
731+
bmqt::UriParser::initialize(bmqtst::TestHelperUtil::allocator());
732+
733+
bslmt::Latch initThreadLatch(NUM_THREADS);
734+
bslmt::Barrier startBenchmarkBarrier(NUM_THREADS + 1);
735+
bslmt::Latch finishBenchmarkLatch(NUM_THREADS);
736+
737+
bslmt::ThreadGroup threadGroup(bmqtst::TestHelperUtil::allocator());
738+
for (size_t i = 0; i < NUM_THREADS; ++i) {
739+
const int rc = threadGroup.addThread(
740+
bdlf::BindUtil::bindS(bmqtst::TestHelperUtil::allocator(),
741+
&(BENCHMARK::bench),
742+
&initThreadLatch,
743+
&startBenchmarkBarrier,
744+
&finishBenchmarkLatch));
745+
BMQTST_ASSERT_EQ_D(i, rc, 0);
746+
}
747+
748+
initThreadLatch.wait();
749+
750+
size_t iter = 0;
751+
for (auto _ : state) {
752+
// Benchmark time start
753+
754+
// We don't support running multi-iteration benchmarks because we
755+
// prepare and start complex tasks in separate threads.
756+
// Once these tasks are finished, we cannot simply re-run them without
757+
// reinitialization, and it goes against benchmark library design.
758+
// Make sure we run this only once.
759+
BSLS_ASSERT_OPT(0 == iter++ && "Must be run only once");
760+
761+
startBenchmarkBarrier.wait();
762+
finishBenchmarkLatch.wait();
763+
764+
// Benchmark time end
765+
}
766+
767+
threadGroup.joinAll();
768+
bmqt::UriParser::shutdown();
769+
}
770+
771+
#endif // BMQTST_BENCHMARK_ENABLED
772+
650773
// ============================================================================
651774
// MAIN PROGRAM
652775
// ----------------------------------------------------------------------------
@@ -664,6 +787,50 @@ int main(int argc, char* argv[])
664787
case 3: test3_URIBuilderMultiThreaded(); break;
665788
case 2: test2_URIBuilder(); break;
666789
case 1: test1_breathingTest(); break;
790+
case -1: {
791+
#ifdef BMQTST_BENCHMARK_ENABLED
792+
BENCHMARK(testN1_benchmark<1, UriParserBenchmark>)
793+
->Name("bmqt::UriParser::parse threads=1")
794+
->Iterations(1)
795+
->Unit(benchmark::kMillisecond);
796+
BENCHMARK(testN1_benchmark<2, UriParserBenchmark>)
797+
->Name("bmqt::UriParser::parse threads=2")
798+
->Iterations(1)
799+
->Unit(benchmark::kMillisecond);
800+
BENCHMARK(testN1_benchmark<4, UriParserBenchmark>)
801+
->Name("bmqt::UriParser::parse threads=4")
802+
->Iterations(1)
803+
->Unit(benchmark::kMillisecond);
804+
BENCHMARK(testN1_benchmark<8, UriParserBenchmark>)
805+
->Name("bmqt::UriParser::parse threads=8")
806+
->Iterations(1)
807+
->Unit(benchmark::kMillisecond);
808+
809+
BENCHMARK(testN1_benchmark<1, UriConstructorBenchmark>)
810+
->Name("bmqt::Uri::Uri threads=1")
811+
->Iterations(1)
812+
->Unit(benchmark::kMillisecond);
813+
BENCHMARK(testN1_benchmark<2, UriConstructorBenchmark>)
814+
->Name("bmqt::Uri::Uri threads=2")
815+
->Iterations(1)
816+
->Unit(benchmark::kMillisecond);
817+
BENCHMARK(testN1_benchmark<4, UriConstructorBenchmark>)
818+
->Name("bmqt::Uri::Uri threads=4")
819+
->Iterations(1)
820+
->Unit(benchmark::kMillisecond);
821+
BENCHMARK(testN1_benchmark<8, UriConstructorBenchmark>)
822+
->Name("bmqt::Uri::Uri threads=8")
823+
->Iterations(1)
824+
->Unit(benchmark::kMillisecond);
825+
826+
benchmark::Initialize(&argc, argv);
827+
benchmark::RunSpecifiedBenchmarks();
828+
#else
829+
cerr << "WARNING: BENCHMARK '" << _testCase
830+
<< "' IS NOT SUPPORTED ON THIS PLATFORM." << endl;
831+
bmqtst::TestHelperUtil::testStatus() = -1;
832+
#endif // BMQTST_BENCHMARK_ENABLED
833+
} break;
667834
default: {
668835
cerr << "WARNING: CASE '" << _testCase << "' NOT FOUND." << endl;
669836
bmqtst::TestHelperUtil::testStatus() = -1;

0 commit comments

Comments
 (0)