7a41198e5cb4e1a7d0a96ea198d076e6ed384698
1 /**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved.
3 *
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 */
9 #include <fcntl.h>
10 #include <malloc.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <errno.h>
15 #include <sys/time.h>
16 #include "Collector.h"
17 #include "SessionData.h"
18 #include "Logging.h"
20 extern void handleException();
22 // Driver initialization independent of session settings
23 Collector::Collector() {
24 char text[sizeof(gSessionData->mPerfCounterType[0]) + 20]; // sufficiently large to hold all events/<types>/<file>
26 bufferFD = 0;
28 checkVersion();
30 int enable = -1;
31 if (readIntDriver("enable", &enable) != 0 || enable != 0) {
32 logg->logError(__FILE__, __LINE__, "Driver already enabled, possibly a session is already in progress.");
33 handleException();
34 }
36 readIntDriver("cpu_cores", &gSessionData->mCores);
37 if (gSessionData->mCores == 0) {
38 gSessionData->mCores = 1;
39 }
41 bufferSize = 512 * 1024;
42 if (writeReadDriver("buffer_size", &bufferSize) || bufferSize <= 0) {
43 logg->logError(__FILE__, __LINE__, "Unable to set the driver buffer size");
44 handleException();
45 }
47 getCoreName();
49 enablePerfCounters();
51 // Read unchanging keys from driver which are created at insmod'ing of gator.ko
52 for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
53 if (gSessionData->mPerfCounterEnabled[i]) {
54 snprintf(text, sizeof(text), "events/%s/key", gSessionData->mPerfCounterType[i]);
55 readIntDriver(text, &gSessionData->mPerfCounterKey[i]);
56 }
57 }
58 }
60 Collector::~Collector() {
61 // Write zero for safety, as a zero should have already been written
62 writeDriver("enable", "0");
64 // Calls event_buffer_release in the driver
65 if (bufferFD) {
66 close(bufferFD);
67 }
68 }
70 void Collector::enablePerfCounters() {
71 char text[sizeof(gSessionData->mPerfCounterType[0]) + 30]; // sufficiently large to hold all /dev/gator/events/<types>/enabled
72 for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
73 if (!gSessionData->mPerfCounterEnabled[i]) {
74 continue;
75 }
76 snprintf(text, sizeof(text), "events/%s/enabled", gSessionData->mPerfCounterType[i]);
77 if (writeReadDriver(text, &gSessionData->mPerfCounterEnabled[i])) {
78 // Disable those events that don't exist on this hardware platform even though they exist in configuration.xml
79 gSessionData->mPerfCounterEnabled[i] = 0;
80 continue;
81 }
82 }
83 }
85 void Collector::setupPerfCounters() {
86 char base[sizeof(gSessionData->mPerfCounterType[0]) + 10]; // sufficiently large to hold all events/<types>
87 char text[sizeof(gSessionData->mPerfCounterType[0]) + 20]; // sufficiently large to hold all events/<types>/<file>
89 for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
90 if (!gSessionData->mPerfCounterEnabled[i]) {
91 continue;
92 }
93 snprintf(base, sizeof(base), "events/%s", gSessionData->mPerfCounterType[i]);
94 snprintf(text, sizeof(text), "%s/event", base);
95 writeDriver(text, gSessionData->mPerfCounterEvent[i]);
96 if (gSessionData->mPerfCounterEBSCapable[i]) {
97 snprintf(text, sizeof(text), "%s/count", base);
98 if (access(resolvePath(text), F_OK) == 0) {
99 if (writeReadDriver(text, &gSessionData->mPerfCounterCount[i]) && gSessionData->mPerfCounterCount[i] > 0) {
100 logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s with a count of %d\n", gSessionData->mPerfCounterName[i], gSessionData->mPerfCounterCount[i]);
101 handleException();
102 }
103 } else if (gSessionData->mPerfCounterCount[i] > 0) {
104 logg->logError(__FILE__, __LINE__, "Event Based Sampling is only supported with kernel versions 3.0.0 and higher with CONFIG_PERF_EVENTS=y, and CONFIG_HW_PERF_EVENTS=y\n");
105 handleException();
106 }
107 }
108 }
109 }
111 void Collector::checkVersion() {
112 int driver_version = 0;
114 if (readIntDriver("version", &driver_version) == -1) {
115 logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
116 handleException();
117 }
119 // Verify the driver version matches the daemon version
120 if (driver_version != PROTOCOL_VERSION) {
121 if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
122 // One of the mismatched versions is development version
123 logg->logError(__FILE__, __LINE__,
124 "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
125 ">> The following must be synchronized from engineering repository:\n"
126 ">> * gator driver\n"
127 ">> * gator daemon\n"
128 ">> * Streamline", driver_version, PROTOCOL_VERSION);
129 handleException();
130 } else {
131 // Release version mismatch
132 logg->logError(__FILE__, __LINE__,
133 "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
134 ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
135 handleException();
136 }
137 }
138 }
140 void Collector::start() {
141 // Set the maximum backtrace depth
142 if (writeReadDriver("backtrace_depth", &gSessionData->mBacktraceDepth)) {
143 logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
144 handleException();
145 }
147 // open the buffer which calls userspace_buffer_open() in the driver
148 bufferFD = open(resolvePath("buffer"), O_RDONLY);
149 if (bufferFD < 0) {
150 logg->logError(__FILE__, __LINE__, "The gator driver did not set up properly. Please view the linux console or dmesg log for more information on the failure.");
151 handleException();
152 }
154 // set the tick rate of the profiling timer
155 if (writeReadDriver("tick", &gSessionData->mSampleRate) != 0) {
156 logg->logError(__FILE__, __LINE__, "Unable to set the driver tick");
157 handleException();
158 }
160 // notify the kernel of the streaming mode, currently used for network stats
161 int streaming = (int)!gSessionData->mOneShot;
162 if (writeReadDriver("streaming", &streaming) != 0) {
163 logg->logError(__FILE__, __LINE__, "Unable to set streaming");
164 handleException();
165 }
167 logg->logMessage("Start the driver");
169 // This command makes the driver start profiling by calling gator_op_start() in the driver
170 if (writeDriver("enable", "1") != 0) {
171 logg->logError(__FILE__, __LINE__, "The gator driver did not start properly. Please view the linux console or dmesg log for more information on the failure.");
172 handleException();
173 }
175 lseek(bufferFD, 0, SEEK_SET);
176 }
178 // These commands should cause the read() function in collect() to return
179 void Collector::stop() {
180 // This will stop the driver from profiling
181 if (writeDriver("enable", "0") != 0) {
182 logg->logMessage("Stopping kernel failed");
183 }
184 }
186 int Collector::collect(char* buffer) {
187 // Calls event_buffer_read in the driver
188 int bytesRead = read(bufferFD, buffer, bufferSize);
190 // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data
191 if (bytesRead == -1 && errno == EINTR) {
192 bytesRead = read(bufferFD, buffer, bufferSize);
193 }
195 logg->logMessage("Driver read of %d bytes", bytesRead);
197 return bytesRead;
198 }
200 void Collector::getCoreName() {
201 char temp[256]; // arbitrarily large amount
202 strcpy(gSessionData->mCoreName, "unknown");
204 FILE* f = fopen("/proc/cpuinfo", "r");
205 if (f == NULL) {
206 logg->logMessage("Error opening /proc/cpuinfo\n"
207 "The core name in the captured xml file will be 'unknown'.");
208 return;
209 }
211 while (fgets(temp, sizeof(temp), f)) {
212 if (strlen(temp) > 0)
213 temp[strlen(temp) - 1] = 0; // Replace the line feed with a null
215 if (strstr(temp, "Hardware") != 0) {
216 char* position = strchr(temp, ':');
217 if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
218 logg->logMessage("Unknown format of /proc/cpuinfo\n"
219 "The core name in the captured xml file will be 'unknown'.");
220 return;
221 }
222 strncpy(gSessionData->mCoreName, (char *)((int)position + 2), sizeof(gSessionData->mCoreName));
223 gSessionData->mCoreName[sizeof(gSessionData->mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
224 fclose(f);
225 return;
226 }
227 }
229 logg->logMessage("Could not determine core name from /proc/cpuinfo\n"
230 "The core name in the captured xml file will be 'unknown'.");
231 fclose(f);
232 }
234 char* Collector::resolvePath(const char* file) {
235 static char fullpath[100]; // Sufficiently large to hold any path within /dev/gator
236 snprintf(fullpath, sizeof(fullpath), "/dev/gator/%s", file);
237 return fullpath;
238 }
240 int Collector::readIntDriver(const char* path, int* value) {
241 char* fullpath = resolvePath(path);
242 FILE* file = fopen(fullpath, "r");
243 if (file == NULL) {
244 return -1;
245 }
246 if (fscanf(file, "%u", value) != 1) {
247 fclose(file);
248 logg->logMessage("Invalid value in file %s", fullpath);
249 return -1;
250 }
251 fclose(file);
252 return 0;
253 }
255 int Collector::writeDriver(const char* path, int value) {
256 char data[40]; // Sufficiently large to hold any integer
257 snprintf(data, sizeof(data), "%d", value);
258 return writeDriver(path, data);
259 }
261 int Collector::writeDriver(const char* path, const char* data) {
262 char* fullpath = resolvePath(path);
263 int fd = open(fullpath, O_WRONLY);
264 if (fd < 0) {
265 return -1;
266 }
267 if (write(fd, data, strlen(data)) < 0) {
268 close(fd);
269 logg->logMessage("Opened but could not write to %s", fullpath);
270 return -1;
271 }
272 close(fd);
273 return 0;
274 }
276 int Collector::writeReadDriver(const char* path, int* value) {
277 if (writeDriver(path, *value) || readIntDriver(path, value)) {
278 return -1;
279 }
280 return 0;
281 }