Skip to content

Commit 268b789

Browse files
authored
UT[BMQP]: add benchmark for bmqp::MessageProperties (#1033)
Signed-off-by: Evgeny Malygin <[email protected]>
1 parent 2741ee8 commit 268b789

File tree

1 file changed

+200
-0
lines changed

1 file changed

+200
-0
lines changed

src/groups/bmq/bmqp/bmqp_messageproperties.t.cpp

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@
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
4756
using namespace BloombergLP;
4857
using 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

Comments
 (0)