@@ -31,6 +31,10 @@ static cl::opt<bool>
31
31
IgnoreStackSamples (" ignore-stack-samples" , cl::init(false ), cl::ZeroOrMore,
32
32
cl::desc(" Ignore call stack samples for hybrid samples "
33
33
" and produce context-insensitive profile." ));
34
+ static cl::opt<bool >
35
+ ShowDetailedWarning (" show-detailed-warning" , cl::init(false ),
36
+ cl::ZeroOrMore,
37
+ cl::desc(" Show detailed warning message." ));
34
38
35
39
extern cl::opt<std::string> PerfTraceFilename;
36
40
extern cl::opt<bool > ShowDisassemblyOnly;
@@ -433,10 +437,16 @@ void HybridPerfReader::unwindSamples() {
433
437
}
434
438
435
439
// Warn about untracked frames due to missing probes.
436
- for (auto Address : AllUntrackedCallsites)
437
- WithColor::warning () << " Profile context truncated due to missing probe "
438
- << " for call instruction at "
439
- << format (" 0x%" PRIx64, Address) << " \n " ;
440
+ if (ShowDetailedWarning) {
441
+ for (auto Address : AllUntrackedCallsites)
442
+ WithColor::warning () << " Profile context truncated due to missing probe "
443
+ << " for call instruction at "
444
+ << format (" 0x%" PRIx64, Address) << " \n " ;
445
+ }
446
+
447
+ emitWarningSummary (AllUntrackedCallsites.size (), SampleCounters.size (),
448
+ " of profiled contexts are truncated due to missing probe "
449
+ " for call instruction." );
440
450
}
441
451
442
452
bool PerfScriptReader::extractLBRStack (TraceStream &TraceIt,
@@ -1008,12 +1018,105 @@ void HybridPerfReader::generateUnsymbolizedProfile() {
1008
1018
}
1009
1019
1010
1020
void PerfScriptReader::warnTruncatedStack () {
1011
- for (auto Address : InvalidReturnAddresses) {
1012
- WithColor::warning ()
1013
- << " Truncated stack sample due to invalid return address at "
1014
- << format (" 0x%" PRIx64, Address)
1015
- << " , likely caused by frame pointer omission\n " ;
1021
+ if (ShowDetailedWarning) {
1022
+ for (auto Address : InvalidReturnAddresses) {
1023
+ WithColor::warning ()
1024
+ << " Truncated stack sample due to invalid return address at "
1025
+ << format (" 0x%" PRIx64, Address)
1026
+ << " , likely caused by frame pointer omission\n " ;
1027
+ }
1028
+ }
1029
+ emitWarningSummary (
1030
+ InvalidReturnAddresses.size (), AggregatedSamples.size (),
1031
+ " of truncated stack samples due to invalid return address, "
1032
+ " likely caused by frame pointer omission." );
1033
+ }
1034
+
1035
+ void PerfScriptReader::emitWarningSummary (uint64_t Num, uint64_t Total,
1036
+ StringRef Msg) {
1037
+ if (!Total || !Num)
1038
+ return ;
1039
+ WithColor::warning () << format (" %.2f" , static_cast <double >(Num) * 100 / Total)
1040
+ << " %(" << Num << " /" << Total << " ) " << Msg << " \n " ;
1041
+ }
1042
+
1043
+ void PerfScriptReader::warnInvalidRange () {
1044
+ std::unordered_map<std::pair<uint64_t , uint64_t >, uint64_t ,
1045
+ pair_hash<uint64_t , uint64_t >>
1046
+ Ranges;
1047
+
1048
+ for (const auto &Item : AggregatedSamples) {
1049
+ const PerfSample *Sample = Item.first .getPtr ();
1050
+ uint64_t Count = Item.second ;
1051
+ uint64_t EndOffeset = 0 ;
1052
+ for (const LBREntry &LBR : Sample->LBRStack ) {
1053
+ uint64_t SourceOffset = Binary->virtualAddrToOffset (LBR.Source );
1054
+ uint64_t StartOffset = Binary->virtualAddrToOffset (LBR.Target );
1055
+ if (EndOffeset != 0 )
1056
+ Ranges[{StartOffset, EndOffeset}] += Count;
1057
+ EndOffeset = SourceOffset;
1058
+ }
1016
1059
}
1060
+
1061
+ if (Ranges.empty ()) {
1062
+ WithColor::warning () << " No samples in perf script!\n " ;
1063
+ return ;
1064
+ }
1065
+
1066
+ auto WarnInvalidRange =
1067
+ [&](uint64_t StartOffset, uint64_t EndOffset, StringRef Msg) {
1068
+ if (!ShowDetailedWarning)
1069
+ return ;
1070
+ WithColor::warning ()
1071
+ << " ["
1072
+ << format (" %8" PRIx64, Binary->offsetToVirtualAddr (StartOffset))
1073
+ << " ,"
1074
+ << format (" %8" PRIx64, Binary->offsetToVirtualAddr (EndOffset))
1075
+ << " ]: " << Msg << " \n " ;
1076
+ };
1077
+
1078
+ const char *EndNotBoundaryMsg = " Range is not on instruction boundary, "
1079
+ " likely due to profile and binary mismatch." ;
1080
+ const char *DanglingRangeMsg = " Range does not belong to any functions, "
1081
+ " likely from PLT, .init or .fini section." ;
1082
+ const char *RangeCrossFuncMsg =
1083
+ " Fall through range should not cross function boundaries, likely due to "
1084
+ " profile and binary mismatch." ;
1085
+
1086
+ uint64_t InstNotBoundary = 0 ;
1087
+ uint64_t UnmatchedRange = 0 ;
1088
+ uint64_t RangeCrossFunc = 0 ;
1089
+
1090
+ for (auto &I : Ranges) {
1091
+ uint64_t StartOffset = I.first .first ;
1092
+ uint64_t EndOffset = I.first .second ;
1093
+
1094
+ if (!Binary->offsetIsCode (StartOffset) ||
1095
+ !Binary->offsetIsTransfer (EndOffset)) {
1096
+ InstNotBoundary++;
1097
+ WarnInvalidRange (StartOffset, EndOffset, EndNotBoundaryMsg);
1098
+ }
1099
+
1100
+ auto *FRange = Binary->findFuncRangeForOffset (StartOffset);
1101
+ if (!FRange) {
1102
+ UnmatchedRange++;
1103
+ WarnInvalidRange (StartOffset, EndOffset, DanglingRangeMsg);
1104
+ continue ;
1105
+ }
1106
+
1107
+ if (EndOffset >= FRange->EndOffset ) {
1108
+ RangeCrossFunc++;
1109
+ WarnInvalidRange (StartOffset, EndOffset, RangeCrossFuncMsg);
1110
+ }
1111
+ }
1112
+
1113
+ uint64_t TotalRangeNum = Ranges.size ();
1114
+ emitWarningSummary (InstNotBoundary, TotalRangeNum,
1115
+ " of profiled ranges are not on instruction boundary." );
1116
+ emitWarningSummary (UnmatchedRange, TotalRangeNum,
1117
+ " of profiled ranges do not belong to any functions." );
1118
+ emitWarningSummary (RangeCrossFunc, TotalRangeNum,
1119
+ " of profiled ranges do cross function boundaries." );
1017
1120
}
1018
1121
1019
1122
void PerfScriptReader::parsePerfTraces () {
@@ -1022,6 +1125,7 @@ void PerfScriptReader::parsePerfTraces() {
1022
1125
1023
1126
// Generate unsymbolized profile.
1024
1127
warnTruncatedStack ();
1128
+ warnInvalidRange ();
1025
1129
generateUnsymbolizedProfile ();
1026
1130
1027
1131
if (SkipSymbolization)
0 commit comments