@@ -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 = printHeatMap ())
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);
@@ -1323,7 +1294,7 @@ bool DataAggregator::ignoreKernelInterrupt(LBREntry &LBR) const {
13231294 (LBR.From >= KernelBaseAddr || LBR.To >= KernelBaseAddr);
13241295}
13251296
1326- std::error_code DataAggregator::printLBRHeatMap () {
1297+ std::error_code DataAggregator::printHeatMap () {
13271298 outs () << " PERF2BOLT: parse branch events...\n " ;
13281299 NamedRegionTimer T (" parseBranch" , " Parsing branch events" , TimerGroupName,
13291300 TimerGroupDesc, opts::TimeAggregator);
@@ -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,10 +1320,14 @@ std::error_code DataAggregator::printLBRHeatMap() {
13961320
13971321 outs () << " HEATMAP: building heat map...\n " ;
13981322
1399- for (const auto &LBR : FallthroughLBRs) {
1400- const Trace &Trace = LBR.first ;
1401- const FTInfo &Info = LBR.second ;
1402- HM.registerAddressRange (Trace.From , Trace.To , Info.InternCount );
1323+ if (opts::BasicAggregation) {
1324+ for (const auto &[PC, Hits] : BasicSamples)
1325+ HM.registerAddress (PC, Hits);
1326+ } else {
1327+ for (const auto &[Trace, Info] : FallthroughLBRs)
1328+ HM.registerAddressRange (Trace.From , Trace.To , Info.InternCount );
1329+ for (const auto &[Trace, Info] : BranchLBRs)
1330+ HM.registerAddress (Trace.From , Info.TakenCount );
14031331 }
14041332
14051333 if (HM.getNumInvalidRanges ())
0 commit comments