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
3844using 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