diff options
Diffstat (limited to 'daemon/PerfDriver.cpp')
-rw-r--r-- | daemon/PerfDriver.cpp | 92 |
1 files changed, 73 insertions, 19 deletions
diff --git a/daemon/PerfDriver.cpp b/daemon/PerfDriver.cpp index 8e25c22..ac97a07 100644 --- a/daemon/PerfDriver.cpp +++ b/daemon/PerfDriver.cpp | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <dirent.h> | 11 | #include <dirent.h> |
12 | #include <sys/utsname.h> | 12 | #include <sys/utsname.h> |
13 | #include <time.h> | 13 | #include <time.h> |
14 | #include <unistd.h> | ||
14 | 15 | ||
15 | #include "Buffer.h" | 16 | #include "Buffer.h" |
16 | #include "Config.h" | 17 | #include "Config.h" |
@@ -30,7 +31,7 @@ | |||
30 | struct gator_cpu { | 31 | struct gator_cpu { |
31 | const int cpuid; | 32 | const int cpuid; |
32 | // Human readable name | 33 | // Human readable name |
33 | const char core_name[32]; | 34 | const char *const core_name; |
34 | // gatorfs event and Perf PMU name | 35 | // gatorfs event and Perf PMU name |
35 | const char *const pmnc_name; | 36 | const char *const pmnc_name; |
36 | const int pmnc_counters; | 37 | const int pmnc_counters; |
@@ -62,9 +63,20 @@ static const struct gator_cpu gator_cpus[] = { | |||
62 | static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-"; | 63 | static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-"; |
63 | static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_"; | 64 | static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_"; |
64 | 65 | ||
66 | struct uncore_counter { | ||
67 | // gatorfs event and Perf PMU name | ||
68 | const char *const name; | ||
69 | const int count; | ||
70 | }; | ||
71 | |||
72 | static const struct uncore_counter uncore_counters[] = { | ||
73 | { "CCI_400", 4 }, | ||
74 | { "CCI_400-r1", 4 }, | ||
75 | }; | ||
76 | |||
65 | class PerfCounter { | 77 | class PerfCounter { |
66 | public: | 78 | public: |
67 | PerfCounter(PerfCounter *next, const char *name, uint32_t type, uint64_t config) : mNext(next), mName(name), mType(type), mCount(0), mKey(getEventKey()), mConfig(config), mEnabled(false) {} | 79 | PerfCounter(PerfCounter *next, const char *name, uint32_t type, uint64_t config, bool perCpu) : mNext(next), mName(name), mType(type), mCount(0), mKey(getEventKey()), mConfig(config), mEnabled(false), mPerCpu(perCpu) {} |
68 | ~PerfCounter() { | 80 | ~PerfCounter() { |
69 | delete [] mName; | 81 | delete [] mName; |
70 | } | 82 | } |
@@ -79,6 +91,7 @@ public: | |||
79 | void setConfig(const uint64_t config) { mConfig = config; } | 91 | void setConfig(const uint64_t config) { mConfig = config; } |
80 | bool isEnabled() const { return mEnabled; } | 92 | bool isEnabled() const { return mEnabled; } |
81 | void setEnabled(const bool enabled) { mEnabled = enabled; } | 93 | void setEnabled(const bool enabled) { mEnabled = enabled; } |
94 | bool isPerCpu() const { return mPerCpu; } | ||
82 | 95 | ||
83 | private: | 96 | private: |
84 | PerfCounter *const mNext; | 97 | PerfCounter *const mNext; |
@@ -87,10 +100,11 @@ private: | |||
87 | int mCount; | 100 | int mCount; |
88 | const int mKey; | 101 | const int mKey; |
89 | uint64_t mConfig; | 102 | uint64_t mConfig; |
90 | bool mEnabled; | 103 | int mEnabled : 1, |
104 | mPerCpu : 1; | ||
91 | }; | 105 | }; |
92 | 106 | ||
93 | PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(false) { | 107 | PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(false), mLegacySupport(false) { |
94 | } | 108 | } |
95 | 109 | ||
96 | PerfDriver::~PerfDriver() { | 110 | PerfDriver::~PerfDriver() { |
@@ -105,13 +119,27 @@ void PerfDriver::addCpuCounters(const char *const counterName, const int type, c | |||
105 | int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1; | 119 | int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1; |
106 | char *name = new char[len]; | 120 | char *name = new char[len]; |
107 | snprintf(name, len, "%s_ccnt", counterName); | 121 | snprintf(name, len, "%s_ccnt", counterName); |
108 | mCounters = new PerfCounter(mCounters, name, type, -1); | 122 | mCounters = new PerfCounter(mCounters, name, type, -1, true); |
109 | 123 | ||
110 | for (int j = 0; j < numCounters; ++j) { | 124 | for (int j = 0; j < numCounters; ++j) { |
111 | len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1; | 125 | len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1; |
112 | name = new char[len]; | 126 | name = new char[len]; |
113 | snprintf(name, len, "%s_cnt%d", counterName, j); | 127 | snprintf(name, len, "%s_cnt%d", counterName, j); |
114 | mCounters = new PerfCounter(mCounters, name, type, -1); | 128 | mCounters = new PerfCounter(mCounters, name, type, -1, true); |
129 | } | ||
130 | } | ||
131 | |||
132 | void PerfDriver::addUncoreCounters(const char *const counterName, const int type, const int numCounters) { | ||
133 | int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1; | ||
134 | char *name = new char[len]; | ||
135 | snprintf(name, len, "%s_ccnt", counterName); | ||
136 | mCounters = new PerfCounter(mCounters, name, type, -1, false); | ||
137 | |||
138 | for (int j = 0; j < numCounters; ++j) { | ||
139 | len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1; | ||
140 | name = new char[len]; | ||
141 | snprintf(name, len, "%s_cnt%d", counterName, j); | ||
142 | mCounters = new PerfCounter(mCounters, name, type, -1, false); | ||
115 | } | 143 | } |
116 | } | 144 | } |
117 | 145 | ||
@@ -139,10 +167,16 @@ bool PerfDriver::setup() { | |||
139 | } | 167 | } |
140 | } | 168 | } |
141 | 169 | ||
142 | if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0)) { | 170 | if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 4, 0)) { |
143 | logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__); | 171 | logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__); |
144 | return false; | 172 | return false; |
145 | } | 173 | } |
174 | mLegacySupport = KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0); | ||
175 | |||
176 | if (access(EVENTS_PATH, R_OK) != 0) { | ||
177 | logg->logMessage("%s(%s:%i): " EVENTS_PATH " does not exist, is CONFIG_TRACING enabled?", __FUNCTION__, __FILE__, __LINE__); | ||
178 | return false; | ||
179 | } | ||
146 | 180 | ||
147 | // Add supported PMUs | 181 | // Add supported PMUs |
148 | bool foundCpu = false; | 182 | bool foundCpu = false; |
@@ -174,6 +208,21 @@ bool PerfDriver::setup() { | |||
174 | foundCpu = true; | 208 | foundCpu = true; |
175 | addCpuCounters(gator_cpus[i].pmnc_name, type, gator_cpus[i].pmnc_counters); | 209 | addCpuCounters(gator_cpus[i].pmnc_name, type, gator_cpus[i].pmnc_counters); |
176 | } | 210 | } |
211 | |||
212 | for (int i = 0; i < ARRAY_LENGTH(uncore_counters); ++i) { | ||
213 | if (strcmp(dirent->d_name, uncore_counters[i].name) != 0) { | ||
214 | continue; | ||
215 | } | ||
216 | |||
217 | int type; | ||
218 | char buf[256]; | ||
219 | snprintf(buf, sizeof(buf), PERF_DEVICES "/%s/type", dirent->d_name); | ||
220 | if (DriverSource::readIntDriver(buf, &type) != 0) { | ||
221 | continue; | ||
222 | } | ||
223 | |||
224 | addUncoreCounters(uncore_counters[i].name, type, uncore_counters[i].count); | ||
225 | } | ||
177 | } | 226 | } |
178 | closedir(dir); | 227 | closedir(dir); |
179 | 228 | ||
@@ -203,12 +252,12 @@ bool PerfDriver::setup() { | |||
203 | 252 | ||
204 | id = getTracepointId("irq/softirq_exit", &printb); | 253 | id = getTracepointId("irq/softirq_exit", &printb); |
205 | if (id >= 0) { | 254 | if (id >= 0) { |
206 | mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id); | 255 | mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, true); |
207 | } | 256 | } |
208 | 257 | ||
209 | id = getTracepointId("irq/irq_handler_exit", &printb); | 258 | id = getTracepointId("irq/irq_handler_exit", &printb); |
210 | if (id >= 0) { | 259 | if (id >= 0) { |
211 | mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id); | 260 | mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, true); |
212 | } | 261 | } |
213 | 262 | ||
214 | //Linux_block_rq_wr | 263 | //Linux_block_rq_wr |
@@ -218,7 +267,7 @@ bool PerfDriver::setup() { | |||
218 | 267 | ||
219 | id = getTracepointId(SCHED_SWITCH, &printb); | 268 | id = getTracepointId(SCHED_SWITCH, &printb); |
220 | if (id >= 0) { | 269 | if (id >= 0) { |
221 | mCounters = new PerfCounter(mCounters, "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id); | 270 | mCounters = new PerfCounter(mCounters, "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, true); |
222 | } | 271 | } |
223 | 272 | ||
224 | //Linux_meminfo_memused | 273 | //Linux_meminfo_memused |
@@ -227,7 +276,7 @@ bool PerfDriver::setup() { | |||
227 | //Linux_power_cpu_freq | 276 | //Linux_power_cpu_freq |
228 | //Linux_power_cpu_idle | 277 | //Linux_power_cpu_idle |
229 | 278 | ||
230 | mCounters = new PerfCounter(mCounters, "Linux_cpu_wait_contention", TYPE_DERIVED, -1); | 279 | mCounters = new PerfCounter(mCounters, "Linux_cpu_wait_contention", TYPE_DERIVED, -1, false); |
231 | 280 | ||
232 | //Linux_cpu_wait_io | 281 | //Linux_cpu_wait_io |
233 | 282 | ||
@@ -252,15 +301,16 @@ bool PerfDriver::summary(Buffer *const buffer) { | |||
252 | } | 301 | } |
253 | const int64_t timestamp = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec; | 302 | const int64_t timestamp = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec; |
254 | 303 | ||
255 | if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { | 304 | const int64_t uptime = getTime(); |
256 | logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__); | ||
257 | return false; | ||
258 | } | ||
259 | const int64_t uptime = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec; | ||
260 | 305 | ||
261 | buffer->summary(timestamp, uptime, 0, buf); | 306 | buffer->summary(timestamp, uptime, 0, buf); |
262 | 307 | ||
263 | for (int i = 0; i < gSessionData->mCores; ++i) { | 308 | for (int i = 0; i < gSessionData->mCores; ++i) { |
309 | // Don't send information on a cpu we know nothing about | ||
310 | if (gSessionData->mCpuIds[i] == -1) { | ||
311 | continue; | ||
312 | } | ||
313 | |||
264 | int j; | 314 | int j; |
265 | for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) { | 315 | for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) { |
266 | if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) { | 316 | if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) { |
@@ -270,7 +320,11 @@ bool PerfDriver::summary(Buffer *const buffer) { | |||
270 | if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) { | 320 | if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) { |
271 | buffer->coreName(i, gSessionData->mCpuIds[i], gator_cpus[j].core_name); | 321 | buffer->coreName(i, gSessionData->mCpuIds[i], gator_cpus[j].core_name); |
272 | } else { | 322 | } else { |
273 | snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]); | 323 | if (gSessionData->mCpuIds[i] == -1) { |
324 | snprintf(buf, sizeof(buf), "Unknown"); | ||
325 | } else { | ||
326 | snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]); | ||
327 | } | ||
274 | buffer->coreName(i, gSessionData->mCpuIds[i], buf); | 328 | buffer->coreName(i, gSessionData->mCpuIds[i], buf); |
275 | } | 329 | } |
276 | } | 330 | } |
@@ -326,10 +380,10 @@ int PerfDriver::writeCounters(mxml_node_t *root) const { | |||
326 | return count; | 380 | return count; |
327 | } | 381 | } |
328 | 382 | ||
329 | bool PerfDriver::enable(PerfGroup *group, Buffer *const buffer) const { | 383 | bool PerfDriver::enable(PerfGroup *const group, Buffer *const buffer) const { |
330 | for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { | 384 | for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { |
331 | if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) { | 385 | if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) { |
332 | if (!group->add(buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), 0, 0)) { | 386 | if (!group->add(buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), counter->getCount() > 0 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP : 0, counter->isPerCpu() ? PERF_GROUP_PER_CPU : 0)) { |
333 | logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__); | 387 | logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__); |
334 | return false; | 388 | return false; |
335 | } | 389 | } |