diff options
Diffstat (limited to 'daemon/PerfDriver.cpp')
-rw-r--r-- | daemon/PerfDriver.cpp | 184 |
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; } |