diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp --- a/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp +++ b/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include +#include #include #include "Assembler.h" @@ -14,11 +15,13 @@ #include "Error.h" #include "MCInstrDescView.h" #include "PerfHelper.h" +#include "Target.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Program.h" @@ -38,7 +41,7 @@ FunctionExecutorImpl(const LLVMState &State, object::OwningBinary Obj, BenchmarkRunner::ScratchSpace *Scratch) - : Function(State.createTargetMachine(), std::move(Obj)), + : State(State), Function(State.createTargetMachine(), std::move(Obj)), Scratch(Scratch) {} private: @@ -51,30 +54,33 @@ char *const ScratchPtr = Scratch->ptr(); for (auto &CounterName : CounterNames) { CounterName = CounterName.trim(); - pfm::PerfEvent PerfEvent(CounterName); - if (!PerfEvent.valid()) - return make_error( - Twine("invalid perf event '").concat(CounterName).concat("'")); - pfm::Counter Counter(std::move(PerfEvent)); + auto CounterOrError = + State.getExegesisTarget().createCounter(CounterName.data(), State); + + if (!CounterOrError) + return CounterOrError.takeError(); + + pfm::Counter *Counter = CounterOrError.get().get(); Scratch->clear(); { CrashRecoveryContext CRC; CrashRecoveryContext::Enable(); - const bool Crashed = !CRC.RunSafely([this, &Counter, ScratchPtr]() { - Counter.start(); + const bool Crashed = !CRC.RunSafely([this, Counter, ScratchPtr]() { + Counter->start(); this->Function(ScratchPtr); - Counter.stop(); + Counter->stop(); }); CrashRecoveryContext::Disable(); // FIXME: Better diagnosis. if (Crashed) return make_error("snippet crashed while running"); } - CounterValue += Counter.read(); + CounterValue += Counter->read(); } return CounterValue; } + const LLVMState &State; const ExecutableFunction Function; BenchmarkRunner::ScratchSpace *const Scratch; }; diff --git a/llvm/tools/llvm-exegesis/lib/PerfHelper.h b/llvm/tools/llvm-exegesis/lib/PerfHelper.h --- a/llvm/tools/llvm-exegesis/lib/PerfHelper.h +++ b/llvm/tools/llvm-exegesis/lib/PerfHelper.h @@ -17,6 +17,8 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" +#include "llvm/Support/Error.h" +#include #include #include @@ -36,7 +38,7 @@ public: // http://perfmon2.sourceforge.net/manv4/libpfm.html // Events are expressed as strings. e.g. "INSTRUCTION_RETIRED" - explicit PerfEvent(StringRef pfm_event_string); + explicit PerfEvent(StringRef PfmEventString); PerfEvent(const PerfEvent &) = delete; PerfEvent(PerfEvent &&other); @@ -63,18 +65,27 @@ // Uses a valid PerfEvent to configure the Kernel so we can measure the // underlying event. -struct Counter { +class Counter { +public: // event: the PerfEvent to measure. explicit Counter(PerfEvent &&event); Counter(const Counter &) = delete; Counter(Counter &&other) = default; - ~Counter(); + virtual ~Counter(); + + /// Starts the measurement of the event. + virtual void start(); + + /// Stops the measurement of the event. + void stop(); + + /// Returns the current value of the counter or -1 if it cannot be read. + int64_t read() const; - void start(); // Starts the measurement of the event. - void stop(); // Stops the measurement of the event. - int64_t read() const; // Return the current value of the counter. + /// Returns the current value of the counter or error if it cannot be read. + virtual llvm::Expected readOrError() const; private: PerfEvent Event; diff --git a/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp b/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp --- a/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp +++ b/llvm/tools/llvm-exegesis/lib/PerfHelper.cpp @@ -8,13 +8,19 @@ #include "PerfHelper.h" #include "llvm/Config/config.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" #include "llvm/Support/raw_ostream.h" #ifdef HAVE_LIBPFM #include "perfmon/perf_event.h" #include "perfmon/pfmlib.h" #include "perfmon/pfmlib_perf_event.h" #endif + #include +#include +#include // for erno +#include // for strerror() namespace llvm { namespace exegesis { @@ -97,7 +103,8 @@ perf_event_attr AttrCopy = *Event.attribute(); FileDescriptor = perf_event_open(&AttrCopy, Pid, Cpu, GroupFd, Flags); if (FileDescriptor == -1) { - errs() << "Unable to open event, make sure your kernel allows user " + errs() << "Unable to open event. ERRNO: " << strerror(errno) + << ". Make sure your kernel allows user " "space perf monitoring.\nYou may want to try:\n$ sudo sh " "-c 'echo -1 > /proc/sys/kernel/perf_event_paranoid'\n"; } @@ -111,12 +118,21 @@ void Counter::stop() { ioctl(FileDescriptor, PERF_EVENT_IOC_DISABLE, 0); } int64_t Counter::read() const { + auto ValueOrError = readOrError(); + if (ValueOrError) + return ValueOrError.get(); + + errs() << ValueOrError.takeError() << "\n"; + return -1; +} + +llvm::Expected Counter::readOrError() const { int64_t Count = 0; ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count)); - if (ReadSize != sizeof(Count)) { - Count = -1; - errs() << "Failed to read event counter\n"; - } + if (ReadSize != sizeof(Count)) + return llvm::make_error("Failed to read event counter", + llvm::errc::io_error); + return Count; } @@ -132,6 +148,11 @@ int64_t Counter::read() const { return 42; } +llvm::Expected Counter::readOrError() const { + return llvm::make_error("Not implemented", + llvm::errc::io_error); +} + #endif } // namespace pfm diff --git a/llvm/tools/llvm-exegesis/lib/Target.h b/llvm/tools/llvm-exegesis/lib/Target.h --- a/llvm/tools/llvm-exegesis/lib/Target.h +++ b/llvm/tools/llvm-exegesis/lib/Target.h @@ -20,6 +20,7 @@ #include "BenchmarkRunner.h" #include "Error.h" #include "LlvmState.h" +#include "PerfHelper.h" #include "SnippetGenerator.h" #include "llvm/ADT/Triple.h" #include "llvm/CodeGen/TargetPassConfig.h" @@ -27,6 +28,7 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/Error.h" namespace llvm { namespace exegesis { @@ -65,6 +67,10 @@ explicit ExegesisTarget(ArrayRef CpuPfmCounters) : CpuPfmCounters(CpuPfmCounters) {} + // Targets can use this to create target-specific perf counters. + virtual Expected> + createCounter(const char *CounterName, const LLVMState &State) const; + // Targets can use this to add target-specific passes in assembleToStream(); virtual void addTargetSpecificPasses(PassManagerBase &PM) const {} diff --git a/llvm/tools/llvm-exegesis/lib/Target.cpp b/llvm/tools/llvm-exegesis/lib/Target.cpp --- a/llvm/tools/llvm-exegesis/lib/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/Target.cpp @@ -11,6 +11,8 @@ #include "ParallelSnippetGenerator.h" #include "SerialSnippetGenerator.h" #include "UopsBenchmarkRunner.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Error.h" namespace llvm { namespace exegesis { @@ -27,6 +29,19 @@ return nullptr; } +Expected> +ExegesisTarget::createCounter(const char *CounterName, + const LLVMState &) const { + pfm::PerfEvent Event(CounterName); + if (!Event.valid()) + return llvm::make_error( + llvm::Twine("Unable to create counter with name '") + .concat(CounterName) + .concat("'")); + + return std::make_unique(std::move(Event)); +} + void ExegesisTarget::registerTarget(ExegesisTarget *Target) { if (FirstTarget == nullptr) { FirstTarget = Target;