aboutsummaryrefslogtreecommitdiff
path: root/tools/gator/daemon/SessionData.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gator/daemon/SessionData.cpp')
-rw-r--r--tools/gator/daemon/SessionData.cpp261
1 files changed, 261 insertions, 0 deletions
diff --git a/tools/gator/daemon/SessionData.cpp b/tools/gator/daemon/SessionData.cpp
new file mode 100644
index 000000000000..0e65d7842647
--- /dev/null
+++ b/tools/gator/daemon/SessionData.cpp
@@ -0,0 +1,261 @@
+/**
+ * Copyright (C) ARM Limited 2010-2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "SessionData.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "CPUFreqDriver.h"
+#include "DiskIODriver.h"
+#include "FSDriver.h"
+#include "HwmonDriver.h"
+#include "Logging.h"
+#include "MemInfoDriver.h"
+#include "NetDriver.h"
+#include "SessionXML.h"
+
+#define CORE_NAME_UNKNOWN "unknown"
+
+SessionData* gSessionData = NULL;
+
+SessionData::SessionData() {
+ usDrivers[0] = new HwmonDriver();
+ usDrivers[1] = new FSDriver();
+ usDrivers[2] = new MemInfoDriver();
+ usDrivers[3] = new NetDriver();
+ usDrivers[4] = new CPUFreqDriver();
+ usDrivers[5] = new DiskIODriver();
+ initialize();
+}
+
+SessionData::~SessionData() {
+}
+
+void SessionData::initialize() {
+ mWaitingOnCommand = false;
+ mSessionIsActive = false;
+ mLocalCapture = false;
+ mOneShot = false;
+ mSentSummary = false;
+ mAllowCommands = false;
+ const size_t cpuIdSize = sizeof(int)*NR_CPUS;
+ // Share mCpuIds across all instances of gatord
+ mCpuIds = (int *)mmap(NULL, cpuIdSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (mCpuIds == MAP_FAILED) {
+ logg->logError(__FILE__, __LINE__, "Unable to mmap shared memory for cpuids");
+ handleException();
+ }
+ memset(mCpuIds, -1, cpuIdSize);
+ strcpy(mCoreName, CORE_NAME_UNKNOWN);
+ readModel();
+ readCpuInfo();
+ mImages = NULL;
+ mConfigurationXMLPath = NULL;
+ mSessionXMLPath = NULL;
+ mEventsXMLPath = NULL;
+ mTargetPath = NULL;
+ mAPCDir = NULL;
+ mCaptureWorkingDir = NULL;
+ mCaptureCommand = NULL;
+ mCaptureUser = NULL;
+ mSampleRate = 0;
+ mLiveRate = 0;
+ mDuration = 0;
+ mMonotonicStarted = -1;
+ mBacktraceDepth = 0;
+ mTotalBufferSize = 0;
+ // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
+ mCores = 1;
+ mPageSize = 0;
+}
+
+void SessionData::parseSessionXML(char* xmlString) {
+ SessionXML session(xmlString);
+ session.parse();
+
+ // Set session data values - use prime numbers just below the desired value to reduce the chance of events firing at the same time
+ if (strcmp(session.parameters.sample_rate, "high") == 0) {
+ mSampleRate = 9973; // 10000
+ } else if (strcmp(session.parameters.sample_rate, "normal") == 0) {
+ mSampleRate = 997; // 1000
+ } else if (strcmp(session.parameters.sample_rate, "low") == 0) {
+ mSampleRate = 97; // 100
+ } else if (strcmp(session.parameters.sample_rate, "none") == 0) {
+ mSampleRate = 0;
+ } else {
+ logg->logError(__FILE__, __LINE__, "Invalid sample rate (%s) in session xml.", session.parameters.sample_rate);
+ handleException();
+ }
+ mBacktraceDepth = session.parameters.call_stack_unwinding == true ? 128 : 0;
+
+ // Determine buffer size (in MB) based on buffer mode
+ mOneShot = true;
+ if (strcmp(session.parameters.buffer_mode, "streaming") == 0) {
+ mOneShot = false;
+ mTotalBufferSize = 1;
+ } else if (strcmp(session.parameters.buffer_mode, "small") == 0) {
+ mTotalBufferSize = 1;
+ } else if (strcmp(session.parameters.buffer_mode, "normal") == 0) {
+ mTotalBufferSize = 4;
+ } else if (strcmp(session.parameters.buffer_mode, "large") == 0) {
+ mTotalBufferSize = 16;
+ } else {
+ logg->logError(__FILE__, __LINE__, "Invalid value for buffer mode in session xml.");
+ handleException();
+ }
+
+ // Convert milli- to nanoseconds
+ mLiveRate = session.parameters.live_rate * (int64_t)1000000;
+ if (mLiveRate > 0 && mLocalCapture) {
+ logg->logMessage("Local capture is not compatable with live, disabling live");
+ mLiveRate = 0;
+ }
+
+ if (!mAllowCommands && (mCaptureCommand != NULL)) {
+ logg->logError(__FILE__, __LINE__, "Running a command during a capture is not currently allowed. Please restart gatord with the -a flag.");
+ handleException();
+ }
+}
+
+void SessionData::readModel() {
+ FILE *fh = fopen("/proc/device-tree/model", "rb");
+ if (fh == NULL) {
+ return;
+ }
+
+ char buf[256];
+ if (fgets(buf, sizeof(buf), fh) != NULL) {
+ strcpy(mCoreName, buf);
+ }
+
+ fclose(fh);
+}
+
+void SessionData::readCpuInfo() {
+ char temp[256]; // arbitrarily large amount
+ mMaxCpuId = -1;
+
+ FILE *f = fopen("/proc/cpuinfo", "r");
+ if (f == NULL) {
+ logg->logMessage("Error opening /proc/cpuinfo\n"
+ "The core name in the captured xml file will be 'unknown'.");
+ return;
+ }
+
+ bool foundCoreName = false;
+ int processor = -1;
+ while (fgets(temp, sizeof(temp), f)) {
+ const size_t len = strlen(temp);
+
+ if (len == 1) {
+ // 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.
+ processor = -1;
+ continue;
+ }
+
+ if (len > 0) {
+ // Replace the line feed with a null
+ temp[len - 1] = '\0';
+ }
+
+ const bool foundHardware = strstr(temp, "Hardware") != 0;
+ const bool foundCPUPart = strstr(temp, "CPU part") != 0;
+ const bool foundProcessor = strstr(temp, "processor") != 0;
+ if (foundHardware || foundCPUPart || foundProcessor) {
+ char* position = strchr(temp, ':');
+ if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
+ logg->logMessage("Unknown format of /proc/cpuinfo\n"
+ "The core name in the captured xml file will be 'unknown'.");
+ return;
+ }
+ position += 2;
+
+ if (foundHardware && (strcmp(mCoreName, CORE_NAME_UNKNOWN) == 0)) {
+ strncpy(mCoreName, position, sizeof(mCoreName));
+ mCoreName[sizeof(mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string
+ foundCoreName = true;
+ }
+
+ if (foundCPUPart) {
+ const int cpuId = strtol(position, NULL, 0);
+ // 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
+ if (cpuId > mMaxCpuId) {
+ mMaxCpuId = cpuId;
+ }
+ if (processor >= NR_CPUS) {
+ logg->logMessage("Too many processors, please increase NR_CPUS");
+ } else if (processor >= 0) {
+ mCpuIds[processor] = cpuId;
+ }
+ }
+
+ if (foundProcessor) {
+ processor = strtol(position, NULL, 0);
+ }
+ }
+ }
+
+ if (!foundCoreName) {
+ logg->logMessage("Could not determine core name from /proc/cpuinfo\n"
+ "The core name in the captured xml file will be 'unknown'.");
+ }
+ fclose(f);
+}
+
+uint64_t getTime() {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
+ logg->logError(__FILE__, __LINE__, "Failed to get uptime");
+ handleException();
+ }
+ return (NS_PER_S*ts.tv_sec + ts.tv_nsec);
+}
+
+int getEventKey() {
+ // key 0 is reserved as a timestamp
+ // key 1 is reserved as the marker for thread specific counters
+ // key 2 is reserved as the marker for core
+ // Odd keys are assigned by the driver, even keys by the daemon
+ static int key = 4;
+
+ const int ret = key;
+ key += 2;
+ return ret;
+}
+
+int pipe_cloexec(int pipefd[2]) {
+ if (pipe(pipefd) != 0) {
+ return -1;
+ }
+
+ int fdf;
+ if (((fdf = fcntl(pipefd[0], F_GETFD)) == -1) || (fcntl(pipefd[0], F_SETFD, fdf | FD_CLOEXEC) != 0) ||
+ ((fdf = fcntl(pipefd[1], F_GETFD)) == -1) || (fcntl(pipefd[1], F_SETFD, fdf | FD_CLOEXEC) != 0)) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return -1;
+ }
+ return 0;
+}
+
+FILE *fopen_cloexec(const char *path, const char *mode) {
+ FILE *fh = fopen(path, mode);
+ if (fh == NULL) {
+ return NULL;
+ }
+ int fd = fileno(fh);
+ int fdf = fcntl(fd, F_GETFD);
+ if ((fdf == -1) || (fcntl(fd, F_SETFD, fdf | FD_CLOEXEC) != 0)) {
+ fclose(fh);
+ return NULL;
+ }
+ return fh;
+}