Skip to content

Commit 0c77468

Browse files
authored
[BOLT] Expose external entry count for functions (#141674)
Record the number of function invocations from external code - code outside the binary, which may include JIT code and DSOs. Accounting external entry counts improves the fidelity of call graph flow conservation analysis. Test Plan: updated shrinkwrapping.test
1 parent 13ccce2 commit 0c77468

File tree

10 files changed

+33
-0
lines changed

10 files changed

+33
-0
lines changed

bolt/include/bolt/Core/BinaryFunction.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,10 @@ class BinaryFunction {
388388
/// The profile data for the number of times the function was executed.
389389
uint64_t ExecutionCount{COUNT_NO_PROFILE};
390390

391+
/// Profile data for the number of times this function was entered from
392+
/// external code (DSO, JIT, etc).
393+
uint64_t ExternEntryCount{0};
394+
391395
/// Profile match ratio.
392396
float ProfileMatchRatio{0.0f};
393397

@@ -1877,6 +1881,10 @@ class BinaryFunction {
18771881
return *this;
18781882
}
18791883

1884+
/// Set the profile data for the number of times the function was entered from
1885+
/// external code (DSO/JIT).
1886+
void setExternEntryCount(uint64_t Count) { ExternEntryCount = Count; }
1887+
18801888
/// Adjust execution count for the function by a given \p Count. The value
18811889
/// \p Count will be subtracted from the current function count.
18821890
///
@@ -1904,6 +1912,10 @@ class BinaryFunction {
19041912
/// Return COUNT_NO_PROFILE if there's no profile info.
19051913
uint64_t getExecutionCount() const { return ExecutionCount; }
19061914

1915+
/// Return the profile information about the number of times the function was
1916+
/// entered from external code (DSO/JIT).
1917+
uint64_t getExternEntryCount() const { return ExternEntryCount; }
1918+
19071919
/// Return the raw profile information about the number of branch
19081920
/// executions corresponding to this function.
19091921
uint64_t getRawSampleCount() const { return RawSampleCount; }

bolt/include/bolt/Profile/DataReader.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ struct FuncBranchData {
9797
/// Total execution count for the function.
9898
int64_t ExecutionCount{0};
9999

100+
/// Total entry count from external code for the function.
101+
uint64_t ExternEntryCount{0};
102+
100103
/// Indicate if the data was used.
101104
bool Used{false};
102105

bolt/include/bolt/Profile/ProfileYAMLMapping.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ struct BinaryFunctionProfile {
206206
uint32_t Id{0};
207207
llvm::yaml::Hex64 Hash{0};
208208
uint64_t ExecCount{0};
209+
uint64_t ExternEntryCount{0};
209210
std::vector<BinaryBasicBlockProfile> Blocks;
210211
std::vector<InlineTreeNode> InlineTree;
211212
bool Used{false};
@@ -218,6 +219,7 @@ template <> struct MappingTraits<bolt::BinaryFunctionProfile> {
218219
YamlIO.mapRequired("fid", BFP.Id);
219220
YamlIO.mapRequired("hash", BFP.Hash);
220221
YamlIO.mapRequired("exec", BFP.ExecCount);
222+
YamlIO.mapOptional("extern", BFP.ExternEntryCount, 0);
221223
YamlIO.mapRequired("nblocks", BFP.NumBasicBlocks);
222224
YamlIO.mapOptional("blocks", BFP.Blocks,
223225
std::vector<bolt::BinaryBasicBlockProfile>());

bolt/lib/Core/BinaryFunction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,8 @@ void BinaryFunction::print(raw_ostream &OS, std::string Annotation) {
471471
OS << "\n Sample Count: " << RawSampleCount;
472472
OS << "\n Profile Acc : " << format("%.1f%%", ProfileMatchRatio * 100.0f);
473473
}
474+
if (ExternEntryCount)
475+
OS << "\n Extern Entry Count: " << ExternEntryCount;
474476

475477
if (opts::PrintDynoStats && !getLayout().block_empty()) {
476478
OS << '\n';

bolt/lib/Passes/ProfileQualityStats.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,9 @@ void computeFlowMappings(const BinaryContext &BC, FlowInfo &TotalFlowMap) {
532532
std::vector<uint64_t> &MaxCountMap = TotalMaxCountMaps[FunctionNum];
533533
std::vector<uint64_t> &MinCountMap = TotalMinCountMaps[FunctionNum];
534534

535+
// Record external entry count into CallGraphIncomingFlows
536+
CallGraphIncomingFlows[FunctionNum] += Function->getExternEntryCount();
537+
535538
// Update MaxCountMap, MinCountMap, and CallGraphIncomingFlows
536539
auto recordCall = [&](const BinaryBasicBlock *SourceBB,
537540
const MCSymbol *DestSymbol, uint64_t Count,

bolt/lib/Profile/DataAggregator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2255,6 +2255,7 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
22552255
YamlBF.Id = BF->getFunctionNumber();
22562256
YamlBF.Hash = BAT->getBFHash(FuncAddress);
22572257
YamlBF.ExecCount = BF->getKnownExecutionCount();
2258+
YamlBF.ExternEntryCount = BF->getExternEntryCount();
22582259
YamlBF.NumBasicBlocks = BAT->getNumBasicBlocks(FuncAddress);
22592260
const BoltAddressTranslation::BBHashMapTy &BlockMap =
22602261
BAT->getBBHashMap(FuncAddress);

bolt/lib/Profile/DataReader.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ void FuncBranchData::appendFrom(const FuncBranchData &FBD, uint64_t Offset) {
8585
}
8686
llvm::stable_sort(Data);
8787
ExecutionCount += FBD.ExecutionCount;
88+
ExternEntryCount += FBD.ExternEntryCount;
8889
for (auto I = FBD.EntryData.begin(), E = FBD.EntryData.end(); I != E; ++I) {
8990
assert(I->To.Name == FBD.Name);
9091
auto NewElmt = EntryData.insert(EntryData.end(), *I);
@@ -269,6 +270,7 @@ Error DataReader::preprocessProfile(BinaryContext &BC) {
269270
if (FuncBranchData *FuncData = getBranchDataForNames(Function.getNames())) {
270271
setBranchData(Function, FuncData);
271272
Function.ExecutionCount = FuncData->ExecutionCount;
273+
Function.ExternEntryCount = FuncData->ExternEntryCount;
272274
FuncData->Used = true;
273275
}
274276
}
@@ -419,6 +421,7 @@ void DataReader::matchProfileData(BinaryFunction &BF) {
419421
if (fetchProfileForOtherEntryPoints(BF)) {
420422
BF.ProfileMatchRatio = evaluateProfileData(BF, *FBD);
421423
BF.ExecutionCount = FBD->ExecutionCount;
424+
BF.ExternEntryCount = FBD->ExternEntryCount;
422425
BF.RawSampleCount = FBD->getNumExecutedBranches();
423426
}
424427
return;
@@ -449,6 +452,7 @@ void DataReader::matchProfileData(BinaryFunction &BF) {
449452
setBranchData(BF, NewBranchData);
450453
NewBranchData->Used = true;
451454
BF.ExecutionCount = NewBranchData->ExecutionCount;
455+
BF.ExternEntryCount = NewBranchData->ExternEntryCount;
452456
BF.ProfileMatchRatio = 1.0f;
453457
break;
454458
}
@@ -1190,6 +1194,8 @@ std::error_code DataReader::parse() {
11901194
if (BI.To.IsSymbol && BI.To.Offset == 0) {
11911195
I = GetOrCreateFuncEntry(BI.To.Name);
11921196
I->second.ExecutionCount += BI.Branches;
1197+
if (!BI.From.IsSymbol)
1198+
I->second.ExternEntryCount += BI.Branches;
11931199
}
11941200
}
11951201

bolt/lib/Profile/YAMLProfileReader.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ bool YAMLProfileReader::parseFunctionProfile(
176176
uint64_t FunctionExecutionCount = 0;
177177

178178
BF.setExecutionCount(YamlBF.ExecCount);
179+
BF.setExternEntryCount(YamlBF.ExternEntryCount);
179180

180181
uint64_t FuncRawBranchCount = 0;
181182
for (const yaml::bolt::BinaryBasicBlockProfile &YamlBB : YamlBF.Blocks)

bolt/lib/Profile/YAMLProfileWriter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS,
226226
YamlBF.Hash = BF.getHash();
227227
YamlBF.NumBasicBlocks = BF.size();
228228
YamlBF.ExecCount = BF.getKnownExecutionCount();
229+
YamlBF.ExternEntryCount = BF.getExternEntryCount();
229230
DenseMap<const MCDecodedPseudoProbeInlineTree *, uint32_t> InlineTreeNodeId;
230231
if (PseudoProbeDecoder && BF.getGUID()) {
231232
std::tie(YamlBF.InlineTree, InlineTreeNodeId) =

bolt/test/X86/shrinkwrapping.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ REQUIRES: shell
88

99
RUN: %clangxx %cxxflags -no-pie %S/Inputs/exc4sw.S -o %t.exe -Wl,-q
1010
RUN: llvm-bolt %t.exe -o %t --relocs --frame-opt=all \
11+
RUN: --print-only=main --print-cfg \
1112
RUN: --data=%p/Inputs/exc4sw.fdata --reorder-blocks=cache 2>&1 | \
1213
RUN: FileCheck %s --check-prefix=CHECK-BOLT
1314

@@ -19,6 +20,7 @@ RUN: llvm-objdump --dwarf=frames %t | grep -A20 -e \
1920
RUN: `llvm-nm --numeric-sort %t | grep main | tail -n 1 | cut -f1 -d' ' | \
2021
RUN: tail -c9` 2>&1 | FileCheck %s --check-prefix=CHECK-OUTPUT
2122

23+
CHECK-BOLT: Extern Entry Count: 100
2224
CHECK-BOLT: Shrink wrapping moved 2 spills inserting load/stores and 0 spills inserting push/pops
2325

2426
CHECK-INPUT: DW_CFA_advance_loc: 2

0 commit comments

Comments
 (0)