123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- //===-- PerfHelper.cpp ------------------------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #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
- #error #include <perfmon/perf_event.h>
- #error #include <perfmon/pfmlib.h>
- #error #include <perfmon/pfmlib_perf_event.h>
- #endif
- #include <cassert>
- #include <cstddef>
- #include <errno.h> // for erno
- #include <string.h> // for strerror()
- namespace llvm {
- namespace exegesis {
- namespace pfm {
- #ifdef HAVE_LIBPFM
- static bool isPfmError(int Code) { return Code != PFM_SUCCESS; }
- #endif
- bool pfmInitialize() {
- #ifdef HAVE_LIBPFM
- return isPfmError(pfm_initialize());
- #else
- return true;
- #endif
- }
- void pfmTerminate() {
- #ifdef HAVE_LIBPFM
- pfm_terminate();
- #endif
- }
- PerfEvent::~PerfEvent() {
- #ifdef HAVE_LIBPFM
- delete Attr;
- ;
- #endif
- }
- PerfEvent::PerfEvent(PerfEvent &&Other)
- : EventString(std::move(Other.EventString)),
- FullQualifiedEventString(std::move(Other.FullQualifiedEventString)),
- Attr(Other.Attr) {
- Other.Attr = nullptr;
- }
- PerfEvent::PerfEvent(StringRef PfmEventString)
- : EventString(PfmEventString.str()), Attr(nullptr) {
- #ifdef HAVE_LIBPFM
- char *Fstr = nullptr;
- pfm_perf_encode_arg_t Arg = {};
- Attr = new perf_event_attr();
- Arg.attr = Attr;
- Arg.fstr = &Fstr;
- Arg.size = sizeof(pfm_perf_encode_arg_t);
- const int Result = pfm_get_os_event_encoding(EventString.c_str(), PFM_PLM3,
- PFM_OS_PERF_EVENT, &Arg);
- if (isPfmError(Result)) {
- // We don't know beforehand which counters are available (e.g. 6 uops ports
- // on Sandybridge but 8 on Haswell) so we report the missing counter without
- // crashing.
- errs() << pfm_strerror(Result) << " - cannot create event " << EventString
- << "\n";
- }
- if (Fstr) {
- FullQualifiedEventString = Fstr;
- free(Fstr);
- }
- #endif
- }
- StringRef PerfEvent::name() const { return EventString; }
- bool PerfEvent::valid() const { return !FullQualifiedEventString.empty(); }
- const perf_event_attr *PerfEvent::attribute() const { return Attr; }
- StringRef PerfEvent::getPfmEventString() const {
- return FullQualifiedEventString;
- }
- #ifdef HAVE_LIBPFM
- Counter::Counter(PerfEvent &&E) : Event(std::move(E)){
- assert(Event.valid());
- const pid_t Pid = 0; // measure current process/thread.
- const int Cpu = -1; // measure any processor.
- const int GroupFd = -1; // no grouping of counters.
- const uint32_t Flags = 0;
- perf_event_attr AttrCopy = *Event.attribute();
- FileDescriptor = perf_event_open(&AttrCopy, Pid, Cpu, GroupFd, Flags);
- if (FileDescriptor == -1) {
- 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";
- }
- assert(FileDescriptor != -1 && "Unable to open event");
- }
- Counter::~Counter() { close(FileDescriptor); }
- void Counter::start() { ioctl(FileDescriptor, PERF_EVENT_IOC_RESET, 0); }
- void Counter::stop() { ioctl(FileDescriptor, PERF_EVENT_IOC_DISABLE, 0); }
- int64_t Counter::read() const {
- auto ValueOrError = readOrError();
- if (ValueOrError) {
- if (!ValueOrError.get().empty())
- return ValueOrError.get()[0];
- errs() << "Counter has no reading\n";
- } else
- errs() << ValueOrError.takeError() << "\n";
- return -1;
- }
- llvm::Expected<llvm::SmallVector<int64_t, 4>>
- Counter::readOrError(StringRef /*unused*/) const {
- int64_t Count = 0;
- ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count));
- if (ReadSize != sizeof(Count))
- return llvm::make_error<llvm::StringError>("Failed to read event counter",
- llvm::errc::io_error);
- llvm::SmallVector<int64_t, 4> Result;
- Result.push_back(Count);
- return Result;
- }
- int Counter::numValues() const { return 1; }
- #else
- Counter::Counter(PerfEvent &&Event) : Event(std::move(Event)) {}
- Counter::~Counter() = default;
- void Counter::start() {}
- void Counter::stop() {}
- int64_t Counter::read() const { return 42; }
- llvm::Expected<llvm::SmallVector<int64_t, 4>>
- Counter::readOrError(StringRef /*unused*/) const {
- return llvm::make_error<llvm::StringError>("Not implemented",
- llvm::errc::io_error);
- }
- int Counter::numValues() const { return 1; }
- #endif
- } // namespace pfm
- } // namespace exegesis
- } // namespace llvm
|