1 /**
2 * Copyright (C) ARM Limited 2010-2011. 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"
19 #include "ConfigurationXML.h"
21 extern void handleException();
23 // Driver initialization independent of session settings
24 Collector::Collector() {
25 bufferFD = 0;
27 checkVersion();
29 int enable = -1;
30 if (readIntDriver("enable", &enable) != 0 || enable != 0) {
31 logg->logError(__FILE__, __LINE__, "Driver already enabled, possibly a session is already in progress.");
32 handleException();
33 }
35 readIntDriver("cpu_cores", &gSessionData.mCores);
36 if (gSessionData.mCores == 0) {
37 gSessionData.mCores = 1;
38 }
40 bufferSize = 512 * 1024;
41 if (writeReadDriver("buffer_size", &bufferSize) || bufferSize <= 0) {
42 logg->logError(__FILE__, __LINE__, "Unable to set the driver buffer size");
43 handleException();
44 }
46 getCoreName();
48 // populate performance counter session data
49 new ConfigurationXML();
50 }
52 Collector::~Collector() {
53 // Write zero for safety, as a zero should have already been written
54 writeDriver("enable", "0");
56 // Calls event_buffer_release in the driver
57 if (bufferFD) {
58 close(bufferFD);
59 }
60 }
62 void Collector::enablePerfCounters() {
63 char base[sizeof(gSessionData.mPerfCounterType[0]) + 10]; // sufficiently large to hold all events/<types>
64 char text[sizeof(gSessionData.mPerfCounterType[0]) + 20]; // sufficiently large to hold all events/<types>/<file>
66 for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
67 if (!gSessionData.mPerfCounterEnabled[i]) {
68 continue;
69 }
70 snprintf(base, sizeof(base), "events/%s", gSessionData.mPerfCounterType[i]);
71 snprintf(text, sizeof(text), "%s/event", base);
72 writeDriver(text, gSessionData.mPerfCounterEvent[i]);
73 snprintf(text, sizeof(text), "%s/key", base);
74 readIntDriver(text, &gSessionData.mPerfCounterKey[i]);
75 if (gSessionData.mPerfCounterEBSCapable[i]) {
76 snprintf(text, sizeof(text), "%s/count", base);
77 if (writeReadDriver(text, &gSessionData.mPerfCounterCount[i]))
78 gSessionData.mPerfCounterCount[i] = 0;
79 if (gSessionData.mPerfCounterCount[i] > 0)
80 logg->logMessage("EBS enabled for %s with a count of %d", gSessionData.mPerfCounterName[i], gSessionData.mPerfCounterCount[i]);
81 }
82 snprintf(text, sizeof(text), "%s/enabled", base);
83 if (writeReadDriver(text, &gSessionData.mPerfCounterEnabled[i])) {
84 gSessionData.mPerfCounterEnabled[i] = 0;
85 }
86 }
87 }
89 void Collector::checkVersion() {
90 int driver_version = 0;
92 if (readIntDriver("version", &driver_version) == -1) {
93 logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
94 handleException();
95 }
97 // Verify the driver version matches the daemon version
98 if (driver_version != PROTOCOL_VERSION) {
99 if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
100 // One of the mismatched versions is development version
101 logg->logError(__FILE__, __LINE__,
102 "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
103 ">> The following must be synchronized from engineering repository:\n"
104 ">> * gator driver\n"
105 ">> * gator daemon\n"
106 ">> * Streamline", driver_version, PROTOCOL_VERSION);
107 handleException();
108 } else {
109 // Release version mismatch
110 logg->logError(__FILE__, __LINE__,
111 "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
112 ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
113 handleException();
114 }
115 }
116 }
118 void Collector::start() {
119 // Set the maximum backtrace depth
120 if (writeReadDriver("backtrace_depth", &gSessionData.mBacktraceDepth)) {
121 logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
122 handleException();
123 }
125 // open the buffer which calls userspace_buffer_open() in the driver
126 char* fullpath = resolvePath("buffer");
127 bufferFD = open(fullpath, O_RDONLY);
128 if (bufferFD < 0) {
129 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.");
130 handleException();
131 }
133 // set the tick rate of the profiling timer
134 if (writeReadDriver("tick", &gSessionData.mSampleRate) != 0) {
135 logg->logError(__FILE__, __LINE__, "Unable to set the driver tick");
136 handleException();
137 }
139 // notify the kernel of the streaming mode, currently used for network stats
140 int streaming = (int)!gSessionData.mOneShot;
141 if (writeReadDriver("streaming", &streaming) != 0) {
142 logg->logError(__FILE__, __LINE__, "Unable to set streaming");
143 handleException();
144 }
146 logg->logMessage("Start the driver");
148 // This command makes the driver start profiling by calling gator_op_start() in the driver
149 if (writeDriver("enable", "1") != 0) {
150 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.");
151 handleException();
152 }
154 lseek(bufferFD, 0, SEEK_SET);
155 }
157 // These commands should cause the read() function in collect() to return
158 void Collector::stop() {
159 // This will stop the driver from profiling
160 if (writeDriver("enable", "0") != 0) {
161 logg->logMessage("Stopping kernel failed");
162 }
163 }
165 int Collector::collect(char* buffer) {
166 // Calls event_buffer_read in the driver
167 int bytesRead = read(bufferFD, buffer, bufferSize);
169 // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data
170 if (bytesRead == -1 && errno == EINTR) {
171 bytesRead = read(bufferFD, buffer, bufferSize);
172 }
174 logg->logMessage("Driver read of %d bytes", bytesRead);
176 return bytesRead;
177 }
179 void Collector::getCoreName() {
180 char temp[256]; // arbitrarily large amount
181 strcpy(gSessionData.mCoreName, "unknown");
183 FILE* f = fopen("/proc/cpuinfo", "r");
184 if (f == NULL) {
185 logg->logMessage("Error opening /proc/cpuinfo\n"
186 "The core name in the captured xml file will be 'unknown'.");
187 return;
188 }
190 while (fgets(temp, sizeof(temp), f)) {
191 if (strlen(temp) > 0)
192 temp[strlen(temp) - 1] = 0; // Replace the line feed with a null
194 if (strstr(temp, "Hardware") != 0) {
195 char* position = strchr(temp, ':');
196 if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
197 logg->logMessage("Unknown format of /proc/cpuinfo\n"
198 "The core name in the captured xml file will be 'unknown'.");
199 return;
200 }
201 strncpy(gSessionData.mCoreName, (char *)((int)position + 2), sizeof(gSessionData.mCoreName));
202 gSessionData.mCoreName[sizeof(gSessionData.mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
203 fclose(f);
204 return;
205 }
206 }
208 logg->logMessage("Could not determine core name from /proc/cpuinfo\n"
209 "The core name in the captured xml file will be 'unknown'.");
210 fclose(f);
211 }
213 char* Collector::resolvePath(const char* file) {
214 static char fullpath[100]; // Sufficiently large to hold any path within /dev/gator
215 snprintf(fullpath, sizeof(fullpath), "/dev/gator/%s", file);
216 return fullpath;
217 }
219 int Collector::readIntDriver(const char* path, int* value) {
220 char* fullpath = resolvePath(path);
221 FILE* file = fopen(fullpath, "r");
222 if (file == NULL) {
223 return -1;
224 }
225 if (fscanf(file, "%u", value) != 1) {
226 fclose(file);
227 logg->logMessage("Invalid value in file %s", fullpath);
228 return -1;
229 }
230 fclose(file);
231 return 0;
232 }
234 int Collector::writeDriver(const char* path, int value) {
235 char data[40]; // Sufficiently large to hold any integer
236 snprintf(data, sizeof(data), "%d", value);
237 return writeDriver(path, data);
238 }
240 int Collector::writeDriver(const char* path, const char* data) {
241 char* fullpath = resolvePath(path);
242 int fd = open(fullpath, O_WRONLY);
243 if (fd < 0) {
244 return -1;
245 }
246 if (write(fd, data, strlen(data)) < 0) {
247 close(fd);
248 logg->logMessage("Opened but could not write to %s", fullpath);
249 return -1;
250 }
251 close(fd);
252 return 0;
253 }
255 int Collector::writeReadDriver(const char* path, int* value) {
256 if (writeDriver(path, *value) || readIntDriver(path, value)) {
257 return -1;
258 }
259 return 0;
260 }