ATLAS Offline Software
Loading...
Searching...
No Matches
columnar::TestUtils Namespace Reference

Classes

class  Benchmark
 this is a simple benchmarking helper class wrapping timers from std::chrono More...
struct  BranchPerfData
 the performance data for reading a single branch/column More...
class  BranchReader
class  BranchReaderArray
class  ColumnarTestToolHandle
 a handle to a columnar tool for running tests More...
struct  ColumnDataEventCount
struct  ColumnDataMetNames
struct  ColumnDataOutputMet
struct  ColumnDataOutVector
struct  ColumnDataSamplingPattern
struct  ColumnDataScalar
struct  ColumnDataVector
struct  ColumnDataVectorVector
struct  ColumnDataVectorVectorVector
struct  ColumnMapType
class  IColumnData
class  IXAODToolCaller
 a wrapper around a CP tool in xAOD mdoe to call it in the PHYSLITE test More...
class  LinkColumnVector
class  ManualColumnData
 a class that holds manually specified column data More...
class  RNTFieldReader
struct  RNTupleBackend
struct  TestDefinition
 the general configuration for a single test More...
struct  ToolPerfData
 the performance data for running a single tool More...
class  ToolWrapperData
 a class that holds a reference to a ToolColumnVectorMap and a ColumnVectorData More...
struct  UserConfiguration
 a struct holding user configuration for the PHYSLITE tests More...

Typedefs

using Backend = std::variant<TTree*, RNTupleBackend*>

Functions

void checkExpectation (const std::string &columnName, const std::type_info &outputType, std::size_t outputSize, const void *outputData, const std::type_info &expectationType, std::size_t expectationSize, const void *expectationData)
void printExpectedOutput (const std::string &columnName, const std::type_info &outputType, std::size_t outputSize, const void *outputData)
void runXaodTest (const UserConfiguration &userConfiguration, std::span< const TestDefinition > testDefinitions, TFile *file)
void runXaodArrayTest (const UserConfiguration &userConfiguration, const TestDefinition &testDefinition, TFile *file)

Typedef Documentation

◆ Backend

using columnar::TestUtils::Backend = std::variant<TTree*, RNTupleBackend*>

Definition at line 84 of file ColumnarPhysliteTest.cxx.

Function Documentation

◆ checkExpectation()

void columnar::TestUtils::checkExpectation ( const std::string & columnName,
const std::type_info & outputType,
std::size_t outputSize,
const void * outputData,
const std::type_info & expectationType,
std::size_t expectationSize,
const void * expectationData )

Definition at line 46 of file ExpectationCompare.cxx.

47 {
48 SCOPED_TRACE (columnName);
49 ASSERT_EQ (outputType, expectationType);
50 if (outputType == typeid(float))
51 checkExpectationTyped (columnName, std::span<const float> (static_cast<const float*> (outputData), outputSize), std::span<const float> (static_cast<const float*> (expectationData), expectationSize));
52 else if (outputType == typeid(char))
53 checkExpectationTyped (columnName, std::span<const char> (static_cast<const char*> (outputData), outputSize), std::span<const char> (static_cast<const char*> (expectationData), expectationSize));
54 else if (outputType == typeid(int))
55 checkExpectationTyped (columnName, std::span<const int> (static_cast<const int*> (outputData), outputSize), std::span<const int> (static_cast<const int*> (expectationData), expectationSize));
56 else if (outputType == typeid(std::uint8_t))
57 checkExpectationTyped (columnName, std::span<const std::uint8_t> (static_cast<const std::uint8_t*> (outputData), outputSize), std::span<const std::uint8_t> (static_cast<const std::uint8_t*> (expectationData), expectationSize));
58 else if (outputType == typeid(std::uint16_t))
59 checkExpectationTyped (columnName, std::span<const std::uint16_t> (static_cast<const std::uint16_t*> (outputData), outputSize), std::span<const std::uint16_t> (static_cast<const std::uint16_t*> (expectationData), expectationSize));
60 else if (outputType == typeid(std::uint32_t))
61 checkExpectationTyped (columnName, std::span<const std::uint32_t> (static_cast<const std::uint32_t*> (outputData), outputSize), std::span<const std::uint32_t> (static_cast<const std::uint32_t*> (expectationData), expectationSize));
62 else if (outputType == typeid(std::uint64_t))
63 checkExpectationTyped (columnName, std::span<const std::uint64_t> (static_cast<const std::uint64_t*> (outputData), outputSize), std::span<const std::uint64_t> (static_cast<const std::uint64_t*> (expectationData), expectationSize));
64 else if (outputType == typeid(std::size_t))
65 checkExpectationTyped (columnName, std::span<const std::size_t> (static_cast<const std::size_t*> (outputData), outputSize), std::span<const std::size_t> (static_cast<const std::size_t*> (expectationData), expectationSize));
66 else
67 throw std::logic_error ("received unsupported type " + boost::core::demangle(outputType.name()) + " for column compare, cast value or extend test handler to support it");
68 }

◆ printExpectedOutput()

void columnar::TestUtils::printExpectedOutput ( const std::string & columnName,
const std::type_info & outputType,
std::size_t outputSize,
const void * outputData )

Definition at line 93 of file ExpectationCompare.cxx.

94 {
95 if (outputType == typeid(float))
96 printExpectedOutputTyped (columnName, std::span<const float> (static_cast<const float*> (outputData), outputSize));
97 else if (outputType == typeid(char))
98 printExpectedOutputTyped (columnName, std::span<const char> (static_cast<const char*> (outputData), outputSize));
99 else if (outputType == typeid(int))
100 printExpectedOutputTyped (columnName, std::span<const int> (static_cast<const int*> (outputData), outputSize));
101 else if (outputType == typeid(std::uint8_t))
102 printExpectedOutputTyped (columnName, std::span<const std::uint8_t> (static_cast<const std::uint8_t*> (outputData), outputSize));
103 else if (outputType == typeid(std::uint16_t))
104 printExpectedOutputTyped (columnName, std::span<const std::uint16_t> (static_cast<const std::uint16_t*> (outputData), outputSize));
105 else if (outputType == typeid(std::uint32_t))
106 printExpectedOutputTyped (columnName, std::span<const std::uint32_t> (static_cast<const std::uint32_t*> (outputData), outputSize));
107 else if (outputType == typeid(std::uint64_t))
108 printExpectedOutputTyped (columnName, std::span<const std::uint64_t> (static_cast<const std::uint64_t*> (outputData), outputSize));
109 else if (outputType == typeid(std::size_t))
110 printExpectedOutputTyped (columnName, std::span<const std::size_t> (static_cast<const std::size_t*> (outputData), outputSize));
111 else
112 throw std::logic_error ("received unsupported type " + boost::core::demangle(outputType.name()) + " for column printout, cast value or extend test handler to support it");
113 }

◆ runXaodArrayTest()

void columnar::TestUtils::runXaodArrayTest ( const UserConfiguration & userConfiguration,
const TestDefinition & testDefinition,
TFile * file )

Definition at line 317 of file PhysliteTestXaodArray.cxx.

318 {
319 using namespace asg::msgUserCode;
320
321 xAOD::TEvent event;
322 xAOD::TStore store;
323 ANA_CHECK_THROW (event.readFrom (file));
324
325 auto *myTool = dynamic_cast<ColumnarTool<ColumnarModeXAODArray>*>(testDefinition.tool);
326 if (!myTool)
327 throw std::runtime_error ("tool is not a ColumnarTool<ColumnarModeXAODArray>");
328 if (!testDefinition.containerRenames.empty())
329 renameContainers (*myTool, testDefinition.containerRenames);
330 ColumnVectorHeader columnHeader;
331 ToolColumnVectorMap toolWrapper (columnHeader, *myTool);
332
333 std::unordered_map<std::string,TestUtils::ColumnDataXA> requestedColumns;
334 for (auto& column : myTool->getColumnInfo())
335 requestedColumns[column.name].info = std::move (column);
336 for (auto& [name, data] : requestedColumns)
337 {
338 if (data.info.isOffset)
339 {
340 if (*data.info.type != typeid(ColumnarOffsetType))
341 throw std::runtime_error ("unexpected type for offset column: " + name + " " + data.info.type->name());
342 if (name == eventRangeColumnName)
343 {
344 data.reader = std::make_shared<TestUtils::ColumnDataXAEventInfo> (data.info);
345 } else if (data.info.offsetName == eventRangeColumnName)
346 {
347 if (name == "AnalysisMuons")
348 data.reader = std::make_shared<TestUtils::ColumnDataXARetrieve<xAOD::MuonContainer>> (data.info, userConfiguration);
349 else if (name == "AnalysisElectrons")
350 data.reader = std::make_shared<TestUtils::ColumnDataXARetrieve<xAOD::ElectronContainer>> (data.info, userConfiguration);
351 else if (name == "AnalysisPhotons")
352 data.reader = std::make_shared<TestUtils::ColumnDataXARetrieve<xAOD::PhotonContainer>> (data.info, userConfiguration);
353 else if (name == "egammaClusters")
354 data.reader = std::make_shared<TestUtils::ColumnDataXARetrieve<xAOD::CaloClusterContainer>> (data.info, userConfiguration);
355 else if (name == "GSFTrackParticles")
356 data.reader = std::make_shared<TestUtils::ColumnDataXARetrieve<xAOD::TrackParticleContainer>> (data.info, userConfiguration);
357 else if (name == "GSFConversionVertices")
358 data.reader = std::make_shared<TestUtils::ColumnDataXARetrieve<xAOD::VertexContainer>> (data.info, userConfiguration);
359 }
360 } else
361 {
362 if (*data.info.type == typeid(float))
363 data.reader = std::make_shared<TestUtils::ColumnDataXAAccessor<float>> (data.info, userConfiguration);
364 else if (*data.info.type == typeid(double))
365 data.reader = std::make_shared<TestUtils::ColumnDataXAAccessor<double>> (data.info, userConfiguration);
366 else if (*data.info.type == typeid(char))
367 data.reader = std::make_shared<TestUtils::ColumnDataXAAccessor<char>> (data.info, userConfiguration);
368 else if (*data.info.type == typeid(std::uint8_t))
369 data.reader = std::make_shared<TestUtils::ColumnDataXAAccessor<std::uint8_t>> (data.info, userConfiguration);
370 else if (*data.info.type == typeid(std::uint16_t))
371 data.reader = std::make_shared<TestUtils::ColumnDataXAAccessor<std::uint16_t>> (data.info, userConfiguration);
372 else if (*data.info.type == typeid(std::uint32_t))
373 data.reader = std::make_shared<TestUtils::ColumnDataXAAccessor<std::uint32_t>> (data.info, userConfiguration);
374 else if (*data.info.type == typeid(std::uint64_t))
375 data.reader = std::make_shared<TestUtils::ColumnDataXAAccessor<std::uint64_t>> (data.info, userConfiguration);
376 else if (*data.info.type == typeid(std::vector<float>))
377 data.reader = std::make_shared<TestUtils::ColumnDataXAAccessor<std::vector<float>>> (data.info, userConfiguration);
378 else if (*data.info.type == typeid(std::vector<ElementLink<xAOD::CaloClusterContainer>>))
379 data.reader = std::make_shared<TestUtils::ColumnDataXAAccessor<std::vector<ElementLink<xAOD::CaloClusterContainer>>>> (data.info, userConfiguration);
380 else if (*data.info.type == typeid(std::vector<ElementLink<xAOD::TrackParticleContainer>>))
381 data.reader = std::make_shared<TestUtils::ColumnDataXAAccessor<std::vector<ElementLink<xAOD::TrackParticleContainer>>>> (data.info, userConfiguration);
382 else if (*data.info.type == typeid(std::vector<ElementLink<xAOD::VertexContainer>>))
383 data.reader = std::make_shared<TestUtils::ColumnDataXAAccessor<std::vector<ElementLink<xAOD::VertexContainer>>>> (data.info, userConfiguration);
384 }
385 }
386
387 bool allColumnsHandled = true;
388 for (auto& [name, data] : requestedColumns)
389 {
390 if (!data.reader)
391 {
392 allColumnsHandled = false;
393 std::cout << "WARNING: no handling for requested column: name=" << name << " offset=" << data.info.offsetName << " type=" << boost::core::demangle(data.info.type->name()) << std::endl;
394 }
395 }
396 if (!allColumnsHandled)
397 {
398 ADD_FAILURE() << "not all requested columns could be handled";
399 return;
400 }
401
402 for (auto& [name, data]: requestedColumns)
403 {
404 data.reader->connect (data, requestedColumns);
405 }
406
407 Benchmark benchmarkEmptyClear (testDefinition.name + " empty clear");
408 Benchmark benchmarkCallClear (testDefinition.name + " call clear");
409 Benchmark benchmarkGetEntry (testDefinition.name + " getEntry");
410 Benchmark benchmarkCheck (testDefinition.name + " check");
411 Benchmark benchmarkCall2 (testDefinition.name + " call2");
412 Benchmark benchmarkCall (testDefinition.name + " call");
413 Benchmark benchmarkEmpty ("empty");
414
415 const auto numberOfEvents = event.getEntries();
416 if (numberOfEvents == 0){
417 throw std::runtime_error ("ColumnarPhysLiteTest: numberOfEvents == 0");
418 }
419 Long64_t entry = 0;
420
421 // Instead of running for a fixed number of events, we run for a
422 // fixed amount of time. That is because individual tools can
423 // vary wildly in how long they take to run, and we mostly want to
424 // make sure that we ran the tool enough to get a precise
425 // performance estimate.
426 const auto startTime = std::chrono::high_resolution_clock::now();
427 for (; (std::chrono::high_resolution_clock::now() - startTime) < userConfiguration.targetTime; ++entry)
428 {
429 benchmarkEmpty.startTimer ();
430 benchmarkEmpty.stopTimer ();
431
432 benchmarkGetEntry.startTimer ();
433 event.getEntry (entry % numberOfEvents);
434 benchmarkGetEntry.stopTimer ();
435
436 ColumnVectorData columnData (&columnHeader);
437 for (auto& [name, data] : requestedColumns)
438 ASSERT_SUCCESS (data.reader->retrieveContainer (event, store, columnData));
439 for (auto& [name, data] : requestedColumns)
440 data.reader->retrieveAuxData (columnData);
441
442 benchmarkCheck.startTimer ();
443 columnData.checkData ();
444 benchmarkCheck.stopTimer ();
445 benchmarkCall.startTimer ();
446 columnData.callNoCheck (*myTool);
447 benchmarkCall.stopTimer ();
448 if (userConfiguration.runToolTwice)
449 {
450 benchmarkCall2.startTimer ();
451 columnData.callNoCheck (*myTool);
452 benchmarkCall2.stopTimer ();
453 }
454
455 benchmarkCallClear.startTimer ();
456 store.clear ();
457 benchmarkCallClear.stopTimer ();
458 benchmarkEmptyClear.startTimer ();
459 store.clear ();
460 benchmarkEmptyClear.stopTimer ();
461 }
462 std::cout << "Total entries read: " << entry << std::endl;
463 const float emptyTime = benchmarkEmpty.getEntryTime(0).value();
464 std::cout << "Empty benchmark time: " << emptyTime << "ns (tick=" << Benchmark::getTickDuration() << "ns)" << std::endl;
465 benchmarkEmpty.setSilence();
466 std::cout << "Average getEntry time: " << benchmarkGetEntry.getEntryTime(emptyTime).value() << "ns" << std::endl;
467 benchmarkGetEntry.setSilence();
468 std::cout << "Average clear time: " << benchmarkCallClear.getEntryTime(emptyTime).value() << "ns" << " (empty=" << benchmarkEmptyClear.getEntryTime(emptyTime).value() << "ns)" << std::endl;
469 benchmarkCallClear.setSilence();
470 benchmarkEmptyClear.setSilence();
471
472 // Column performance table
473 {
474 std::vector<BranchPerfData> columnPerfData;
476 summary.name = "total";
477 summary.timeRead = 0;
478 summary.timeReadAgain = 0;
479 summary.timeShallowCopy = 0;
480 summary.timeShallowRegister = 0;
481 for (auto& [name, data] : requestedColumns)
482 {
483 auto perfData = data.reader->getPerfData(emptyTime);
484 if (perfData.timeRead.has_value() || perfData.timeReadAgain.has_value())
485 {
486 columnPerfData.push_back(perfData);
487 summary.timeRead.value() += perfData.timeRead.value_or(0);
488 summary.timeReadAgain.value() += perfData.timeReadAgain.value_or(0);
489 summary.timeShallowCopy.value() += perfData.timeShallowCopy.value_or(0);
490 summary.timeShallowRegister.value() += perfData.timeShallowRegister.value_or(0);
491 }
492 }
493 std::sort(columnPerfData.begin(), columnPerfData.end(), [](const auto& a, const auto& b) { return a.name < b.name; });
494 columnPerfData.push_back(summary);
495
496 const std::size_t nameWidth = std::max_element(columnPerfData.begin(), columnPerfData.end(), [](const auto& a, const auto& b) { return a.name.size() < b.name.size(); })->name.size();
497 std::string header = std::format("{:{}} | 1st(ns) | 2nd(ns) | shallow copy(ns)", "column name", nameWidth);
498 std::cout << "\n" << header << std::endl;
499 std::cout << std::string(header.size(), '-') << std::endl;
500 for (auto& data : columnPerfData)
501 {
502 if (data.name == "total")
503 std::cout << std::string(header.size(), '-') << std::endl;
504 std::cout << std::format("{:{}} |", data.name, nameWidth);
505 if (data.timeRead)
506 std::cout << std::format("{:>8.0f} |", data.timeRead.value());
507 else
508 std::cout << " |";
509 if (data.timeReadAgain)
510 std::cout << std::format("{:>8.1f} |", data.timeReadAgain.value());
511 else
512 std::cout << " |";
513 if (data.timeShallowCopy || data.timeShallowRegister)
514 std::cout << std::format("{:>10.0f} +{:>5.0f}", data.timeShallowCopy.value_or(-1), data.timeShallowRegister .value_or(-1));
515 std::cout << std::endl;
516 }
517 }
518
519 // Tool performance table
520 {
521 std::vector<ToolPerfData> toolPerfData;
522 toolPerfData.emplace_back();
523 toolPerfData.back().name = testDefinition.name;
524 toolPerfData.back().timeCall = benchmarkCall.getEntryTime(emptyTime);
525 if (userConfiguration.runToolTwice)
526 toolPerfData.back().timeCall2 = benchmarkCall2.getEntryTime(emptyTime);
527 toolPerfData.back().timeCheck = benchmarkCheck.getEntryTime(emptyTime);
528 benchmarkCall.setSilence();
529 benchmarkCall2.setSilence();
530 benchmarkCheck.setSilence();
531
532 const std::size_t nameWidth = std::max_element(toolPerfData.begin(), toolPerfData.end(), [](const auto& a, const auto& b) { return a.name.size() < b.name.size(); })->name.size();
533 std::string header = std::format("{:{}} | call(ns) | call2(ns) | check(ns)", "tool name", nameWidth);
534 std::cout << "\n" << header << std::endl;
535 std::cout << std::string(header.size(), '-') << std::endl;
536 for (auto& data : toolPerfData)
537 {
538 std::cout << std::format("{:{}} |", data.name, nameWidth);
539 if (data.timeCall)
540 std::cout << std::format("{:>9.0f} |", data.timeCall.value());
541 else
542 std::cout << " |";
543 if (data.timeCall2)
544 std::cout << std::format("{:>10.0f} |", data.timeCall2.value());
545 else
546 std::cout << " |";
547 if (data.timeCheck)
548 std::cout << std::format("{:>10.1f}", data.timeCheck.value());
549 std::cout << std::endl;
550 }
551 }
552 }
#define ANA_CHECK_THROW(EXP)
check whether the given expression was successful, throwing an exception on failure
int numberOfEvents()
static Double_t a
the header information for the entire columnar data vector
the base class for all columnar components
this is a simple benchmarking helper class wrapping timers from std::chrono
Definition Benchmark.h:51
static float getTickDuration()
Definition Benchmark.h:86
a class that interfaces an IColumnarTool to a ColumnVectorHeader
Tool for accessing xAOD files outside of Athena.
A relatively simple transient store for objects created in analysis.
Definition TStore.h:45
TestStore store
Definition TestStore.cxx:23
void renameContainers(IColumnarTool &tool, const std::vector< std::pair< std::string, std::string > > &renames)
rename containers in the columnar tool
const std::string eventRangeColumnName
the default name for the column containing the event range
std::size_t ColumnarOffsetType
the type used for the size and offsets in the columnar data
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
the performance data for reading a single branch/column
std::vector< std::pair< std::string, std::string > > containerRenames
the container name remappings to apply
TFile * file

◆ runXaodTest()

void columnar::TestUtils::runXaodTest ( const UserConfiguration & userConfiguration,
std::span< const TestDefinition > testDefinitions,
TFile * file )

Definition at line 267 of file PhysliteTestXaod.cxx.

268 {
269 using namespace asg::msgUserCode;
270
271 auto eventReader = makeEventReader();
272 ANA_CHECK_THROW(eventReader->readFrom(file));
273
274 std::vector<ToolData> toolDataVec;
275 for (const auto& testDefinition : testDefinitions)
276 {
277 if (testDefinition.xAODToolCaller != nullptr)
278 {
279 ToolData toolData;
280 toolData.name = testDefinition.name;
281 toolData.xAODToolCaller = testDefinition.xAODToolCaller;
282 toolData.noRepeatCall = testDefinition.noRepeatCall;
283 toolDataVec.push_back(std::move(toolData));
284 }
285 }
286
287 IXAODToolCaller::EventStoreType* evtStore = nullptr;
288 if (!testDefinitions.empty() && testDefinitions[0].tool)
289 evtStore = &*testDefinitions[0].tool->evtStore();
290
291 Benchmark benchmarkEmpty;
292
293 const std::uint64_t numberOfEvents = eventReader->getEntries();
294 if (numberOfEvents == 0){
295 throw std::runtime_error ("ColumnarPhysLiteTest: numberOfEvents == 0");
296 }
297 std::uint64_t entry = 0;
298
299 // Instead of running for a fixed number of events, we run for a
300 // fixed amount of time. That is because individual tools can
301 // vary wildly in how long they take to run, and we mostly want to
302 // make sure that we ran the tool enough to get a precise
303 // performance estimate.
304 const auto startTime = std::chrono::high_resolution_clock::now();
305 for (; (std::chrono::high_resolution_clock::now() - startTime) < userConfiguration.targetTime; ++entry)
306 {
307 benchmarkEmpty.startTimer();
308 benchmarkEmpty.stopTimer();
309 ANA_CHECK_THROW(eventReader->getEntry(entry % numberOfEvents));
310 if (eventReader->hasClearStore())
311 {
312 static const std::string prepPostfix = "Prep";
313 for (auto& toolData : toolDataVec)
314 ASSERT_SUCCESS (toolData.retrieve (0, *evtStore));
315 for (auto& toolData : toolDataVec)
316 ASSERT_SUCCESS (toolData.copyRecord (0, *evtStore, prepPostfix));
317 for (auto& toolData : toolDataVec)
318 ASSERT_SUCCESS (toolData.call (0));
319 for (auto& toolData : toolDataVec)
320 toolData.clear (0);
321 eventReader->clearStore();
322 }
323 static const std::string callPostfix = "Call";
324 for (auto& toolData : toolDataVec)
325 ASSERT_SUCCESS (toolData.retrieve (1, *evtStore));
326 for (auto& toolData : toolDataVec)
327 ASSERT_SUCCESS (toolData.copyRecord (1, *evtStore, callPostfix));
328 for (auto& toolData : toolDataVec)
329 {
330 ASSERT_SUCCESS (toolData.call (1));
331 // a second call, immediately after, to have the tool in
332 // instruction cache and simulate it being run on multi-event
333 // batches. this is a bit too good, as it will run on exactly
334 // the same event, instead of different events as would happen
335 // in a real multi-event batch.
336 if (userConfiguration.runToolTwice && !toolData.noRepeatCall)
337 {
338 ASSERT_SUCCESS (toolData.call (2));
339 }
340 }
341 for (auto& toolData : toolDataVec)
342 toolData.clear (1);
343 if (eventReader->hasClearStore())
344 eventReader->clearStore();
345 }
346 std::cout << "Total entries read: " << entry << std::endl;
347 const float emptyTime = benchmarkEmpty.getEntryTime(0).value();
348 std::cout << "Empty benchmark time: " << emptyTime << "ns (tick=" << Benchmark::getTickDuration() << "ns)" << std::endl;
349 eventReader->printBenchmarkTable(emptyTime);
350
351 // Fill vector of ToolPerfData pairs from benchmarks
352 std::vector<std::pair<ToolPerfData, ToolPerfData>> toolPerfData;
353 for (auto& toolData : toolDataVec)
354 {
355 ToolPerfData prepPerfData;
356 prepPerfData.name = toolData.name;
357 if (eventReader->hasClearStore()) {
358 prepPerfData.timeRetrieve = toolData.benchmarkRetrieve[0].getEntryTime(emptyTime);
359 prepPerfData.timeCopyRecord = toolData.benchmarkCopyRecord[0].getEntryTime(emptyTime);
360 prepPerfData.timeCall = toolData.benchmarkCall[0].getEntryTime(emptyTime);
361 prepPerfData.timeClear = toolData.benchmarkClear[0].getEntryTime(emptyTime);
362 toolData.benchmarkRetrieve[0].setSilence();
363 toolData.benchmarkCopyRecord[0].setSilence();
364 toolData.benchmarkCall[0].setSilence();
365 toolData.benchmarkClear[0].setSilence();
366 }
367
368 ToolPerfData callPerfData;
369 callPerfData.name = toolData.name;
370 callPerfData.timeRetrieve = toolData.benchmarkRetrieve[1].getEntryTime(emptyTime);
371 callPerfData.timeCopyRecord = toolData.benchmarkCopyRecord[1].getEntryTime(emptyTime);
372 callPerfData.timeCall = toolData.benchmarkCall[1].getEntryTime(emptyTime);
373 callPerfData.timeClear = toolData.benchmarkClear[1].getEntryTime(emptyTime);
374 if (userConfiguration.runToolTwice) {
375 callPerfData.timeCall2 = toolData.benchmarkCall[2].getEntryTime(emptyTime);
376 toolData.benchmarkCall[2].setSilence();
377 }
378 toolData.benchmarkRetrieve[1].setSilence();
379 toolData.benchmarkCopyRecord[1].setSilence();
380 toolData.benchmarkCall[1].setSilence();
381 toolData.benchmarkClear[1].setSilence();
382
383 toolPerfData.emplace_back(std::move(prepPerfData), std::move(callPerfData));
384 }
385
386 // Helper lambda for printing optional time values
387 auto printOptionalTime = [](std::optional<float> time, int width, bool trailingBar = true) {
388 if (time)
389 std::cout << std::format("{:>{}.0f}", time.value(), width);
390 else
391 std::cout << std::format("{:>{}}", "", width);
392 if (trailingBar)
393 std::cout << " |";
394 };
395
396 // Calculate name width from all entries
397 std::size_t nameWidth = std::string_view("tool name").size();
398 for (const auto& [prep, call] : toolPerfData)
399 nameWidth = std::max(nameWidth, prep.name.size());
400
401 // Print tool performance table with grouped columns
402 std::string groupHeader = std::format("{:{}} |{:^42}|{:^52}",
403 "", nameWidth, "prep", "call");
404 std::string colHeader = std::format("{:{}} | retr(ns) | copy(ns) | call(ns) | clr(ns) | retr(ns) | copy(ns) | call(ns) | 2nd(ns) | clr(ns)",
405 "tool name", nameWidth);
406
407 std::cout << "\ntool benchmarks:" << std::endl;
408 std::cout << groupHeader << std::endl;
409 std::cout << colHeader << std::endl;
410 std::cout << std::string(colHeader.size(), '-') << std::endl;
411
412 // Print data rows
413 for (const auto& [prep, call] : toolPerfData)
414 {
415 std::cout << std::format("{:{}} |", prep.name, nameWidth);
416 printOptionalTime(prep.timeRetrieve, 9);
417 printOptionalTime(prep.timeCopyRecord, 9);
418 printOptionalTime(prep.timeCall, 9);
419 printOptionalTime(prep.timeClear, 8);
420 printOptionalTime(call.timeRetrieve, 9);
421 printOptionalTime(call.timeCopyRecord, 9);
422 printOptionalTime(call.timeCall, 9);
423 printOptionalTime(call.timeCall2, 8);
424 printOptionalTime(call.timeClear, 8, false);
425 std::cout << std::endl;
426 }
427
428 // Print total line only when there are multiple tools
429 if (toolPerfData.size() > 1)
430 {
431 std::optional<float> totalPrepRetrieve, totalPrepCopyRecord, totalPrepCall, totalPrepClear;
432 std::optional<float> totalCallRetrieve, totalCallCopyRecord, totalCallCall, totalCallClear, totalRepeat;
433 for (const auto& [prep, call] : toolPerfData)
434 {
435 if (prep.timeRetrieve)
436 totalPrepRetrieve = totalPrepRetrieve.value_or(0) + prep.timeRetrieve.value();
437 if (prep.timeCopyRecord)
438 totalPrepCopyRecord = totalPrepCopyRecord.value_or(0) + prep.timeCopyRecord.value();
439 if (prep.timeCall)
440 totalPrepCall = totalPrepCall.value_or(0) + prep.timeCall.value();
441 if (prep.timeClear)
442 totalPrepClear = totalPrepClear.value_or(0) + prep.timeClear.value();
443 if (call.timeRetrieve)
444 totalCallRetrieve = totalCallRetrieve.value_or(0) + call.timeRetrieve.value();
445 if (call.timeCopyRecord)
446 totalCallCopyRecord = totalCallCopyRecord.value_or(0) + call.timeCopyRecord.value();
447 if (call.timeCall)
448 totalCallCall = totalCallCall.value_or(0) + call.timeCall.value();
449 if (call.timeClear)
450 totalCallClear = totalCallClear.value_or(0) + call.timeClear.value();
451 if (call.timeCall2)
452 totalRepeat = totalRepeat.value_or(0) + call.timeCall2.value();
453 }
454
455 std::cout << std::string(colHeader.size(), '-') << std::endl;
456 std::cout << std::format("{:{}} |", "total", nameWidth);
457 printOptionalTime(totalPrepRetrieve, 9);
458 printOptionalTime(totalPrepCopyRecord, 9);
459 printOptionalTime(totalPrepCall, 9);
460 printOptionalTime(totalPrepClear, 8);
461 printOptionalTime(totalCallRetrieve, 9);
462 printOptionalTime(totalCallCopyRecord, 9);
463 printOptionalTime(totalCallCall, 9);
464 printOptionalTime(totalRepeat, 8);
465 printOptionalTime(totalCallClear, 8, false);
466 std::cout << std::endl;
467 }
468 }
const double width
std::optional< float > getEntryTime(float emptyTime) const
Definition Benchmark.h:74
std::decay_t< decltype(*std::declval< asg::AsgTool >().evtStore())> EventStoreType
the type used for the event store
time(flags, cells_name, *args, **kw)
call(args, bufsize=0, executable=None, stdin=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, message="", logger=msg, loglevel=None, timeout=None, retry=2, timefactor=1.5, sleeptime=10)
Definition trfUtils.py:157
the performance data for running a single tool