blob: 98bd0a5d9eece006ddf4c9c3f2deea86d1db808c [file] [log] [blame]
Jon Medhurst96b56152014-10-30 18:01:15 +00001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2014-2015. All rights reserved.
Jon Medhurst96b56152014-10-30 18:01:15 +00003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "FtraceDriver.h"
10
11#include <regex.h>
Jon Medhurstb1d07442015-05-08 12:04:18 +010012#include <unistd.h>
Jon Medhurst96b56152014-10-30 18:01:15 +000013
Jon Medhurstb1d07442015-05-08 12:04:18 +010014#include "DriverSource.h"
Jon Medhurst96b56152014-10-30 18:01:15 +000015#include "Logging.h"
Jon Medhurstb1d07442015-05-08 12:04:18 +010016#include "Setup.h"
Jon Medhurst96b56152014-10-30 18:01:15 +000017
18class FtraceCounter : public DriverCounter {
19public:
Jon Medhurstb1d07442015-05-08 12:04:18 +010020 FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable);
Jon Medhurst96b56152014-10-30 18:01:15 +000021 ~FtraceCounter();
22
Jon Medhurstb1d07442015-05-08 12:04:18 +010023 void prepare();
Jon Medhurst96b56152014-10-30 18:01:15 +000024 int read(const char *const line, int64_t *values);
Jon Medhurstb1d07442015-05-08 12:04:18 +010025 void stop();
Jon Medhurst96b56152014-10-30 18:01:15 +000026
27private:
Jon Medhurstb1d07442015-05-08 12:04:18 +010028 regex_t mReg;
29 char *const mEnable;
30 int mWasEnabled;
Jon Medhurst96b56152014-10-30 18:01:15 +000031
32 // Intentionally unimplemented
33 FtraceCounter(const FtraceCounter &);
34 FtraceCounter &operator=(const FtraceCounter &);
35};
36
Jon Medhurstb1d07442015-05-08 12:04:18 +010037FtraceCounter::FtraceCounter(DriverCounter *next, char *name, const char *regex, const char *enable) : DriverCounter(next, name), mEnable(enable == NULL ? NULL : strdup(enable)) {
38 int result = regcomp(&mReg, regex, REG_EXTENDED);
Jon Medhurst96b56152014-10-30 18:01:15 +000039 if (result != 0) {
40 char buf[128];
Jon Medhurstb1d07442015-05-08 12:04:18 +010041 regerror(result, &mReg, buf, sizeof(buf));
42 logg->logError("Invalid regex '%s': %s", regex, buf);
Jon Medhurst96b56152014-10-30 18:01:15 +000043 handleException();
44 }
45}
46
47FtraceCounter::~FtraceCounter() {
Jon Medhurstb1d07442015-05-08 12:04:18 +010048 regfree(&mReg);
49 if (mEnable != NULL) {
50 free(mEnable);
51 }
52}
53
54void FtraceCounter::prepare() {
55 if (mEnable == NULL) {
56 return;
57 }
58
59 char buf[1<<10];
60 snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
61 if ((DriverSource::readIntDriver(buf, &mWasEnabled) != 0) ||
62 (DriverSource::writeDriver(buf, 1) != 0)) {
63 logg->logError("Unable to read or write to %s", buf);
64 handleException();
65 }
Jon Medhurst96b56152014-10-30 18:01:15 +000066}
67
68int FtraceCounter::read(const char *const line, int64_t *values) {
69 regmatch_t match[2];
Jon Medhurstb1d07442015-05-08 12:04:18 +010070 int result = regexec(&mReg, line, 2, match, 0);
Jon Medhurst96b56152014-10-30 18:01:15 +000071 if (result != 0) {
72 // No match
73 return 0;
74 }
75
Jon Medhurstb1d07442015-05-08 12:04:18 +010076 int64_t value;
Jon Medhurst96b56152014-10-30 18:01:15 +000077 if (match[1].rm_so < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010078 value = 1;
79 } else {
80 errno = 0;
81 value = strtoll(line + match[1].rm_so, NULL, 0);
82 if (errno != 0) {
83 logg->logError("Parsing %s failed: %s", getName(), strerror(errno));
84 handleException();
85 }
Jon Medhurst96b56152014-10-30 18:01:15 +000086 }
87
88 values[0] = getKey();
89 values[1] = value;
90
91 return 1;
92}
93
Jon Medhurstb1d07442015-05-08 12:04:18 +010094void FtraceCounter::stop() {
95 if (mEnable == NULL) {
96 return;
97 }
98
99 char buf[1<<10];
100 snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", mEnable);
101 DriverSource::writeDriver(buf, mWasEnabled);
102}
103
Jon Medhurst96b56152014-10-30 18:01:15 +0000104FtraceDriver::FtraceDriver() : mValues(NULL) {
105}
106
107FtraceDriver::~FtraceDriver() {
108 delete [] mValues;
109}
110
111void FtraceDriver::readEvents(mxml_node_t *const xml) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100112 // Check the kernel version
113 int release[3];
114 if (!getLinuxVersion(release)) {
115 logg->logError("getLinuxVersion failed");
116 handleException();
117 }
118
119 // The perf clock was added in 3.10
120 if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 10, 0)) {
121 logg->logMessage("Unsupported kernel version, to use ftrace please upgrade to Linux 3.10 or later");
122 return;
123 }
124
Jon Medhurst96b56152014-10-30 18:01:15 +0000125 mxml_node_t *node = xml;
126 int count = 0;
127 while (true) {
128 node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
129 if (node == NULL) {
130 break;
131 }
132 const char *counter = mxmlElementGetAttr(node, "counter");
133 if (counter == NULL) {
134 continue;
135 }
136
137 if (strncmp(counter, "ftrace_", 7) != 0) {
138 continue;
139 }
140
141 const char *regex = mxmlElementGetAttr(node, "regex");
142 if (regex == NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100143 logg->logError("The regex counter %s is missing the required regex attribute", counter);
Jon Medhurst96b56152014-10-30 18:01:15 +0000144 handleException();
145 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100146 bool addCounter = true;
147 const char *enable = mxmlElementGetAttr(node, "enable");
148 if (enable != NULL) {
149 char buf[1<<10];
150 snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/enable", enable);
151 if (access(buf, W_OK) != 0) {
152 logg->logMessage("Disabling counter %s, %s not found", counter, buf);
153 addCounter = false;
154 }
155 }
156 if (addCounter) {
157 setCounters(new FtraceCounter(getCounters(), strdup(counter), regex, enable));
158 ++count;
159 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000160 }
161
162 mValues = new int64_t[2*count];
163}
164
Jon Medhurstb1d07442015-05-08 12:04:18 +0100165void FtraceDriver::prepare() {
166 for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
167 if (!counter->isEnabled()) {
168 continue;
169 }
170 counter->prepare();
171 }
172}
173
Jon Medhurst96b56152014-10-30 18:01:15 +0000174int FtraceDriver::read(const char *line, int64_t **buf) {
175 int count = 0;
176
177 for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
178 if (!counter->isEnabled()) {
179 continue;
180 }
181 count += counter->read(line, mValues + 2*count);
182 }
183
184 *buf = mValues;
185 return count;
186}
Jon Medhurstb1d07442015-05-08 12:04:18 +0100187
188void FtraceDriver::stop() {
189 for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL; counter = static_cast<FtraceCounter *>(counter->getNext())) {
190 if (!counter->isEnabled()) {
191 continue;
192 }
193 counter->stop();
194 }
195}