4343#include < bsl_cstring.h>
4444#include < bsl_ostream.h>
4545
46+ #ifdef BMQTST_BENCHMARK_ENABLED
47+ #include < bslmt_barrier.h>
48+ #include < bslmt_latch.h>
49+ #include < bslmt_threadgroup.h>
50+
51+ // BENCHMARKING LIBRARY
52+ #include < benchmark/benchmark.h>
53+ #endif
54+
4655// CONVENIENCE
4756using namespace BloombergLP ;
4857using namespace bsl ;
@@ -1243,6 +1252,173 @@ static void test10_empty()
12431252 BMQTST_ASSERT (!p.hasProperty (" z" ));
12441253}
12451254
1255+ #ifdef BMQTST_BENCHMARK_ENABLED
1256+
1257+ struct MessagePropertiesBenchmark_getPropertyRef {
1258+ static void bench (bslmt::Latch* initLatch_p,
1259+ bslmt::Barrier* startBarrier_p,
1260+ bslmt::Latch* finishLatch_p)
1261+ {
1262+ // PRECONDITIONS
1263+ BSLS_ASSERT_OPT (initLatch_p);
1264+ BSLS_ASSERT_OPT (startBarrier_p);
1265+ BSLS_ASSERT_OPT (finishLatch_p);
1266+
1267+ bslma::Allocator* alloc = bmqtst::TestHelperUtil::allocator ();
1268+
1269+ const size_t k_NUM_ITERATIONS = 1000000 ;
1270+
1271+ bdlbb::PooledBlobBufferFactory bufferFactory (1024 , alloc);
1272+ bmqp::MessageProperties obj (alloc);
1273+ bdlbb::Blob wireRep (&bufferFactory, alloc);
1274+ PropertyMap pmap (alloc);
1275+ bmqp::MessagePropertiesInfo logic =
1276+ bmqp::MessagePropertiesInfo::makeNoSchema ();
1277+
1278+ const size_t numProps =
1279+ bmqp::MessagePropertiesHeader::k_MAX_NUM_PROPERTIES;
1280+
1281+ // Populate with various properties.
1282+
1283+ // Note that `dummyP` is used only because `populateProperties`
1284+ // requires one.
1285+ bmqp::MessageProperties dummyP (alloc);
1286+
1287+ populateProperties (&dummyP, &pmap, numProps);
1288+
1289+ // Init vector once to allow faster iteration in benchmark
1290+ bsl::vector<bsl::string> propertyNames (alloc);
1291+ for (auto iter = pmap.cbegin (); iter != pmap.cend (); iter++) {
1292+ propertyNames.push_back (iter->first );
1293+ }
1294+
1295+ BMQTST_ASSERT_EQ (numProps, pmap.size ());
1296+
1297+ encode (&wireRep, pmap);
1298+
1299+ BMQTST_ASSERT_EQ (0 , obj.streamIn (wireRep, logic.isExtended ()));
1300+
1301+ initLatch_p->arrive ();
1302+ startBarrier_p->wait ();
1303+
1304+ for (size_t i = 0 ; i < k_NUM_ITERATIONS; ++i) {
1305+ bmqp::MessageProperties props;
1306+ props.setDeepCopy (false );
1307+ props.streamIn (wireRep, true );
1308+
1309+ for (size_t j = 0 ; j < propertyNames.size (); j++) {
1310+ // Don't use slow `bmqtst::TestHelperUtil::allocator`:
1311+ (void )props.getPropertyRef (propertyNames[j], 0 );
1312+ }
1313+ }
1314+
1315+ finishLatch_p->arrive ();
1316+ }
1317+ };
1318+
1319+ struct MessagePropertiesBenchmark_streamIn {
1320+ static void bench (bslmt::Latch* initLatch_p,
1321+ bslmt::Barrier* startBarrier_p,
1322+ bslmt::Latch* finishLatch_p)
1323+ {
1324+ // PRECONDITIONS
1325+ BSLS_ASSERT_OPT (initLatch_p);
1326+ BSLS_ASSERT_OPT (startBarrier_p);
1327+ BSLS_ASSERT_OPT (finishLatch_p);
1328+
1329+ bslma::Allocator* alloc = bmqtst::TestHelperUtil::allocator ();
1330+
1331+ const size_t k_NUM_ITERATIONS = 10000000 ;
1332+
1333+ bdlbb::PooledBlobBufferFactory bufferFactory (1024 , alloc);
1334+ bmqp::MessageProperties obj (alloc);
1335+ bdlbb::Blob wireRep (&bufferFactory, alloc);
1336+ PropertyMap pmap (alloc);
1337+ bmqp::MessagePropertiesInfo logic =
1338+ bmqp::MessagePropertiesInfo::makeNoSchema ();
1339+
1340+ const size_t numProps =
1341+ bmqp::MessagePropertiesHeader::k_MAX_NUM_PROPERTIES;
1342+
1343+ // Populate with various properties.
1344+
1345+ // Note that `dummyP` is used only because `populateProperties`
1346+ // requires one.
1347+ bmqp::MessageProperties dummyP (alloc);
1348+
1349+ populateProperties (&dummyP, &pmap, numProps);
1350+
1351+ BMQTST_ASSERT_EQ (numProps, pmap.size ());
1352+
1353+ encode (&wireRep, pmap);
1354+
1355+ BMQTST_ASSERT_EQ (0 , obj.streamIn (wireRep, logic.isExtended ()));
1356+
1357+ initLatch_p->arrive ();
1358+ startBarrier_p->wait ();
1359+
1360+ for (size_t i = 0 ; i < k_NUM_ITERATIONS; ++i) {
1361+ bmqp::MessageProperties props;
1362+ props.setDeepCopy (false );
1363+ props.streamIn (wireRep, true );
1364+ }
1365+
1366+ finishLatch_p->arrive ();
1367+ }
1368+ };
1369+
1370+ template <size_t NUM_THREADS, typename BENCHMARK>
1371+ static void testN1_benchmark (benchmark::State& state)
1372+ // ------------------------------------------------------------------------
1373+ // MESSAGE PROPERTIES PERFORMANCE TEST
1374+ //
1375+ // Plan: spawn NUM_THREADS and measure the time taken for BENCHMARK::bench
1376+ //
1377+ // Testing:
1378+ // Performance
1379+ // ------------------------------------------------------------------------
1380+ {
1381+ bmqtst::TestHelper::printTestName (" MESSAGE PROPERTIES PERFORMANCE TEST" );
1382+
1383+ bslmt::Latch initThreadLatch (NUM_THREADS);
1384+ bslmt::Barrier startBenchmarkBarrier (NUM_THREADS + 1 );
1385+ bslmt::Latch finishBenchmarkLatch (NUM_THREADS);
1386+
1387+ bslmt::ThreadGroup threadGroup (bmqtst::TestHelperUtil::allocator ());
1388+ for (size_t i = 0 ; i < NUM_THREADS; ++i) {
1389+ const int rc = threadGroup.addThread (
1390+ bdlf::BindUtil::bindS (bmqtst::TestHelperUtil::allocator (),
1391+ &(BENCHMARK::bench),
1392+ &initThreadLatch,
1393+ &startBenchmarkBarrier,
1394+ &finishBenchmarkLatch));
1395+ BMQTST_ASSERT_EQ_D (i, rc, 0 );
1396+ }
1397+
1398+ initThreadLatch.wait ();
1399+
1400+ size_t iter = 0 ;
1401+ for (auto _ : state) {
1402+ // Benchmark time start
1403+
1404+ // We don't support running multi-iteration benchmarks because we
1405+ // prepare and start complex tasks in separate threads.
1406+ // Once these tasks are finished, we cannot simply re-run them without
1407+ // reinitialization, and it goes against benchmark library design.
1408+ // Make sure we run this only once.
1409+ BSLS_ASSERT_OPT (0 == iter++ && " Must be run only once" );
1410+
1411+ startBenchmarkBarrier.wait ();
1412+ finishBenchmarkLatch.wait ();
1413+
1414+ // Benchmark time end
1415+ }
1416+
1417+ threadGroup.joinAll ();
1418+ }
1419+
1420+ #endif // BMQTST_BENCHMARK_ENABLED
1421+
12461422// ============================================================================
12471423// MAIN PROGRAM
12481424// ----------------------------------------------------------------------------
@@ -1265,6 +1441,30 @@ int main(int argc, char* argv[])
12651441 case 3 : test3_binaryPropertyTest (); break ;
12661442 case 2 : test2_setPropertyTest (); break ;
12671443 case 1 : test1_breathingTest (); break ;
1444+ case -1 : {
1445+ #ifdef BMQTST_BENCHMARK_ENABLED
1446+ // Not necessary to check performance in multiple threads
1447+ BENCHMARK (testN1_benchmark<1 , MessagePropertiesBenchmark_streamIn>)
1448+ ->Name (" bmqp::MessageProperties::streamIn" )
1449+ ->Iterations (1 )
1450+ ->Repetitions (10 )
1451+ ->Unit (benchmark::kMillisecond );
1452+
1453+ BENCHMARK (
1454+ testN1_benchmark<1 , MessagePropertiesBenchmark_getPropertyRef>)
1455+ ->Name (" bmqp::MessageProperties::getPropertyRef" )
1456+ ->Iterations (1 )
1457+ ->Repetitions (10 )
1458+ ->Unit (benchmark::kMillisecond );
1459+
1460+ benchmark::Initialize (&argc, argv);
1461+ benchmark::RunSpecifiedBenchmarks ();
1462+ #else
1463+ cerr << " WARNING: BENCHMARK '" << _testCase
1464+ << " ' IS NOT SUPPORTED ON THIS PLATFORM." << endl;
1465+ bmqtst::TestHelperUtil::testStatus () = -1 ;
1466+ #endif // BMQTST_BENCHMARK_ENABLED
1467+ } break ;
12681468 default : {
12691469 cerr << " WARNING: CASE '" << _testCase << " ' NOT FOUND." << endl;
12701470 bmqtst::TestHelperUtil::testStatus () = -1 ;
0 commit comments