2e4af0cc7175a3485e30e408599db3707b8fd548
[android-sdk/arm-ds5-gator.git] / daemon / Collector.cpp
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"
19 #include "Sender.h"
21 // Driver initialization independent of session settings
22 Collector::Collector() {
23         char text[sizeof(gSessionData->mPerfCounterType[0]) + 30]; // sufficiently large to hold all /dev/gator/events/<types>/<file>
25         mBufferFD = 0;
27         checkVersion();
29         int enable = -1;
30         if (readIntDriver("/dev/gator/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("/dev/gator/cpu_cores", &gSessionData->mCores);
36         if (gSessionData->mCores == 0) {
37                 gSessionData->mCores = 1;
38         }
40         mBufferSize = 0;
41         if (readIntDriver("/dev/gator/buffer_size", &mBufferSize) || mBufferSize <= 0) {
42                 logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size");
43                 handleException();
44         }
46         getCoreName();
48         enablePerfCounters();
50         // Read unchanging keys from driver which are created at insmod'ing of gator.ko
51         for (int i = 0; i < MAX_PERFORMANCE_COUNTERS; i++) {
52                 if (gSessionData->mPerfCounterEnabled[i]) {
53                         snprintf(text, sizeof(text), "/dev/gator/events/%s/key", gSessionData->mPerfCounterType[i]);
54                         readIntDriver(text, &gSessionData->mPerfCounterKey[i]);
55                 }
56         }
57 }
59 Collector::~Collector() {
60         // Write zero for safety, as a zero should have already been written
61         writeDriver("/dev/gator/enable", "0");
63         // Calls event_buffer_release in the driver
64         if (mBufferFD) {
65                 close(mBufferFD);
66         }
67 }
69 #include <dirent.h>
70 void Collector::enablePerfCounters() {
71         char text[sizeof(gSessionData->mPerfCounterType[0]) + 30]; // sufficiently large to hold all /dev/gator/events/<types>/enabled
73         // Initialize all perf counters in the driver, i.e. set enabled to zero
74         struct dirent *ent;
75         DIR* dir = opendir("/dev/gator/events");
76         if (dir) {
77                 while ((ent = readdir(dir)) != NULL) {
78                         // skip hidden files, current dir, and parent dir
79                         if (ent->d_name[0] == '.')
80                                 continue;
81                         snprintf(text, sizeof(text), "/dev/gator/events/%s/enabled", ent->d_name);
82                         writeDriver(text, 0);
83                 }
84                 closedir (dir);
85         }
87         for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
88                 if (!gSessionData->mPerfCounterEnabled[i]) {
89                         continue;
90                 }
91                 snprintf(text, sizeof(text), "/dev/gator/events/%s/enabled", gSessionData->mPerfCounterType[i]);
92                 if (writeReadDriver(text, &gSessionData->mPerfCounterEnabled[i])) {
93                         // Disable those events that don't exist on this hardware platform even though they exist in configuration.xml
94                         gSessionData->mPerfCounterEnabled[i] = 0;
95                         continue;
96                 }
97         }
98 }
100 void Collector::setupPerfCounters() {
101         char base[sizeof(gSessionData->mPerfCounterType[0]) + 20]; // sufficiently large to hold all /dev/gator/events/<types>
102         char text[sizeof(gSessionData->mPerfCounterType[0]) + 30]; // sufficiently large to hold all /dev/gator/events/<types>/<file>
104         for (int i=0; i<MAX_PERFORMANCE_COUNTERS; i++) {
105                 if (!gSessionData->mPerfCounterEnabled[i]) {
106                         continue;
107                 }
108                 snprintf(base, sizeof(base), "/dev/gator/events/%s", gSessionData->mPerfCounterType[i]);
109                 snprintf(text, sizeof(text), "%s/event", base);
110                 writeDriver(text, gSessionData->mPerfCounterEvent[i]);
111                 if (gSessionData->mPerfCounterEBSCapable[i]) {
112                         snprintf(text, sizeof(text), "%s/count", base);
113                         if (access(text, F_OK) == 0) {
114                                 if (writeReadDriver(text, &gSessionData->mPerfCounterCount[i]) && gSessionData->mPerfCounterCount[i] > 0) {
115                                         logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%s with a count of %d\n", gSessionData->mPerfCounterTitle[i], gSessionData->mPerfCounterName[i], gSessionData->mPerfCounterCount[i]);
116                                         handleException();
117                                 }
118                         } else if (gSessionData->mPerfCounterCount[i] > 0) {
119                                 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");
120                                 handleException();
121                         }
122                 }
123         }
126 void Collector::checkVersion() {
127         int driver_version = 0;
129         if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
130                 logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
131                 handleException();
132         }
134         // Verify the driver version matches the daemon version
135         if (driver_version != PROTOCOL_VERSION) {
136                 if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
137                         // One of the mismatched versions is development version
138                         logg->logError(__FILE__, __LINE__,
139                                 "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
140                                 ">> The following must be synchronized from engineering repository:\n"
141                                 ">> * gator driver\n"
142                                 ">> * gator daemon\n"
143                                 ">> * Streamline", driver_version, PROTOCOL_VERSION);
144                         handleException();
145                 } else {
146                         // Release version mismatch
147                         logg->logError(__FILE__, __LINE__, 
148                                 "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
149                                 ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
150                         handleException();
151                 }
152         }
155 void Collector::start() {
156         // Set the maximum backtrace depth
157         if (writeReadDriver("/dev/gator/backtrace_depth", &gSessionData->mBacktraceDepth)) {
158                 logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
159                 handleException();
160         }
162         // open the buffer which calls userspace_buffer_open() in the driver
163         mBufferFD = open("/dev/gator/buffer", O_RDONLY);
164         if (mBufferFD < 0) {
165                 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.");
166                 handleException();
167         }
169         // set the tick rate of the profiling timer
170         if (writeReadDriver("/dev/gator/tick", &gSessionData->mSampleRate) != 0) {
171                 logg->logError(__FILE__, __LINE__, "Unable to set the driver tick");
172                 handleException();
173         }
175         // notify the kernel of the response type
176         int response_type = gSessionData->mLocalCapture ? 0 : RESPONSE_APC_DATA;
177         if (writeDriver("/dev/gator/response_type", response_type)) {
178                 logg->logError(__FILE__, __LINE__, "Unable to write the response type");
179                 handleException();
180         }
182         logg->logMessage("Start the driver");
184         // This command makes the driver start profiling by calling gator_op_start() in the driver
185         if (writeDriver("/dev/gator/enable", "1") != 0) {
186                 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.");
187                 handleException();
188         }
190         lseek(mBufferFD, 0, SEEK_SET);
193 // These commands should cause the read() function in collect() to return
194 void Collector::stop() {
195         // This will stop the driver from profiling
196         if (writeDriver("/dev/gator/enable", "0") != 0) {
197                 logg->logMessage("Stopping kernel failed");
198         }
201 int Collector::collect(char* buffer) {
202         // Calls event_buffer_read in the driver
203         int bytesRead;
205         errno = 0;
206         bytesRead = read(mBufferFD, buffer, mBufferSize);
208         // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data
209         if (bytesRead == -1 && errno == EINTR) {
210                 bytesRead = read(mBufferFD, buffer, mBufferSize);
211         }
213         // return the total bytes written
214         logg->logMessage("Driver read of %d bytes", bytesRead);
215         return bytesRead;
218 void Collector::getCoreName() {
219         char temp[256]; // arbitrarily large amount
220         strcpy(gSessionData->mCoreName, "unknown");
222         FILE* f = fopen("/proc/cpuinfo", "r");  
223         if (f == NULL) {
224                 logg->logMessage("Error opening /proc/cpuinfo\n"
225                         "The core name in the captured xml file will be 'unknown'.");
226                 return;
227         }
229         while (fgets(temp, sizeof(temp), f)) {
230                 if (strlen(temp) > 0) {
231                         temp[strlen(temp) - 1] = 0;     // Replace the line feed with a null
232                 }
234                 if (strstr(temp, "Hardware") != 0) {
235                         char* position = strchr(temp, ':');
236                         if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
237                                 logg->logMessage("Unknown format of /proc/cpuinfo\n"
238                                         "The core name in the captured xml file will be 'unknown'.");
239                                 return;
240                         }
241                         strncpy(gSessionData->mCoreName, (char*)((long)position + 2), sizeof(gSessionData->mCoreName));
242                         gSessionData->mCoreName[sizeof(gSessionData->mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
243                         fclose(f);
244                         return;
245                 }
246         }
248         logg->logMessage("Could not determine core name from /proc/cpuinfo\n"
249                 "The core name in the captured xml file will be 'unknown'.");
250         fclose(f);
253 int Collector::readIntDriver(const char* fullpath, int* value) {
254         FILE* file = fopen(fullpath, "r");
255         if (file == NULL) {
256                 return -1;
257         }
258         if (fscanf(file, "%u", value) != 1) {
259                 fclose(file);
260                 logg->logMessage("Invalid value in file %s", fullpath);
261                 return -1;
262         }
263         fclose(file);
264         return 0;
267 int Collector::writeDriver(const char* path, int value) {
268         char data[40]; // Sufficiently large to hold any integer
269         snprintf(data, sizeof(data), "%d", value);
270         return writeDriver(path, data);
273 int Collector::writeDriver(const char* fullpath, const char* data) {
274         int fd = open(fullpath, O_WRONLY);
275         if (fd < 0) {
276                 return -1;
277         }
278         if (write(fd, data, strlen(data)) < 0) {
279                 close(fd);
280                 logg->logMessage("Opened but could not write to %s", fullpath);
281                 return -1;
282         }
283         close(fd);
284         return 0;
287 int Collector::writeReadDriver(const char* path, int* value) {
288         if (writeDriver(path, *value) || readIntDriver(path, value)) {
289                 return -1;
290         }
291         return 0;