Skip to content

Commit 980d66c

Browse files
[llvm-exegesis] Error Out If Perf Counter is Not Fully Enabled (#132892)
Perf counters can be multiplexed if there are too many that need to be scheduled on a core at the same time (and they exceed the available PMUs). Other processes (especially system ones in certain environments, not commonly on Desktop Linux from what I've seen) can also interfere. This will impact the measurement fidelity as the counter is not actually counting cycles/uops the entire time. This patch makes it so that we error out in these cases so the user gets a visible indication things have gone wrong rather than things failing silently.
1 parent bfd8cc0 commit 980d66c

File tree

3 files changed

+34
-4
lines changed

3 files changed

+34
-4
lines changed

llvm/tools/llvm-exegesis/lib/Error.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,15 @@ void SnippetSignal::log(raw_ostream &OS) const {
4949
#endif // LLVM_ON_UNIX
5050
}
5151

52+
char PerfCounterNotFullyEnabled::ID;
53+
54+
std::error_code PerfCounterNotFullyEnabled::convertToErrorCode() const {
55+
return inconvertibleErrorCode();
56+
}
57+
58+
void PerfCounterNotFullyEnabled::log(raw_ostream &OS) const {
59+
OS << "The perf counter was not scheduled on the CPU the entire time.";
60+
}
61+
5262
} // namespace exegesis
5363
} // namespace llvm

llvm/tools/llvm-exegesis/lib/Error.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,18 @@ class SnippetSignal : public SnippetExecutionFailure {
7676
int SignalNumber;
7777
};
7878

79+
// A class representing a case where a perf counter was only partially
80+
// scheduled, most likely due to perf counter contention.
81+
struct PerfCounterNotFullyEnabled
82+
: public ErrorInfo<PerfCounterNotFullyEnabled> {
83+
static char ID;
84+
PerfCounterNotFullyEnabled() {}
85+
86+
void log(raw_ostream &OS) const override;
87+
88+
std::error_code convertToErrorCode() const override;
89+
};
90+
7991
} // namespace exegesis
8092
} // namespace llvm
8193

llvm/tools/llvm-exegesis/lib/PerfHelper.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "PerfHelper.h"
10+
#include "Error.h"
1011
#include "llvm/Config/config.h"
1112
#include "llvm/Support/Errc.h"
1213
#include "llvm/Support/Error.h"
@@ -117,6 +118,8 @@ void ConfiguredEvent::initRealEvent(const pid_t ProcessID, const int GroupFD) {
117118
const int CPU = -1;
118119
const uint32_t Flags = 0;
119120
perf_event_attr AttrCopy = *Event.attribute();
121+
AttrCopy.read_format =
122+
PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
120123
FileDescriptor = perf_event_open(&AttrCopy, ProcessID, CPU, GroupFD, Flags);
121124
if (FileDescriptor == -1) {
122125
errs() << "Unable to open event. ERRNO: " << strerror(errno)
@@ -132,15 +135,20 @@ void ConfiguredEvent::initRealEvent(const pid_t ProcessID, const int GroupFD) {
132135

133136
Expected<SmallVector<int64_t>>
134137
ConfiguredEvent::readOrError(StringRef /*unused*/) const {
135-
int64_t Count = 0;
136-
ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count));
138+
int64_t EventInfo[3] = {0, 0, 0};
139+
ssize_t ReadSize = ::read(FileDescriptor, &EventInfo, sizeof(EventInfo));
137140

138-
if (ReadSize != sizeof(Count))
141+
if (ReadSize != sizeof(EventInfo))
139142
return make_error<StringError>("Failed to read event counter",
140143
errc::io_error);
141144

145+
int64_t EventTimeEnabled = EventInfo[1];
146+
int64_t EventTimeRunning = EventInfo[2];
147+
if (EventTimeEnabled != EventTimeRunning)
148+
return make_error<PerfCounterNotFullyEnabled>();
149+
142150
SmallVector<int64_t, 1> Result;
143-
Result.push_back(Count);
151+
Result.push_back(EventInfo[0]);
144152
return Result;
145153
}
146154

0 commit comments

Comments
 (0)