2 * Copyright (C) ARM Limited 2010-2015. All rights reserved.
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.
9 #include "SessionData.h"
16 #include "DiskIODriver.h"
18 #include "HwmonDriver.h"
20 #include "MemInfoDriver.h"
21 #include "NetDriver.h"
22 #include "SessionXML.h"
24 #define CORE_NAME_UNKNOWN "unknown"
26 SessionData* gSessionData = NULL;
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();
37 SessionData::~SessionData() {
40 void SessionData::initialize() {
41 mWaitingOnCommand = false;
42 mSessionIsActive = false;
43 mLocalCapture = 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");
54 memset(mCpuIds, -1, cpuIdSize);
55 strcpy(mCoreName, CORE_NAME_UNKNOWN);
59 mConfigurationXMLPath = NULL;
60 mSessionXMLPath = NULL;
61 mEventsXMLPath = NULL;
62 mEventsXMLAppend = NULL;
65 mCaptureWorkingDir = NULL;
66 mCaptureCommand = NULL;
71 mMonotonicStarted = -1;
74 // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
80 void SessionData::parseSessionXML(char* xmlString) {
81 SessionXML session(xmlString);
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) {
94 logg->logError("Invalid sample rate (%s) in session xml.", session.parameters.sample_rate);
97 mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0;
99 // Determine buffer size (in MB) based on buffer mode
101 if (strcmp(session.parameters.buffer_mode, "streaming") == 0) {
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;
111 logg->logError("Invalid value for buffer mode in session xml.");
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");
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.");
128 void SessionData::readModel() {
129 FILE *fh = fopen("/proc/device-tree/model", "rb");
135 if (fgets(buf, sizeof(buf), fh) != NULL) {
136 strcpy(mCoreName, buf);
142 static void setImplementer(int &cpuId, const int implementer) {
146 cpuId |= implementer << 12;
149 static void setPart(int &cpuId, const int part) {
156 void SessionData::readCpuInfo() {
157 char temp[256]; // arbitrarily large amount
160 FILE *f = fopen("/proc/cpuinfo", "r");
162 logg->logMessage("Error opening /proc/cpuinfo\n"
163 "The core name in the captured xml file will be 'unknown'.");
167 bool foundCoreName = (strcmp(mCoreName, CORE_NAME_UNKNOWN) != 0);
169 while (fgets(temp, sizeof(temp), f)) {
170 const size_t len = strlen(temp);
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.
179 // Replace the line feed with a null
180 temp[len - 1] = '\0';
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'.");
197 strncpy(mCoreName, position, sizeof(mCoreName));
198 mCoreName[sizeof(mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
199 foundCoreName = true;
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);
209 setImplementer(mMaxCpuId, implementer);
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);
220 setPart(mMaxCpuId, cpuId);
224 if (foundProcessor) {
225 processor = strtol(position, NULL, 0);
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];
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'.");
246 if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
247 logg->logError("Failed to get uptime");
250 return (NS_PER_S*ts.tv_sec + ts.tv_nsec);
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
265 int pipe_cloexec(int pipefd[2]) {
266 if (pipe(pipefd) != 0) {
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)) {
280 FILE *fopen_cloexec(const char *path, const char *mode) {
281 FILE *fh = fopen(path, mode);
286 int fdf = fcntl(fd, F_GETFD);
287 if ((fdf == -1) || (fcntl(fd, F_SETFD, fdf | FD_CLOEXEC) != 0)) {