#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 <cassert>
#include <cstddef>
#include <errno.h>
#include <string.h>
namespace llvm {
namespace exegesis {
namespace pfm {
#ifdef HAVE_LIBPFM
static bool isPfmError(int Code) { return Code != PFM_SUCCESS; }
#endif
bool pfmInitialize() { … }
void pfmTerminate() { … }
const char *const PerfEvent::DummyEventString = …;
PerfEvent::~PerfEvent() { … }
PerfEvent::PerfEvent(PerfEvent &&Other)
: … { … }
PerfEvent::PerfEvent(StringRef PfmEventString)
: … { … }
void PerfEvent::initRealEvent(StringRef PfmEventString) { … }
StringRef PerfEvent::name() const { … }
bool PerfEvent::valid() const { … }
const perf_event_attr *PerfEvent::attribute() const { … }
StringRef PerfEvent::getPfmEventString() const { … }
ConfiguredEvent::ConfiguredEvent(PerfEvent &&EventToConfigure)
: … { … }
#ifdef HAVE_LIBPFM
void ConfiguredEvent::initRealEvent(const pid_t ProcessID, const int GroupFD) {
const int CPU = -1;
const uint32_t Flags = 0;
perf_event_attr AttrCopy = *Event.attribute();
FileDescriptor = perf_event_open(&AttrCopy, ProcessID, 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"
<< "If you are debugging and just want to execute the snippet "
"without actually reading performance counters, "
"pass --use-dummy-perf-counters command line option.\n";
}
assert(FileDescriptor != -1 && "Unable to open event");
}
Expected<SmallVector<int64_t>>
ConfiguredEvent::readOrError(StringRef ) const {
int64_t Count = 0;
ssize_t ReadSize = ::read(FileDescriptor, &Count, sizeof(Count));
if (ReadSize != sizeof(Count))
return make_error<StringError>("Failed to read event counter",
errc::io_error);
SmallVector<int64_t, 1> Result;
Result.push_back(Count);
return Result;
}
ConfiguredEvent::~ConfiguredEvent() { close(FileDescriptor); }
#else
void ConfiguredEvent::initRealEvent(pid_t ProcessID, const int GroupFD) { … }
Expected<SmallVector<int64_t>>
ConfiguredEvent::readOrError(StringRef ) const { … }
ConfiguredEvent::~ConfiguredEvent() = default;
#endif
CounterGroup::CounterGroup(PerfEvent &&E, std::vector<PerfEvent> &&ValEvents,
pid_t ProcessID)
: … { … }
#ifdef HAVE_LIBPFM
void CounterGroup::initRealEvent(pid_t ProcessID) {
EventCounter.initRealEvent(ProcessID);
for (auto &ValCounter : ValidationEventCounters)
ValCounter.initRealEvent(ProcessID, getFileDescriptor());
}
void CounterGroup::start() {
if (!IsDummyEvent)
ioctl(getFileDescriptor(), PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
}
void CounterGroup::stop() {
if (!IsDummyEvent)
ioctl(getFileDescriptor(), PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
}
Expected<SmallVector<int64_t, 4>>
CounterGroup::readOrError(StringRef FunctionBytes) const {
if (!IsDummyEvent)
return EventCounter.readOrError(FunctionBytes);
else
return SmallVector<int64_t, 1>(1, 42);
}
Expected<SmallVector<int64_t>>
CounterGroup::readValidationCountersOrError() const {
SmallVector<int64_t, 4> Result;
for (const auto &ValCounter : ValidationEventCounters) {
Expected<SmallVector<int64_t>> ValueOrError =
ValCounter.readOrError(StringRef());
if (!ValueOrError)
return ValueOrError.takeError();
assert(ValueOrError->size() == 1 &&
"Validation counters should only return a single value");
Result.push_back((*ValueOrError)[0]);
}
return Result;
}
int CounterGroup::numValues() const { return 1; }
#else
void CounterGroup::initRealEvent(pid_t ProcessID) { … }
void CounterGroup::start() { … }
void CounterGroup::stop() { … }
Expected<SmallVector<int64_t, 4>>
CounterGroup::readOrError(StringRef ) const { … }
Expected<SmallVector<int64_t>>
CounterGroup::readValidationCountersOrError() const { … }
int CounterGroup::numValues() const { … }
#endif
}
}
}