@@ -321,7 +321,7 @@ bool VirtualUnwinder::unwind(const PerfSample *Sample, uint64_t Repeat) {
321
321
322
322
std::unique_ptr<PerfReaderBase>
323
323
PerfReaderBase::create (ProfiledBinary *Binary, PerfInputFile &PerfInput,
324
- std::optional<uint32_t > PIDFilter) {
324
+ std::optional<int32_t > PIDFilter) {
325
325
std::unique_ptr<PerfReaderBase> PerfReader;
326
326
327
327
if (PerfInput.Format == PerfFormat::UnsymbolizedProfile) {
@@ -331,9 +331,10 @@ PerfReaderBase::create(ProfiledBinary *Binary, PerfInputFile &PerfInput,
331
331
}
332
332
333
333
// For perf data input, we need to convert them into perf script first.
334
+ // If this is a kernel perf file, there is no need for retrieving PIDs.
334
335
if (PerfInput.Format == PerfFormat::PerfData)
335
- PerfInput =
336
- PerfScriptReader::convertPerfDataToTrace ( Binary, PerfInput, PIDFilter);
336
+ PerfInput = PerfScriptReader::convertPerfDataToTrace (
337
+ Binary, Binary-> isKernel () , PerfInput, PIDFilter);
337
338
338
339
assert ((PerfInput.Format == PerfFormat::PerfScript) &&
339
340
" Should be a perfscript!" );
@@ -353,59 +354,69 @@ PerfReaderBase::create(ProfiledBinary *Binary, PerfInputFile &PerfInput,
353
354
}
354
355
355
356
PerfInputFile
356
- PerfScriptReader::convertPerfDataToTrace (ProfiledBinary *Binary,
357
+ PerfScriptReader::convertPerfDataToTrace (ProfiledBinary *Binary, bool SkipPID,
357
358
PerfInputFile &File,
358
- std::optional<uint32_t > PIDFilter) {
359
+ std::optional<int32_t > PIDFilter) {
359
360
StringRef PerfData = File.InputFile ;
360
361
// Run perf script to retrieve PIDs matching binary we're interested in.
361
362
auto PerfExecutable = sys::Process::FindInEnvPath (" PATH" , " perf" );
362
363
if (!PerfExecutable) {
363
364
exitWithError (" Perf not found." );
364
365
}
365
366
std::string PerfPath = *PerfExecutable;
366
-
367
367
SmallString<128 > PerfTraceFile;
368
368
sys::fs::createUniquePath (" perf-script-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%.tmp" ,
369
369
PerfTraceFile, /* MakeAbsolute=*/ true );
370
370
std::string ErrorFile = std::string (PerfTraceFile) + " .err" ;
371
- StringRef ScriptMMapArgs[] = {PerfPath, " script" , " --show-mmap-events" ,
372
- " -F" , " comm,pid" , " -i" ,
373
- PerfData};
374
371
std::optional<StringRef> Redirects[] = {std::nullopt, // Stdin
375
372
StringRef (PerfTraceFile), // Stdout
376
373
StringRef (ErrorFile)}; // Stderr
377
- sys::ExecuteAndWait (PerfPath, ScriptMMapArgs, std::nullopt, Redirects);
378
-
379
374
PerfScriptReader::TempFileCleanups.emplace_back (PerfTraceFile);
380
375
PerfScriptReader::TempFileCleanups.emplace_back (ErrorFile);
381
376
382
- // Collect the PIDs
383
- TraceStream TraceIt (PerfTraceFile);
384
377
std::string PIDs;
385
- std::unordered_set<uint32_t > PIDSet;
386
- while (!TraceIt.isAtEoF ()) {
387
- MMapEvent MMap;
388
- if (isMMap2Event (TraceIt.getCurrentLine ()) &&
389
- extractMMap2EventForBinary (Binary, TraceIt.getCurrentLine (), MMap)) {
390
- auto It = PIDSet.emplace (MMap.PID );
391
- if (It.second && (!PIDFilter || MMap.PID == *PIDFilter)) {
392
- if (!PIDs.empty ()) {
393
- PIDs.append (" ," );
378
+ if (!SkipPID) {
379
+ StringRef ScriptMMapArgs[] = {PerfPath, " script" , " --show-mmap-events" ,
380
+ " -F" , " comm,pid" , " -i" ,
381
+ PerfData};
382
+ sys::ExecuteAndWait (PerfPath, ScriptMMapArgs, std::nullopt, Redirects);
383
+
384
+ // Collect the PIDs
385
+ TraceStream TraceIt (PerfTraceFile);
386
+ std::unordered_set<int32_t > PIDSet;
387
+ while (!TraceIt.isAtEoF ()) {
388
+ MMapEvent MMap;
389
+ if (isMMapEvent (TraceIt.getCurrentLine ()) &&
390
+ extractMMapEventForBinary (Binary, TraceIt.getCurrentLine (), MMap)) {
391
+ auto It = PIDSet.emplace (MMap.PID );
392
+ if (It.second && (!PIDFilter || MMap.PID == *PIDFilter)) {
393
+ if (!PIDs.empty ()) {
394
+ PIDs.append (" ," );
395
+ }
396
+ PIDs.append (utostr (MMap.PID ));
394
397
}
395
- PIDs.append (utostr (MMap.PID ));
396
398
}
399
+ TraceIt.advance ();
397
400
}
398
- TraceIt.advance ();
399
- }
400
401
401
- if (PIDs.empty ()) {
402
- exitWithError (" No relevant mmap event is found in perf data." );
402
+ if (PIDs.empty ()) {
403
+ exitWithError (" No relevant mmap event is found in perf data." );
404
+ }
403
405
}
404
406
405
407
// Run perf script again to retrieve events for PIDs collected above
406
- StringRef ScriptSampleArgs[] = {PerfPath, " script" , " --show-mmap-events" ,
407
- " -F" , " ip,brstack" , " --pid" ,
408
- PIDs, " -i" , PerfData};
408
+ SmallVector<StringRef, 8 > ScriptSampleArgs;
409
+ ScriptSampleArgs.push_back (PerfPath);
410
+ ScriptSampleArgs.push_back (" script" );
411
+ ScriptSampleArgs.push_back (" --show-mmap-events" );
412
+ ScriptSampleArgs.push_back (" -F" );
413
+ ScriptSampleArgs.push_back (" ip,brstack" );
414
+ ScriptSampleArgs.push_back (" -i" );
415
+ ScriptSampleArgs.push_back (PerfData);
416
+ if (!PIDs.empty ()) {
417
+ ScriptSampleArgs.push_back (" --pid" );
418
+ ScriptSampleArgs.push_back (PIDs);
419
+ }
409
420
sys::ExecuteAndWait (PerfPath, ScriptSampleArgs, std::nullopt, Redirects);
410
421
411
422
return {std::string (PerfTraceFile), PerfFormat::PerfScript,
@@ -428,7 +439,10 @@ static StringRef filename(StringRef Path, bool UseBackSlash) {
428
439
void PerfScriptReader::updateBinaryAddress (const MMapEvent &Event) {
429
440
// Drop the event which doesn't belong to user-provided binary
430
441
StringRef BinaryName = filename (Event.BinaryPath , Binary->isCOFF ());
431
- if (Binary->getName () != BinaryName)
442
+ bool IsKernel = Binary->isKernel ();
443
+ if (!IsKernel && Binary->getName () != BinaryName)
444
+ return ;
445
+ if (IsKernel && !Binary->isKernelImageName (BinaryName))
432
446
return ;
433
447
434
448
// Drop the event if process does not match pid filter
@@ -441,7 +455,7 @@ void PerfScriptReader::updateBinaryAddress(const MMapEvent &Event) {
441
455
return ;
442
456
}
443
457
444
- if (Event.Offset == Binary->getTextSegmentOffset ()) {
458
+ if (IsKernel || Event.Offset == Binary->getTextSegmentOffset ()) {
445
459
// A binary image could be unloaded and then reloaded at different
446
460
// place, so update binary load address.
447
461
// Only update for the first executable segment and assume all other
@@ -950,16 +964,23 @@ void PerfScriptReader::parseSample(TraceStream &TraceIt) {
950
964
parseSample (TraceIt, Count);
951
965
}
952
966
953
- bool PerfScriptReader::extractMMap2EventForBinary (ProfiledBinary *Binary,
954
- StringRef Line,
955
- MMapEvent &MMap) {
956
- // Parse a line like:
967
+ bool PerfScriptReader::extractMMapEventForBinary (ProfiledBinary *Binary,
968
+ StringRef Line,
969
+ MMapEvent &MMap) {
970
+ // Parse a MMap2 line like:
957
971
// PERF_RECORD_MMAP2 2113428/2113428: [0x7fd4efb57000(0x204000) @ 0
958
972
// 08:04 19532229 3585508847]: r-xp /usr/lib64/libdl-2.17.so
959
- constexpr static const char *const Pattern =
960
- " PERF_RECORD_MMAP2 ([0-9]+)/[0-9]+: "
973
+ constexpr static const char *const MMap2Pattern =
974
+ " PERF_RECORD_MMAP2 (-? [0-9]+)/[0-9]+: "
961
975
" \\ [(0x[a-f0-9]+)\\ ((0x[a-f0-9]+)\\ ) @ "
962
976
" (0x[a-f0-9]+|0) .*\\ ]: [-a-z]+ (.*)" ;
977
+ // Parse a MMap line like
978
+ // PERF_RECORD_MMAP -1/0: [0xffffffff81e00000(0x3e8fa000) @ \
979
+ // 0xffffffff81e00000]: x [kernel.kallsyms]_text
980
+ constexpr static const char *const MMapPattern =
981
+ " PERF_RECORD_MMAP (-?[0-9]+)/[0-9]+: "
982
+ " \\ [(0x[a-f0-9]+)\\ ((0x[a-f0-9]+)\\ ) @ "
983
+ " (0x[a-f0-9]+|0)\\ ]: [-a-z]+ (.*)" ;
963
984
// Field 0 - whole line
964
985
// Field 1 - PID
965
986
// Field 2 - base address
@@ -975,14 +996,25 @@ bool PerfScriptReader::extractMMap2EventForBinary(ProfiledBinary *Binary,
975
996
BINARY_PATH = 5
976
997
};
977
998
978
- Regex RegMmap2 (Pattern) ;
999
+ bool R = false ;
979
1000
SmallVector<StringRef, 6 > Fields;
980
- bool R = RegMmap2.match (Line, &Fields);
1001
+ if (Line.contains (" PERF_RECORD_MMAP2 " )) {
1002
+ Regex RegMmap2 (MMap2Pattern);
1003
+ R = RegMmap2.match (Line, &Fields);
1004
+ } else if (Line.contains (" PERF_RECORD_MMAP " )) {
1005
+ Regex RegMmap (MMapPattern);
1006
+ R = RegMmap.match (Line, &Fields);
1007
+ } else
1008
+ llvm_unreachable (" unexpected MMAP event entry" );
1009
+
981
1010
if (!R) {
982
1011
std::string WarningMsg = " Cannot parse mmap event: " + Line.str () + " \n " ;
983
1012
WithColor::warning () << WarningMsg;
1013
+ return false ;
984
1014
}
985
- Fields[PID].getAsInteger (10 , MMap.PID );
1015
+ long long MMapPID = 0 ;
1016
+ getAsSignedInteger (Fields[PID], 10 , MMapPID);
1017
+ MMap.PID = MMapPID;
986
1018
Fields[MMAPPED_ADDRESS].getAsInteger (0 , MMap.Address );
987
1019
Fields[MMAPPED_SIZE].getAsInteger (0 , MMap.Size );
988
1020
Fields[PAGE_OFFSET].getAsInteger (0 , MMap.Offset );
@@ -993,19 +1025,22 @@ bool PerfScriptReader::extractMMap2EventForBinary(ProfiledBinary *Binary,
993
1025
}
994
1026
995
1027
StringRef BinaryName = filename (MMap.BinaryPath , Binary->isCOFF ());
1028
+ if (Binary->isKernel ()) {
1029
+ return Binary->isKernelImageName (BinaryName);
1030
+ }
996
1031
return Binary->getName () == BinaryName;
997
1032
}
998
1033
999
- void PerfScriptReader::parseMMap2Event (TraceStream &TraceIt) {
1034
+ void PerfScriptReader::parseMMapEvent (TraceStream &TraceIt) {
1000
1035
MMapEvent MMap;
1001
- if (extractMMap2EventForBinary (Binary, TraceIt.getCurrentLine (), MMap))
1036
+ if (extractMMapEventForBinary (Binary, TraceIt.getCurrentLine (), MMap))
1002
1037
updateBinaryAddress (MMap);
1003
1038
TraceIt.advance ();
1004
1039
}
1005
1040
1006
1041
void PerfScriptReader::parseEventOrSample (TraceStream &TraceIt) {
1007
- if (isMMap2Event (TraceIt.getCurrentLine ()))
1008
- parseMMap2Event (TraceIt);
1042
+ if (isMMapEvent (TraceIt.getCurrentLine ()))
1043
+ parseMMapEvent (TraceIt);
1009
1044
else
1010
1045
parseSample (TraceIt);
1011
1046
}
@@ -1032,17 +1067,17 @@ bool PerfScriptReader::isLBRSample(StringRef Line) {
1032
1067
return false ;
1033
1068
}
1034
1069
1035
- bool PerfScriptReader::isMMap2Event (StringRef Line) {
1070
+ bool PerfScriptReader::isMMapEvent (StringRef Line) {
1036
1071
// Short cut to avoid string find is possible.
1037
1072
if (Line.empty () || Line.size () < 50 )
1038
1073
return false ;
1039
1074
1040
1075
if (std::isdigit (Line[0 ]))
1041
1076
return false ;
1042
1077
1043
- // PERF_RECORD_MMAP2 does not appear at the beginning of the line
1044
- // for ` perf script --show-mmap-events -i ...`
1045
- return Line.contains (" PERF_RECORD_MMAP2 " );
1078
+ // PERF_RECORD_MMAP2 or PERF_RECORD_MMAP does not appear at the beginning of
1079
+ // the line for ` perf script --show-mmap-events -i ...`
1080
+ return Line.contains (" PERF_RECORD_MMAP " );
1046
1081
}
1047
1082
1048
1083
// The raw hybird sample is like
@@ -1208,6 +1243,10 @@ void PerfScriptReader::warnInvalidRange() {
1208
1243
void PerfScriptReader::parsePerfTraces () {
1209
1244
// Parse perf traces and do aggregation.
1210
1245
parseAndAggregateTrace ();
1246
+ if (Binary->isKernel () && !Binary->getIsLoadedByMMap ()) {
1247
+ exitWithError (
1248
+ " Kernel is requested, but no kernel is found in mmap events." );
1249
+ }
1211
1250
1212
1251
emitWarningSummary (NumLeafExternalFrame, NumTotalSample,
1213
1252
" of samples have leaf external frame in call stack." );
0 commit comments