aboutsummaryrefslogtreecommitdiff
path: root/daemon/PerfDriver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/PerfDriver.cpp')
-rw-r--r--daemon/PerfDriver.cpp184
1 files changed, 142 insertions, 42 deletions
diff --git a/daemon/PerfDriver.cpp b/daemon/PerfDriver.cpp
index 796ee75..e5f8aaa 100644
--- a/daemon/PerfDriver.cpp
+++ b/daemon/PerfDriver.cpp
@@ -56,9 +56,9 @@ static const struct gator_cpu gator_cpus[] = {
{ 0x51049, "KraitSIM", "Krait", 4 },
{ 0x5104d, "Krait", "Krait", 4 },
{ 0x5106f, "Krait S4 Pro", "Krait", 4 },
- { 0x41d03, "Cortex-A53", "ARM_Cortex-A53", 6 },
- { 0x41d07, "Cortex-A57", "ARM_Cortex-A57", 6 },
- { 0x41d08, "Cortex-A72", "ARM_Cortex-A72", 6 },
+ { 0x41d03, "Cortex-A53", "ARMv8_Cortex_A53", 6 },
+ { 0x41d07, "Cortex-A57", "ARMv8_Cortex_A57", 6 },
+ { 0x41d08, "Cortex-A72", "ARMv8_Cortex_A72", 6 },
};
static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
@@ -75,14 +75,14 @@ struct uncore_counter {
static const struct uncore_counter uncore_counters[] = {
{ "CCI_400", "CCI_400", 4, true },
- { "CCI_400-r1", "CCI_400-r1", 4, true },
+ { "CCI_400_r1", "CCI_400_r1", 4, true },
{ "CCI_500", "CCI_500", 8, false },
{ "ccn", "ARM_CCN_5XX", 8, true },
};
class PerfCounter : public DriverCounter {
public:
- PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, uint64_t sampleType, uint64_t flags) : DriverCounter(next, name), mType(type), mConfig(config), mSampleType(sampleType), mFlags(flags), mCount(0) {}
+ PerfCounter(DriverCounter *next, const char *name, uint32_t type, uint64_t config, uint64_t sampleType, uint64_t flags, const int count) : DriverCounter(next, name), mType(type), mConfig(config), mSampleType(sampleType), mFlags(flags), mCount(count) {}
~PerfCounter() {
}
@@ -93,13 +93,14 @@ public:
uint64_t getConfig() const { return mConfig; }
void setConfig(const uint64_t config) { mConfig = config; }
uint64_t getSampleType() const { return mSampleType; }
+ void setSampleType(uint64_t sampleType) { mSampleType = sampleType; }
uint64_t getFlags() const { return mFlags; }
virtual void read(Buffer *const, const int) {}
private:
const uint32_t mType;
uint64_t mConfig;
- const uint64_t mSampleType;
+ uint64_t mSampleType;
const uint64_t mFlags;
int mCount;
@@ -110,7 +111,7 @@ private:
class CPUFreqDriver : public PerfCounter {
public:
- CPUFreqDriver(DriverCounter *next, uint64_t id) : PerfCounter(next, "Linux_power_cpu_freq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU) {}
+ CPUFreqDriver(DriverCounter *next, uint64_t id) : PerfCounter(next, "Linux_power_cpu_freq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU, 1) {}
void read(Buffer *const buffer, const int cpu) {
char buf[64];
@@ -135,17 +136,35 @@ PerfDriver::PerfDriver() : mIsSetup(false), mLegacySupport(false) {
PerfDriver::~PerfDriver() {
}
+class PerfTracepoint {
+public:
+ PerfTracepoint(PerfTracepoint *const next, const DriverCounter *const counter, const char *const tracepoint) : mNext(next), mCounter(counter), mTracepoint(tracepoint) {}
+
+ PerfTracepoint *getNext() const { return mNext; }
+ const DriverCounter *getCounter() const { return mCounter; }
+ const char *getTracepoint() const { return mTracepoint; }
+
+private:
+ PerfTracepoint *const mNext;
+ const DriverCounter *const mCounter;
+ const char *const mTracepoint;
+
+ // Intentionally undefined
+ PerfTracepoint(const PerfTracepoint &);
+ PerfTracepoint &operator=(const PerfTracepoint &);
+};
+
void PerfDriver::addCpuCounters(const char *const counterName, const int type, const int numCounters) {
int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
char *name = new char[len];
snprintf(name, len, "%s_ccnt", counterName);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
for (int j = 0; j < numCounters; ++j) {
len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
name = new char[len];
snprintf(name, len, "%s_cnt%d", counterName, j);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
}
@@ -157,14 +176,60 @@ void PerfDriver::addUncoreCounters(const char *const counterName, const int type
len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
name = new char[len];
snprintf(name, len, "%s_ccnt", counterName);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0, 0));
}
for (int j = 0; j < numCounters; ++j) {
len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
name = new char[len];
snprintf(name, len, "%s_cnt%d", counterName, j);
- setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0));
+ setCounters(new PerfCounter(getCounters(), name, type, -1, PERF_SAMPLE_READ, 0, 0));
+ }
+}
+
+void PerfDriver::readEvents(mxml_node_t *const xml) {
+ mxml_node_t *node = xml;
+ DynBuf printb;
+
+ // Only for use with perf
+ if (!isSetup()) {
+ return;
+ }
+
+ while (true) {
+ node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
+ if (node == NULL) {
+ break;
+ }
+ const char *counter = mxmlElementGetAttr(node, "counter");
+ if (counter == NULL) {
+ continue;
+ }
+
+ if (strncmp(counter, "ftrace_", 7) != 0) {
+ continue;
+ }
+
+ const char *tracepoint = mxmlElementGetAttr(node, "tracepoint");
+ if (tracepoint == NULL) {
+ const char *regex = mxmlElementGetAttr(node, "regex");
+ if (regex == NULL) {
+ logg->logError("The tracepoint counter %s is missing the required tracepoint attribute", counter);
+ handleException();
+ } else {
+ logg->logMessage("Not using perf for counter %s", counter);
+ continue;
+ }
+ }
+
+ const char *arg = mxmlElementGetAttr(node, "arg");
+
+ long long id = getTracepointId(tracepoint, &printb);
+ if (id >= 0) {
+ logg->logMessage("Using perf for %s", counter);
+ setCounters(new PerfCounter(getCounters(), strdup(counter), PERF_TYPE_TRACEPOINT, id, arg == NULL ? 0 : PERF_SAMPLE_RAW, PERF_GROUP_LEADER | PERF_GROUP_PER_CPU, 1));
+ mTracepoints = new PerfTracepoint(mTracepoints, getCounters(), strdup(tracepoint));
+ }
}
}
@@ -197,6 +262,7 @@ bool PerfDriver::setup() {
struct dirent *dirent;
while ((dirent = readdir(dir)) != NULL) {
+ logg->logMessage("perf pmu: %s", dirent->d_name);
for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
const struct gator_cpu *const gator_cpu = &gator_cpus[i];
@@ -217,7 +283,7 @@ bool PerfDriver::setup() {
}
foundCpu = true;
- logg->logMessage("Adding cpu counters for %s", gator_cpu->pmnc_name);
+ logg->logMessage("Adding cpu counters for %s with type %i", gator_cpu->pmnc_name, type);
addCpuCounters(gator_cpu->pmnc_name, type, gator_cpu->pmnc_counters);
}
@@ -233,7 +299,7 @@ bool PerfDriver::setup() {
continue;
}
- logg->logMessage("Adding uncore counters for %s", uncore_counters[i].gatorName);
+ logg->logMessage("Adding uncore counters for %s with type %i", uncore_counters[i].gatorName, type);
addUncoreCounters(uncore_counters[i].gatorName, type, uncore_counters[i].count, uncore_counters[i].hasCyclesCounter);
}
}
@@ -264,25 +330,25 @@ bool PerfDriver::setup() {
id = getTracepointId("irq/softirq_exit", &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
id = getTracepointId("irq/irq_handler_exit", &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
id = getTracepointId(SCHED_SWITCH, &printb);
if (id >= 0) {
- setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU));
+ setCounters(new PerfCounter(getCounters(), "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, PERF_SAMPLE_READ, PERF_GROUP_PER_CPU | PERF_GROUP_CPU, 0));
}
id = getTracepointId(CPU_FREQUENCY, &printb);
- if (id >= 0) {
+ if (id >= 0 && access("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq", R_OK) == 0) {
setCounters(new CPUFreqDriver(getCounters(), id));
}
- setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, 0, 0));
+ setCounters(new PerfCounter(getCounters(), "Linux_cpu_wait_contention", TYPE_DERIVED, -1, 0, 0, 0));
//Linux_cpu_wait_io
@@ -300,6 +366,12 @@ bool PerfDriver::summary(Buffer *const buffer) {
char buf[512];
snprintf(buf, sizeof(buf), "%s %s %s %s %s GNU/Linux", utsname.sysname, utsname.nodename, utsname.release, utsname.version, utsname.machine);
+ long pageSize = sysconf(_SC_PAGESIZE);
+ if (pageSize < 0) {
+ logg->logMessage("sysconf _SC_PAGESIZE failed");
+ return false;
+ }
+
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
logg->logMessage("clock_gettime failed");
@@ -311,7 +383,7 @@ bool PerfDriver::summary(Buffer *const buffer) {
gSessionData->mMonotonicStarted = monotonicStarted;
const uint64_t currTime = 0;//getTime() - gSessionData->mMonotonicStarted;
- buffer->summary(currTime, timestamp, monotonicStarted, monotonicStarted, buf);
+ buffer->summary(currTime, timestamp, monotonicStarted, monotonicStarted, buf, pageSize);
for (int i = 0; i < gSessionData->mCores; ++i) {
coreName(currTime, buffer, i);
@@ -322,27 +394,28 @@ bool PerfDriver::summary(Buffer *const buffer) {
}
void PerfDriver::coreName(const uint64_t currTime, Buffer *const buffer, const int cpu) {
+ const SharedData *const sharedData = gSessionData->mSharedData;
// Don't send information on a cpu we know nothing about
- if (gSessionData->mCpuIds[cpu] == -1) {
+ if (sharedData->mCpuIds[cpu] == -1) {
return;
}
int j;
for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) {
- if (gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
+ if (gator_cpus[j].cpuid == sharedData->mCpuIds[cpu]) {
break;
}
}
- if (j < ARRAY_LENGTH(gator_cpus) && gator_cpus[j].cpuid == gSessionData->mCpuIds[cpu]) {
- buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], gator_cpus[j].core_name);
+ if (j < ARRAY_LENGTH(gator_cpus) && gator_cpus[j].cpuid == sharedData->mCpuIds[cpu]) {
+ buffer->coreName(currTime, cpu, sharedData->mCpuIds[cpu], gator_cpus[j].core_name);
} else {
char buf[32];
- if (gSessionData->mCpuIds[cpu] == -1) {
+ if (sharedData->mCpuIds[cpu] == -1) {
snprintf(buf, sizeof(buf), "Unknown");
} else {
- snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[cpu]);
+ snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", sharedData->mCpuIds[cpu]);
}
- buffer->coreName(currTime, cpu, gSessionData->mCpuIds[cpu], buf);
+ buffer->coreName(currTime, cpu, sharedData->mCpuIds[cpu], buf);
}
}
@@ -357,27 +430,22 @@ void PerfDriver::setupCounter(Counter &counter) {
if (counter.getEvent() != -1) {
perfCounter->setConfig(counter.getEvent());
}
- perfCounter->setCount(counter.getCount());
+ if (counter.getCount() > 0) {
+ // EBS
+ perfCounter->setCount(counter.getCount());
+ // Collect samples
+ perfCounter->setSampleType(perfCounter->getSampleType() | PERF_SAMPLE_TID | PERF_SAMPLE_IP);
+ }
perfCounter->setEnabled(true);
counter.setKey(perfCounter->getKey());
}
bool PerfDriver::enable(const uint64_t currTime, PerfGroup *const group, Buffer *const buffer) const {
for (PerfCounter *counter = static_cast<PerfCounter *>(getCounters()); counter != NULL; counter = static_cast<PerfCounter *>(counter->getNext())) {
- if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) {
- int count = counter->getCount();
- uint64_t sampleType = counter->getSampleType();
- if (sampleType & PERF_SAMPLE_RAW) {
- // If raw is enabled, every sample is needed
- count = 1;
- }
- if (!group->add(currTime, buffer, counter->getKey(), counter->getType(), counter->getConfig(), count,
- // use getCount instead of count as EBS counters need TID and IP but RAW tracepoints don't
- (counter->getCount() > 0 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP : 0) | sampleType,
- counter->getFlags())) {
- logg->logMessage("PerfGroup::add failed");
- return false;
- }
+ if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED) &&
+ !group->add(currTime, buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), counter->getSampleType(), counter->getFlags())) {
+ logg->logMessage("PerfGroup::add failed");
+ return false;
}
}
@@ -393,6 +461,38 @@ void PerfDriver::read(Buffer *const buffer, const int cpu) {
}
}
+static bool sendTracepointFormat(const uint64_t currTime, Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
+ if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
+ logg->logMessage("DynBuf::printf failed");
+ return false;
+ }
+ if (!b->read(printb->getBuf())) {
+ logg->logMessage("DynBuf::read failed");
+ return false;
+ }
+ buffer->marshalFormat(currTime, b->getLength(), b->getBuf());
+
+ return true;
+}
+
+bool PerfDriver::sendTracepointFormats(const uint64_t currTime, Buffer *const buffer, DynBuf *const printb, DynBuf *const b) {
+ if (
+ !sendTracepointFormat(currTime, buffer, SCHED_SWITCH, printb, b) ||
+ !sendTracepointFormat(currTime, buffer, CPU_IDLE, printb, b) ||
+ !sendTracepointFormat(currTime, buffer, CPU_FREQUENCY, printb, b) ||
+ false) {
+ return false;
+ }
+
+ for (PerfTracepoint *tracepoint = mTracepoints; tracepoint != NULL; tracepoint = tracepoint->getNext()) {
+ if (tracepoint->getCounter()->isEnabled() && !sendTracepointFormat(currTime, buffer, tracepoint->getTracepoint(), printb, b)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
long long PerfDriver::getTracepointId(const char *const name, DynBuf *const printb) {
if (!printb->printf(EVENTS_PATH "/%s/id", name)) {
logg->logMessage("DynBuf::printf failed");
@@ -401,7 +501,7 @@ long long PerfDriver::getTracepointId(const char *const name, DynBuf *const prin
int64_t result;
if (DriverSource::readInt64Driver(printb->getBuf(), &result) != 0) {
- logg->logMessage("DriverSource::readInt64Driver failed");
+ logg->logMessage("Unable to read tracepoint id for %s", printb->getBuf());
return -1;
}