diff options
Diffstat (limited to 'tools/gator/daemon/SessionData.cpp')
-rw-r--r-- | tools/gator/daemon/SessionData.cpp | 261 |
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; +} |