@@ -499,18 +499,15 @@ Error DataAggregator::preprocessProfile(BinaryContext &BC) {
499499 filterBinaryMMapInfo ();
500500 prepareToParse (" events" , MainEventsPPI, ErrorCallback);
501501
502+ if (opts::BasicAggregation ? parseBasicEvents () : parseBranchEvents ())
503+ errs () << " PERF2BOLT: failed to parse samples\n " ;
504+
502505 if (opts::HeatmapMode) {
503- if (std::error_code EC = printLBRHeatMap ()) {
504- errs () << " ERROR: failed to print heat map: " << EC.message () << ' \n ' ;
505- exit (1 );
506- }
506+ if (std::error_code EC = printLBRHeatMap ())
507+ return errorCodeToError (EC);
507508 exit (0 );
508509 }
509510
510- if ((!opts::BasicAggregation && parseBranchEvents ()) ||
511- (opts::BasicAggregation && parseBasicEvents ()))
512- errs () << " PERF2BOLT: failed to parse samples\n " ;
513-
514511 // Special handling for memory events
515512 if (prepareToParse (" mem events" , MemEventsPPI, MemEventsErrorCallback))
516513 return Error::success ();
@@ -567,15 +564,14 @@ void DataAggregator::processProfile(BinaryContext &BC) {
567564 processMemEvents ();
568565
569566 // Mark all functions with registered events as having a valid profile.
570- const auto Flags = opts::BasicAggregation ? BinaryFunction::PF_SAMPLE
571- : BinaryFunction::PF_LBR;
572567 for (auto &BFI : BC.getBinaryFunctions ()) {
573568 BinaryFunction &BF = BFI.second ;
574- FuncBranchData *FBD = getBranchData (BF);
575- if (FBD || getFuncSampleData (BF.getNames ())) {
576- BF.markProfiled (Flags);
577- if (FBD)
578- BF.RawBranchCount = FBD->getNumExecutedBranches ();
569+ if (FuncBranchData *FBD = getBranchData (BF)) {
570+ BF.markProfiled (BinaryFunction::PF_LBR);
571+ BF.RawSampleCount = FBD->getNumExecutedBranches ();
572+ } else if (FuncSampleData *FSD = getFuncSampleData (BF.getNames ())) {
573+ BF.markProfiled (BinaryFunction::PF_SAMPLE);
574+ BF.RawSampleCount = FSD->getSamples ();
579575 }
580576 }
581577
@@ -632,10 +628,18 @@ StringRef DataAggregator::getLocationName(const BinaryFunction &Func,
632628
633629bool DataAggregator::doSample (BinaryFunction &OrigFunc, uint64_t Address,
634630 uint64_t Count) {
631+ // To record executed bytes, use basic block size as is regardless of BAT.
632+ uint64_t BlockSize = 0 ;
633+ if (BinaryBasicBlock *BB = OrigFunc.getBasicBlockContainingOffset (
634+ Address - OrigFunc.getAddress ()))
635+ BlockSize = BB->getOriginalSize ();
636+
635637 BinaryFunction *ParentFunc = getBATParentFunction (OrigFunc);
636638 BinaryFunction &Func = ParentFunc ? *ParentFunc : OrigFunc;
637- if (ParentFunc || (BAT && !BAT->isBATFunction (OrigFunc .getAddress ())))
639+ if (ParentFunc || (BAT && !BAT->isBATFunction (Func .getAddress ())))
638640 NumColdSamples += Count;
641+ // Attach executed bytes to parent function in case of cold fragment.
642+ Func.SampleCountInBytes += Count * BlockSize;
639643
640644 auto I = NamesToSamples.find (Func.getOneName ());
641645 if (I == NamesToSamples.end ()) {
@@ -720,23 +724,6 @@ bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count,
720724 : isReturn (Func.disassembleInstructionAtOffset (Offset));
721725 };
722726
723- // Returns whether \p Offset in \p Func may be a call continuation excluding
724- // entry points and landing pads.
725- auto checkCallCont = [&](const BinaryFunction &Func, const uint64_t Offset) {
726- // No call continuation at a function start.
727- if (!Offset)
728- return false ;
729-
730- // FIXME: support BAT case where the function might be in empty state
731- // (split fragments declared non-simple).
732- if (!Func.hasCFG ())
733- return false ;
734-
735- // The offset should not be an entry point or a landing pad.
736- const BinaryBasicBlock *ContBB = Func.getBasicBlockAtOffset (Offset);
737- return ContBB && !ContBB->isEntryPoint () && !ContBB->isLandingPad ();
738- };
739-
740727 // Mutates \p Addr to an offset into the containing function, performing BAT
741728 // offset translation and parent lookup.
742729 //
@@ -749,8 +736,7 @@ bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count,
749736
750737 Addr -= Func->getAddress ();
751738
752- bool IsRetOrCallCont =
753- IsFrom ? checkReturn (*Func, Addr) : checkCallCont (*Func, Addr);
739+ bool IsRet = IsFrom && checkReturn (*Func, Addr);
754740
755741 if (BAT)
756742 Addr = BAT->translate (Func->getAddress (), Addr, IsFrom);
@@ -761,24 +747,16 @@ bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count,
761747 NumColdSamples += Count;
762748
763749 if (!ParentFunc)
764- return std::pair{Func, IsRetOrCallCont };
750+ return std::pair{Func, IsRet };
765751
766- return std::pair{ParentFunc, IsRetOrCallCont };
752+ return std::pair{ParentFunc, IsRet };
767753 };
768754
769- uint64_t ToOrig = To;
770755 auto [FromFunc, IsReturn] = handleAddress (From, /* IsFrom*/ true );
771- auto [ToFunc, IsCallCont ] = handleAddress (To, /* IsFrom*/ false );
756+ auto [ToFunc, _ ] = handleAddress (To, /* IsFrom*/ false );
772757 if (!FromFunc && !ToFunc)
773758 return false ;
774759
775- // Record call to continuation trace.
776- if (NeedsConvertRetProfileToCallCont && FromFunc != ToFunc &&
777- (IsReturn || IsCallCont)) {
778- LBREntry First{ToOrig - 1 , ToOrig - 1 , false };
779- LBREntry Second{ToOrig, ToOrig, false };
780- return doTrace (First, Second, Count);
781- }
782760 // Ignore returns.
783761 if (IsReturn)
784762 return true ;
@@ -1235,21 +1213,14 @@ std::error_code DataAggregator::parseAggregatedLBREntry() {
12351213 ErrorOr<StringRef> TypeOrErr = parseString (FieldSeparator);
12361214 if (std::error_code EC = TypeOrErr.getError ())
12371215 return EC;
1238- // Pre-aggregated profile with branches and fallthroughs needs to convert
1239- // return profile into call to continuation fall-through.
1240- auto Type = AggregatedLBREntry::BRANCH;
1241- if (TypeOrErr.get () == " B" ) {
1242- NeedsConvertRetProfileToCallCont = true ;
1216+ auto Type = AggregatedLBREntry::TRACE;
1217+ if (LLVM_LIKELY (TypeOrErr.get () == " T" )) {
1218+ } else if (TypeOrErr.get () == " B" ) {
12431219 Type = AggregatedLBREntry::BRANCH;
12441220 } else if (TypeOrErr.get () == " F" ) {
1245- NeedsConvertRetProfileToCallCont = true ;
12461221 Type = AggregatedLBREntry::FT;
12471222 } else if (TypeOrErr.get () == " f" ) {
1248- NeedsConvertRetProfileToCallCont = true ;
12491223 Type = AggregatedLBREntry::FT_EXTERNAL_ORIGIN;
1250- } else if (TypeOrErr.get () == " T" ) {
1251- // Trace is expanded into B and [Ff]
1252- Type = AggregatedLBREntry::TRACE;
12531224 } else {
12541225 reportError (" expected T, B, F or f" );
12551226 return make_error_code (llvm::errc::io_error);
@@ -1334,53 +1305,6 @@ std::error_code DataAggregator::printLBRHeatMap() {
13341305 }
13351306 Heatmap HM (opts::HeatmapBlock, opts::HeatmapMinAddress,
13361307 opts::HeatmapMaxAddress, getTextSections (BC));
1337- uint64_t NumTotalSamples = 0 ;
1338-
1339- if (opts::BasicAggregation) {
1340- while (hasData ()) {
1341- ErrorOr<PerfBasicSample> SampleRes = parseBasicSample ();
1342- if (std::error_code EC = SampleRes.getError ()) {
1343- if (EC == errc::no_such_process)
1344- continue ;
1345- return EC;
1346- }
1347- PerfBasicSample &Sample = SampleRes.get ();
1348- HM.registerAddress (Sample.PC );
1349- NumTotalSamples++;
1350- }
1351- outs () << " HEATMAP: read " << NumTotalSamples << " basic samples\n " ;
1352- } else {
1353- while (hasData ()) {
1354- ErrorOr<PerfBranchSample> SampleRes = parseBranchSample ();
1355- if (std::error_code EC = SampleRes.getError ()) {
1356- if (EC == errc::no_such_process)
1357- continue ;
1358- return EC;
1359- }
1360-
1361- PerfBranchSample &Sample = SampleRes.get ();
1362-
1363- // LBRs are stored in reverse execution order. NextLBR refers to the next
1364- // executed branch record.
1365- const LBREntry *NextLBR = nullptr ;
1366- for (const LBREntry &LBR : Sample.LBR ) {
1367- if (NextLBR) {
1368- // Record fall-through trace.
1369- const uint64_t TraceFrom = LBR.To ;
1370- const uint64_t TraceTo = NextLBR->From ;
1371- ++FallthroughLBRs[Trace (TraceFrom, TraceTo)].InternCount ;
1372- }
1373- NextLBR = &LBR;
1374- }
1375- if (!Sample.LBR .empty ()) {
1376- HM.registerAddress (Sample.LBR .front ().To );
1377- HM.registerAddress (Sample.LBR .back ().From );
1378- }
1379- NumTotalSamples += Sample.LBR .size ();
1380- }
1381- outs () << " HEATMAP: read " << NumTotalSamples << " LBR samples\n " ;
1382- outs () << " HEATMAP: " << FallthroughLBRs.size () << " unique traces\n " ;
1383- }
13841308
13851309 if (!NumTotalSamples) {
13861310 if (opts::BasicAggregation) {
@@ -1396,6 +1320,8 @@ std::error_code DataAggregator::printLBRHeatMap() {
13961320
13971321 outs () << " HEATMAP: building heat map...\n " ;
13981322
1323+ for (const auto &[PC, Hits] : BasicSamples)
1324+ HM.registerAddress (PC, Hits);
13991325 for (const auto &LBR : FallthroughLBRs) {
14001326 const Trace &Trace = LBR.first ;
14011327 const FTInfo &Info = LBR.second ;
@@ -1445,7 +1371,10 @@ void DataAggregator::parseLBRSample(const PerfBranchSample &Sample,
14451371 const uint64_t TraceTo = NextLBR->From ;
14461372 const BinaryFunction *TraceBF =
14471373 getBinaryFunctionContainingAddress (TraceFrom);
1448- if (TraceBF && TraceBF->containsAddress (TraceTo)) {
1374+ if (opts::HeatmapMode) {
1375+ FTInfo &Info = FallthroughLBRs[Trace (TraceFrom, TraceTo)];
1376+ ++Info.InternCount ;
1377+ } else if (TraceBF && TraceBF->containsAddress (TraceTo)) {
14491378 FTInfo &Info = FallthroughLBRs[Trace (TraceFrom, TraceTo)];
14501379 if (TraceBF->containsAddress (LBR.From ))
14511380 ++Info.InternCount ;
@@ -1479,6 +1408,11 @@ void DataAggregator::parseLBRSample(const PerfBranchSample &Sample,
14791408 }
14801409 NextLBR = &LBR;
14811410
1411+ if (opts::HeatmapMode) {
1412+ TakenBranchInfo &Info = BranchLBRs[Trace (LBR.From , LBR.To )];
1413+ ++Info.TakenCount ;
1414+ continue ;
1415+ }
14821416 uint64_t From = getBinaryFunctionContainingAddress (LBR.From ) ? LBR.From : 0 ;
14831417 uint64_t To = getBinaryFunctionContainingAddress (LBR.To ) ? LBR.To : 0 ;
14841418 if (!From && !To)
@@ -1487,6 +1421,10 @@ void DataAggregator::parseLBRSample(const PerfBranchSample &Sample,
14871421 ++Info.TakenCount ;
14881422 Info.MispredCount += LBR.Mispred ;
14891423 }
1424+ if (opts::HeatmapMode && !Sample.LBR .empty ()) {
1425+ ++BasicSamples[Sample.LBR .front ().To ];
1426+ ++BasicSamples[Sample.LBR .back ().From ];
1427+ }
14901428}
14911429
14921430void DataAggregator::printColdSamplesDiagnostic () const {
@@ -1663,13 +1601,15 @@ std::error_code DataAggregator::parseBasicEvents() {
16631601
16641602 if (!Sample->PC )
16651603 continue ;
1604+ ++NumTotalSamples;
16661605
16671606 if (BinaryFunction *BF = getBinaryFunctionContainingAddress (Sample->PC ))
16681607 BF->setHasProfileAvailable ();
16691608
16701609 ++BasicSamples[Sample->PC ];
16711610 EventNames.insert (Sample->EventName );
16721611 }
1612+ outs () << " PERF2BOLT: read " << NumTotalSamples << " basic samples\n " ;
16731613
16741614 return std::error_code ();
16751615}
@@ -1682,7 +1622,6 @@ void DataAggregator::processBasicEvents() {
16821622 for (auto &Sample : BasicSamples) {
16831623 const uint64_t PC = Sample.first ;
16841624 const uint64_t HitCount = Sample.second ;
1685- NumTotalSamples += HitCount;
16861625 BinaryFunction *Func = getBinaryFunctionContainingAddress (PC);
16871626 if (!Func) {
16881627 OutOfRangeSamples += HitCount;
@@ -1691,7 +1630,6 @@ void DataAggregator::processBasicEvents() {
16911630
16921631 doSample (*Func, PC, HitCount);
16931632 }
1694- outs () << " PERF2BOLT: read " << NumTotalSamples << " samples\n " ;
16951633
16961634 printBasicSamplesDiagnostics (OutOfRangeSamples);
16971635}
0 commit comments