gator: Version 5.21.1
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / SessionData.cpp
1 /**
2  * Copyright (C) ARM Limited 2010-2015. 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  */
8
9 #include "SessionData.h"
10
11 #include <fcntl.h>
12 #include <string.h>
13 #include <sys/mman.h>
14 #include <unistd.h>
15
16 #include "DiskIODriver.h"
17 #include "FSDriver.h"
18 #include "HwmonDriver.h"
19 #include "Logging.h"
20 #include "MemInfoDriver.h"
21 #include "NetDriver.h"
22 #include "SessionXML.h"
23
24 #define CORE_NAME_UNKNOWN "unknown"
25
26 SessionData* gSessionData = NULL;
27
28 SessionData::SessionData() {
29         usDrivers[0] = new HwmonDriver();
30         usDrivers[1] = new FSDriver();
31         usDrivers[2] = new MemInfoDriver();
32         usDrivers[3] = new NetDriver();
33         usDrivers[4] = new DiskIODriver();
34         initialize();
35 }
36
37 SessionData::~SessionData() {
38 }
39
40 void SessionData::initialize() {
41         mWaitingOnCommand = false;
42         mSessionIsActive = false;
43         mLocalCapture = false;
44         mOneShot = false;
45         mSentSummary = false;
46         mAllowCommands = false;
47         const size_t cpuIdSize = sizeof(int)*NR_CPUS;
48         // Share mCpuIds across all instances of gatord
49         mCpuIds = (int *)mmap(NULL, cpuIdSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
50         if (mCpuIds == MAP_FAILED) {
51                 logg->logError("Unable to mmap shared memory for cpuids");
52                 handleException();
53         }
54         memset(mCpuIds, -1, cpuIdSize);
55         strcpy(mCoreName, CORE_NAME_UNKNOWN);
56         readModel();
57         readCpuInfo();
58         mImages = NULL;
59         mConfigurationXMLPath = NULL;
60         mSessionXMLPath = NULL;
61         mEventsXMLPath = NULL;
62         mEventsXMLAppend = NULL;
63         mTargetPath = NULL;
64         mAPCDir = NULL;
65         mCaptureWorkingDir = NULL;
66         mCaptureCommand = NULL;
67         mCaptureUser = NULL;
68         mSampleRate = 0;
69         mLiveRate = 0;
70         mDuration = 0;
71         mMonotonicStarted = -1;
72         mBacktraceDepth = 0;
73         mTotalBufferSize = 0;
74         // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
75         mCores = 1;
76         mPageSize = 0;
77         mAnnotateStart = -1;
78 }
79
80 void SessionData::parseSessionXML(char* xmlString) {
81         SessionXML session(xmlString);
82         session.parse();
83
84         // Set session data values - use prime numbers just below the desired value to reduce the chance of events firing at the same time
85         if (strcmp(session.parameters.sample_rate, "high") == 0) {
86                 mSampleRate = 9973; // 10000
87         } else if (strcmp(session.parameters.sample_rate, "normal") == 0) {
88                 mSampleRate = 997; // 1000
89         } else if (strcmp(session.parameters.sample_rate, "low") == 0) {
90                 mSampleRate = 97; // 100
91         } else if (strcmp(session.parameters.sample_rate, "none") == 0) {
92                 mSampleRate = 0;
93         } else {
94                 logg->logError("Invalid sample rate (%s) in session xml.", session.parameters.sample_rate);
95                 handleException();
96         }
97         mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0;
98
99         // Determine buffer size (in MB) based on buffer mode
100         mOneShot = true;
101         if (strcmp(session.parameters.buffer_mode, "streaming") == 0) {
102                 mOneShot = false;
103                 mTotalBufferSize = 1;
104         } else if (strcmp(session.parameters.buffer_mode, "small") == 0) {
105                 mTotalBufferSize = 1;
106         } else if (strcmp(session.parameters.buffer_mode, "normal") == 0) {
107                 mTotalBufferSize = 4;
108         } else if (strcmp(session.parameters.buffer_mode, "large") == 0) {
109                 mTotalBufferSize = 16;
110         } else {
111                 logg->logError("Invalid value for buffer mode in session xml.");
112                 handleException();
113         }
114
115         // Convert milli- to nanoseconds
116         mLiveRate = session.parameters.live_rate * (int64_t)1000000;
117         if (mLiveRate > 0 && mLocalCapture) {
118                 logg->logMessage("Local capture is not compatable with live, disabling live");
119                 mLiveRate = 0;
120         }
121
122         if (!mAllowCommands && (mCaptureCommand != NULL)) {
123                 logg->logError("Running a command during a capture is not currently allowed. Please restart gatord with the -a flag.");
124                 handleException();
125         }
126 }
127
128 void SessionData::readModel() {
129         FILE *fh = fopen("/proc/device-tree/model", "rb");
130         if (fh == NULL) {
131                 return;
132         }
133
134         char buf[256];
135         if (fgets(buf, sizeof(buf), fh) != NULL) {
136                 strcpy(mCoreName, buf);
137         }
138
139         fclose(fh);
140 }
141
142 static void setImplementer(int &cpuId, const int implementer) {
143         if (cpuId == -1) {
144                 cpuId = 0;
145         }
146         cpuId |= implementer << 12;
147 }
148
149 static void setPart(int &cpuId, const int part) {
150         if (cpuId == -1) {
151                 cpuId = 0;
152         }
153         cpuId |= part;
154 }
155
156 void SessionData::readCpuInfo() {
157         char temp[256]; // arbitrarily large amount
158         mMaxCpuId = -1;
159
160         FILE *f = fopen("/proc/cpuinfo", "r");
161         if (f == NULL) {
162                 logg->logMessage("Error opening /proc/cpuinfo\n"
163                         "The core name in the captured xml file will be 'unknown'.");
164                 return;
165         }
166
167         bool foundCoreName = (strcmp(mCoreName, CORE_NAME_UNKNOWN) != 0);
168         int processor = -1;
169         while (fgets(temp, sizeof(temp), f)) {
170                 const size_t len = strlen(temp);
171
172                 if (len == 1) {
173                         // New section, clear the processor. Streamline will not know the cpus if the pre Linux 3.8 format of cpuinfo is encountered but also that no incorrect information will be transmitted.
174                         processor = -1;
175                         continue;
176                 }
177
178                 if (len > 0) {
179                         // Replace the line feed with a null
180                         temp[len - 1] = '\0';
181                 }
182
183                 const bool foundHardware = !foundCoreName && strstr(temp, "Hardware") != 0;
184                 const bool foundCPUImplementer = strstr(temp, "CPU implementer") != 0;
185                 const bool foundCPUPart = strstr(temp, "CPU part") != 0;
186                 const bool foundProcessor = strstr(temp, "processor") != 0;
187                 if (foundHardware || foundCPUImplementer || foundCPUPart || foundProcessor) {
188                         char* position = strchr(temp, ':');
189                         if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
190                                 logg->logMessage("Unknown format of /proc/cpuinfo\n"
191                                         "The core name in the captured xml file will be 'unknown'.");
192                                 return;
193                         }
194                         position += 2;
195
196                         if (foundHardware) {
197                                 strncpy(mCoreName, position, sizeof(mCoreName));
198                                 mCoreName[sizeof(mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
199                                 foundCoreName = true;
200                         }
201
202                         if (foundCPUImplementer) {
203                                 const int implementer = strtol(position, NULL, 0);
204                                 if (processor >= NR_CPUS) {
205                                         logg->logMessage("Too many processors, please increase NR_CPUS");
206                                 } else if (processor >= 0) {
207                                         setImplementer(mCpuIds[processor], implementer);
208                                 } else {
209                                         setImplementer(mMaxCpuId, implementer);
210                                 }
211                         }
212
213                         if (foundCPUPart) {
214                                 const int cpuId = strtol(position, NULL, 0);
215                                 if (processor >= NR_CPUS) {
216                                         logg->logMessage("Too many processors, please increase NR_CPUS");
217                                 } else if (processor >= 0) {
218                                         setPart(mCpuIds[processor], cpuId);
219                                 } else {
220                                         setPart(mMaxCpuId, cpuId);
221                                 }
222                         }
223
224                         if (foundProcessor) {
225                                 processor = strtol(position, NULL, 0);
226                         }
227                 }
228         }
229
230         // If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId
231         for (int i = 0; i < NR_CPUS; ++i) {
232                 if (mCpuIds[i] > mMaxCpuId) {
233                         mMaxCpuId = mCpuIds[i];
234                 }
235         }
236
237         if (!foundCoreName) {
238                 logg->logMessage("Could not determine core name from /proc/cpuinfo\n"
239                                  "The core name in the captured xml file will be 'unknown'.");
240         }
241         fclose(f);
242 }
243
244 uint64_t getTime() {
245         struct timespec ts;
246         if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
247                 logg->logError("Failed to get uptime");
248                 handleException();
249         }
250         return (NS_PER_S*ts.tv_sec + ts.tv_nsec);
251 }
252
253 int getEventKey() {
254         // key 0 is reserved as a timestamp
255         // key 1 is reserved as the marker for thread specific counters
256         // key 2 is reserved as the marker for core
257         // Odd keys are assigned by the driver, even keys by the daemon
258         static int key = 4;
259
260         const int ret = key;
261         key += 2;
262         return ret;
263 }
264
265 int pipe_cloexec(int pipefd[2]) {
266         if (pipe(pipefd) != 0) {
267                 return -1;
268         }
269
270         int fdf;
271         if (((fdf = fcntl(pipefd[0], F_GETFD)) == -1) || (fcntl(pipefd[0], F_SETFD, fdf | FD_CLOEXEC) != 0) ||
272                         ((fdf = fcntl(pipefd[1], F_GETFD)) == -1) || (fcntl(pipefd[1], F_SETFD, fdf | FD_CLOEXEC) != 0)) {
273                 close(pipefd[0]);
274                 close(pipefd[1]);
275                 return -1;
276         }
277         return 0;
278 }
279
280 FILE *fopen_cloexec(const char *path, const char *mode) {
281         FILE *fh = fopen(path, mode);
282         if (fh == NULL) {
283                 return NULL;
284         }
285         int fd = fileno(fh);
286         int fdf = fcntl(fd, F_GETFD);
287         if ((fdf == -1) || (fcntl(fd, F_SETFD, fdf | FD_CLOEXEC) != 0)) {
288                 fclose(fh);
289                 return NULL;
290         }
291         return fh;
292 }