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...
class  ColumnarTestToolHandle
 a handle to a columnar tool for running tests More...
struct  ColumnMapType
struct  UserConfiguration
 a struct holding user configuration for the PHYSLITE tests More...
struct  TestDefinition
 the general configuration for a single test More...
class  IXAODToolCaller
 a wrapper around a CP tool in xAOD mdoe to call it in the PHYSLITE test More...
class  ManualColumnData
 a class that holds manually specified column data More...
struct  BranchPerfData
 the performance data for reading a single branch/column 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  RNTupleBackend
class  BranchReader
class  BranchReaderArray
class  LinkColumnVector
class  RNTFieldReader
class  IColumnData
struct  ColumnDataEventCount
struct  ColumnDataScalar
struct  ColumnDataVector
struct  ColumnDataOutVector
struct  ColumnDataVectorVector
struct  ColumnDataVectorVectorVector
struct  ColumnDataMetNames
struct  ColumnDataOutputMet
struct  ColumnDataSamplingPattern

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