From 689b7539711ab098911503808cc3e24307d9bcf7 Mon Sep 17 00:00:00 2001 From: Drew Richardson Date: Tue, 29 Nov 2011 12:00:00 -0800 Subject: gator: Version 5.8 Signed-off-by: Drew Richardson --- README_Streamline.txt | 27 +++++--- daemon/Android.mk | 6 +- daemon/CapturedXML.cpp | 8 +-- daemon/Child.cpp | 7 +- daemon/Collector.cpp | 36 ++++++----- daemon/ConfigurationXML.cpp | 11 ++-- daemon/Fifo.cpp | 1 - daemon/Fifo.h | 4 +- daemon/HashMap.cpp | 64 ------------------- daemon/HashMap.h | 34 ---------- daemon/LocalCapture.cpp | 55 +++++++++------- daemon/LocalCapture.h | 2 +- daemon/Logging.cpp | 1 - daemon/Logging.h | 15 +++-- daemon/Makefile | 2 +- daemon/OlySocket.cpp | 13 ++-- daemon/OlySocket.h | 2 +- daemon/OlyUtility.cpp | 9 +-- daemon/ReadSession.cpp | 118 ---------------------------------- daemon/ReadSession.h | 40 ------------ daemon/RequestXML.cpp | 1 - daemon/Sender.cpp | 11 +++- daemon/Sender.h | 2 + daemon/SessionData.cpp | 5 +- daemon/SessionData.h | 2 +- daemon/SessionXML.cpp | 119 ++++++++++++++++++++++++++++++++++ daemon/SessionXML.h | 40 ++++++++++++ daemon/StreamlineSetup.cpp | 24 +++---- daemon/XMLOut.cpp | 3 +- daemon/XMLOut.h | 4 +- daemon/XMLReader.cpp | 7 +- daemon/main.cpp | 75 +++++++++++++++++----- driver/Makefile | 8 +++ driver/gator_annotate.c | 49 ++++++++------ driver/gator_annotate_kernel.c | 91 ++++++++++++++++++++++++++ driver/gator_backtrace.c | 50 ++++++++++++++- driver/gator_cookies.c | 16 +++-- driver/gator_ebs.c | 35 +++++++--- driver/gator_events_armv7.c | 1 + driver/gator_main.c | 91 ++++++++++++++++---------- driver/gator_trace_sched.c | 141 +++++++++++++++++++++++++++-------------- 41 files changed, 725 insertions(+), 505 deletions(-) delete mode 100644 daemon/HashMap.cpp delete mode 100644 daemon/HashMap.h delete mode 100644 daemon/ReadSession.cpp delete mode 100644 daemon/ReadSession.h create mode 100644 daemon/SessionXML.cpp create mode 100644 daemon/SessionXML.h create mode 100644 driver/gator_annotate_kernel.c diff --git a/README_Streamline.txt b/README_Streamline.txt index 51f8e24..f9edf11 100644 --- a/README_Streamline.txt +++ b/README_Streamline.txt @@ -48,7 +48,7 @@ make -j5 ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- uImag *** Building the gator module *** To create the gator.ko module, - cd /ds-5-install-directory/arm/gator/driver-src + cd /path/to/gator/driver-src tar xzf gator-driver.tar.gz cd gator-driver make -C M=`pwd` ARCH=arm CROSS_COMPILE=<...> modules @@ -56,23 +56,34 @@ for example make -C /home/username/kernel_2.6.32/ M=`pwd` ARCH=arm CROSS_COMPILE=/home/username/CodeSourcery/Sourcery_G++_Lite/bin/arm-none-linux-gnueabi- modules If successful, a gator.ko module should be generated -*** Compiling an application or shared library *** +*** Building the gator daemon *** -Recommended compiler settings: - "-g": Debug symbols needed for best analysis results. - "-fno-inline": Speed improvement when processing the image files and most accurate analysis results. - "-fno-omit-frame-pointer": ARM EABI frame pointers (Code Sourcery cross compiler) allow the call stack to be recorded with each sample taken when in ARM state (i.e. not -mthumb). +cd /path/to/gator/daemon-src +tar -xzf gator-daemon.tar.gz +For Linux, + build with 'make' +For Android, + mv gator-daemon jni + install the android ndk, see developer.android.com + /path/to/ndk/ndk-build + gatord should now be created and located in libs/armeabi *** Running gator *** Load the kernel onto the target and copy gatord and gator.ko into the target's filesystem. -gatord is located in /arm/gator/linux or /arm/gator/android or can be built from source. Ensure gatord has execute permissions chmod +x gatord gator.ko must be located in the same directory as gatord on the target. With root privileges, run the daemon sudo ./gatord & +*** Compiling an application or shared library *** + +Recommended compiler settings: + "-g": Debug symbols needed for best analysis results. + "-fno-inline": Speed improvement when processing the image files and most accurate analysis results. + "-fno-omit-frame-pointer": ARM EABI frame pointers (Code Sourcery cross compiler) allow the call stack to be recorded with each sample taken when in ARM state (i.e. not -mthumb). + *** Profiling the kernel (optional) *** make ARCH=arm CROSS_COMPILE=$(CROSS_TOOLS}/bin/arm-none-linux-gnueabi- menuconfig @@ -82,7 +93,7 @@ make ARCH=arm CROSS_COMPILE=$(CROSS_TOOLS}/bin/arm-none-linux-gnueabi- menuconfi make -j5 ARCH=arm CROSS_COMPILE=${CROSS_TOOLS}/bin/arm-none-linux-gnueabi- uImage Use vmlinux as the image for debug symbols in Streamline. Drivers may be profiled using this method by statically linking the driver into the kernel image or adding the module as an image. -Note that the gator driver does not perform kernel call stack recording. +To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko. *** Automatically start gator on boot (optional) *** diff --git a/daemon/Android.mk b/daemon/Android.mk index 45f5b7d..ac3094c 100644 --- a/daemon/Android.mk +++ b/daemon/Android.mk @@ -1,6 +1,8 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +$(shell cd $(LOCAL_PATH);cat events_header.xml events-*\.xml events_footer.xml > events.xml;xxd -i events.xml > events_xml.h;xxd -i configuration.xml > configuration_xml.h) + LOCAL_CFLAGS += -Wall -O3 -ftree-vectorize LOCAL_SRC_FILES:= \ @@ -9,16 +11,15 @@ LOCAL_SRC_FILES:= \ Collector.cpp \ ConfigurationXML.cpp \ Fifo.cpp \ - HashMap.cpp \ LocalCapture.cpp \ Logging.cpp \ main.cpp \ OlySocket.cpp \ OlyUtility.cpp \ - ReadSession.cpp \ RequestXML.cpp \ Sender.cpp \ SessionData.cpp \ + SessionXML.cpp \ StreamlineSetup.cpp \ XMLOut.cpp \ XMLReader.cpp @@ -26,6 +27,7 @@ LOCAL_SRC_FILES:= \ LOCAL_C_INCLUDES := $(LOCAL_PATH) LOCAL_MODULE:= gatord +LOCAL_MODULE_TAGS:= optional LOCAL_LDLIBS := -lz -llog diff --git a/daemon/CapturedXML.cpp b/daemon/CapturedXML.cpp index 9d9fd84..5d1f295 100644 --- a/daemon/CapturedXML.cpp +++ b/daemon/CapturedXML.cpp @@ -6,8 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; -typedef long long int64_t; #include #include #include @@ -83,10 +81,10 @@ const char* CapturedXML::getXML() { } void CapturedXML::write(char* path) { - char file[PATH_MAX]; + char* file = (char*)malloc(PATH_MAX); // Set full path - snprintf(file, sizeof(file), "%s/captured.xml", path); + snprintf(file, PATH_MAX, "%s/captured.xml", path); // Write the file const char* xml = getXML(); @@ -94,4 +92,6 @@ void CapturedXML::write(char* path) { logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); handleException(); } + + free(file); } diff --git a/daemon/Child.cpp b/daemon/Child.cpp index 0abfd1a..6cfbe60 100644 --- a/daemon/Child.cpp +++ b/daemon/Child.cpp @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #include #include @@ -182,7 +181,6 @@ void Child::endSession() { gSessionData.mSessionIsActive = false; collector->stop(); sem_post(&haltPipeline); - sem_post(&haltPipeline); } void Child::run() { @@ -192,7 +190,7 @@ void Child::run() { prctl(PR_SET_NAME, (unsigned int)&"gatord-child", 0, 0, 0); - // Instantiate the Sender - must be done first, afterwhich error messages can be sent + // Instantiate the Sender - must be done first, after which error messages can be sent sender = new Sender(socket); if (numConnections > 1) { @@ -223,8 +221,7 @@ void Child::run() { delete xmlString; } - // Create user-space buffers to pass the driver data to the socket driver - // Could optimize by using a zero-copy pipe/splice to copy directly from the gator driver to the socket buffer + // Create user-space buffers int fifoBufferSize = collector->getBufferSize(); int numCollectorBuffers = (gSessionData.mTotalBufferSize * 1024 * 1024 + fifoBufferSize - 1) / fifoBufferSize; numCollectorBuffers = (numCollectorBuffers < 4) ? 4 : numCollectorBuffers; diff --git a/daemon/Collector.cpp b/daemon/Collector.cpp index c413347..18f6dee 100644 --- a/daemon/Collector.cpp +++ b/daemon/Collector.cpp @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #include #include @@ -27,19 +26,20 @@ Collector::Collector() { checkVersion(); + int enable = -1; + if (readIntDriver("enable", &enable) != 0 || enable != 0) { + logg->logError(__FILE__, __LINE__, "Driver already enabled, possibly a session is already in progress."); + handleException(); + } + readIntDriver("cpu_cores", &gSessionData.mCores); if (gSessionData.mCores == 0) { gSessionData.mCores = 1; } - if (writeDriver("buffer_size", 256*1024)) { - logg->logError(__FILE__, __LINE__, "Unable to set the cpu buffer settings"); - handleException(); - } - - readIntDriver("buffer_size", &bufferSize); - if (bufferSize <= 0) { - logg->logError(__FILE__, __LINE__, "bufferSize %d is invalid", bufferSize); + bufferSize = 512 * 1024; + if (writeReadDriver("buffer_size", &bufferSize) || bufferSize <= 0) { + logg->logError(__FILE__, __LINE__, "Unable to set the driver buffer size"); handleException(); } @@ -60,9 +60,10 @@ Collector::~Collector() { } void Collector::enablePerfCounters() { + char base[sizeof(gSessionData.mPerfCounterType[0]) + 10]; // sufficiently large to hold all events/ + char text[sizeof(gSessionData.mPerfCounterType[0]) + 20]; // sufficiently large to hold all events// + for (int i=0; ilogError(__FILE__, __LINE__, "Unable to set streaming"); @@ -176,8 +177,8 @@ int Collector::collect(char* buffer) { } void Collector::getCoreName() { - char temp[256]; - strncpy(gSessionData.mCoreName, "unknown", sizeof(gSessionData.mCoreName)); + char temp[256]; // arbitrarily large amount + strcpy(gSessionData.mCoreName, "unknown"); FILE* f = fopen("/proc/cpuinfo", "r"); if (f == NULL) { @@ -198,6 +199,7 @@ void Collector::getCoreName() { return; } strncpy(gSessionData.mCoreName, (char *)((int)position + 2), sizeof(gSessionData.mCoreName)); + gSessionData.mCoreName[sizeof(gSessionData.mCoreName) - 1] = 0; // strncpy does not guarantee a null-terminated string fclose(f); return; } @@ -209,7 +211,7 @@ void Collector::getCoreName() { } char* Collector::resolvePath(const char* file) { - static char fullpath[128]; + static char fullpath[100]; // Sufficiently large to hold any path within /dev/gator snprintf(fullpath, sizeof(fullpath), "/dev/gator/%s", file); return fullpath; } @@ -222,7 +224,7 @@ int Collector::readIntDriver(const char* path, int* value) { } if (fscanf(file, "%u", value) != 1) { fclose(file); - logg->logMessage(__FILE__, __LINE__, "Invalid value in file %s", fullpath); + logg->logMessage("Invalid value in file %s", fullpath); return -1; } fclose(file); @@ -230,7 +232,7 @@ int Collector::readIntDriver(const char* path, int* value) { } int Collector::writeDriver(const char* path, int value) { - char data[40]; + char data[40]; // Sufficiently large to hold any integer snprintf(data, sizeof(data), "%d", value); return writeDriver(path, data); } diff --git a/daemon/ConfigurationXML.cpp b/daemon/ConfigurationXML.cpp index 365d422..6348818 100644 --- a/daemon/ConfigurationXML.cpp +++ b/daemon/ConfigurationXML.cpp @@ -6,8 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; -typedef long long int64_t; #include #include #include @@ -33,14 +31,14 @@ static const char* ATTR_DESCRIPTION = "description"; static const char* ATTR_EBS = "event_based_sampling"; ConfigurationXML::ConfigurationXML() { -#include "configuration_xml.h" - char path[PATH_MAX]; +#include "configuration_xml.h" // defines and initializes char configuration_xml[] and int configuration_xml_len index = 0; + char* path = (char *)malloc(PATH_MAX); - if (util->getApplicationFullPath(path, sizeof(path)) != 0) { + if (util->getApplicationFullPath(path, PATH_MAX) != 0) { logg->logMessage("Unable to determine the full path of gatord, the cwd will be used"); } - strcat(path, "configuration.xml"); + strncat(path, "configuration.xml", PATH_MAX - strlen(path) - 1); mConfigurationXML = util->readFromDisk(path); if (mConfigurationXML == NULL) { @@ -66,6 +64,7 @@ ConfigurationXML::ConfigurationXML() { } collector->enablePerfCounters(); + free(path); } ConfigurationXML::~ConfigurationXML() { diff --git a/daemon/Fifo.cpp b/daemon/Fifo.cpp index bbc43a7..6ffebba 100644 --- a/daemon/Fifo.cpp +++ b/daemon/Fifo.cpp @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #include #include diff --git a/daemon/Fifo.h b/daemon/Fifo.h index 02372d5..14688a9 100644 --- a/daemon/Fifo.h +++ b/daemon/Fifo.h @@ -11,8 +11,8 @@ #include -// Driver buffer size is 512k, large buffer mode with 2GB of total RAM will allocate 256M -#define FIFO_BUFFER_LIMIT 256*1024/512 +// Number of buffers allowed with large buffer mode +#define FIFO_BUFFER_LIMIT 64 class Fifo { public: diff --git a/daemon/HashMap.cpp b/daemon/HashMap.cpp deleted file mode 100644 index 1ff6e31..0000000 --- a/daemon/HashMap.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (C) ARM Limited 2010-2011. 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 -#include "HashMap.h" - -/* - * LRU Lossy HashMap - * Values are always inserted to first slot - * Value hits are moved to the first slot - */ - -HashMap::HashMap() { - history = (int*)calloc(HASHMAP_ENTRIES * MAX_COLLISIONS, sizeof(int)); -} - -HashMap::~HashMap() { - free(history); -} - -int *HashMap::hashEntries(int value) { - int hashCode = (value >> 24) & 0xff; - hashCode = hashCode * 31 + ((value >> 16) & 0xff); - hashCode = hashCode * 31 + ((value >> 8) & 0xff); - hashCode = hashCode * 31 + ((value >> 0) & 0xff); - hashCode &= (HASHMAP_ENTRIES-1); - return &history[hashCode * MAX_COLLISIONS]; -} - -/* - * Exists - * Pre: [0][1][v][3]..[n-1] - * Post: [v][0][1][3]..[n-1] - * Add - * Pre: [0][1][2][3]..[n-1] - * Post: [v][0][1][2]..[n-2] - */ -bool HashMap::existsAdd(int value) { - int *line = hashEntries(value); - - /* exists */ - for (int x = 0; x < MAX_COLLISIONS; x++) { - if (line[x] == value) { - for (; x > 0; x--) { - line[x] = line[x-1]; - } - line[0] = value; - return true; - } - } - - /* add */ - for (int x = MAX_COLLISIONS-1; x > 0; x--) { - line[x] = line[x-1]; - } - line[0] = value; - - return false; -} diff --git a/daemon/HashMap.h b/daemon/HashMap.h deleted file mode 100644 index 3831f03..0000000 --- a/daemon/HashMap.h +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (C) ARM Limited 2010-2011. 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. - */ - - -#ifndef __HASH_MAP_H__ -#define __HASH_MAP_H__ - -/********************************** -This class is a limited and lossy hash map, where each hash table bucket will contain at most MAX_COLLISIONS entries -If the limit is exceeded, one of the old entries is dropped from the table -This limit eliminates the need for dynamic memory allocation -It is efficient with a data set containing a lot of use-only-once data -Zero is used as an invalid (unused) hash entry value -**********************************/ - -#define HASHMAP_ENTRIES 1024 /* must be power of 2 */ -#define MAX_COLLISIONS 2 - -class HashMap { -public: - HashMap(); - ~HashMap(); - bool existsAdd(int value); -private: - int *hashEntries(int key); - int *history; -}; - -#endif //__HASH_MAP_H__ diff --git a/daemon/LocalCapture.cpp b/daemon/LocalCapture.cpp index 9927035..510a6c3 100644 --- a/daemon/LocalCapture.cpp +++ b/daemon/LocalCapture.cpp @@ -6,8 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; -typedef long long int64_t; #include #include #include @@ -34,56 +32,60 @@ void LocalCapture::createAPCDirectory(char* target_path, char* name) { } void LocalCapture::write(char* string) { - char file[PATH_MAX]; + char* file = (char*)malloc(PATH_MAX); // Set full path - snprintf(file, sizeof(file), "%s/session.xml", gSessionData.apcDir); + snprintf(file, PATH_MAX, "%s/session.xml", gSessionData.apcDir); // Write the file if (util->writeToDisk(file, string) < 0) { logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); handleException(); } + + free(file); } char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* ending, char* title) { int i; - char path[PATH_MAX]; + char* output; + char* path = (char*)malloc(PATH_MAX); // Ensure the path is an absolute path, i.e. starts with a slash if (initialPath == 0 || strlen(initialPath) == 0) { - if (getcwd(path, sizeof(path)) == 0) + if (getcwd(path, PATH_MAX) == 0) logg->logMessage("Unable to retrive the current working directory"); - strncat(path, "/@F_@N", sizeof(path) - strlen(path) - 1); + strncat(path, "/@F_@N", PATH_MAX - strlen(path) - 1); } else if (initialPath[0] != '/') { - if (getcwd(path, sizeof(path)) == 0) + if (getcwd(path, PATH_MAX) == 0) logg->logMessage("Unable to retrive the current working directory"); - strncat(path, "/", sizeof(path) - strlen(path) - 1); - strncat(path, initialPath, sizeof(path) - strlen(path) - 1); + strncat(path, "/", PATH_MAX - strlen(path) - 1); + strncat(path, initialPath, PATH_MAX - strlen(path) - 1); } else { - strncpy(path, initialPath, sizeof(path)); + strncpy(path, initialPath, PATH_MAX); + path[PATH_MAX - 1] = 0; // strncpy does not guarantee a null-terminated string } // Convert to uppercase - replaceAll(path, "@f", "@F", sizeof(path)); - replaceAll(path, "@n", "@N", sizeof(path)); + replaceAll(path, "@f", "@F", PATH_MAX); + replaceAll(path, "@n", "@N", PATH_MAX); // Replace @F with the session xml title - replaceAll(path, "@F", title, sizeof(path)); + replaceAll(path, "@F", title, PATH_MAX); // Add ending if it is not already there if (strcmp(&path[strlen(path) - strlen(ending)], ending) != 0) { - strncat(path, ending, sizeof(path) - strlen(path) - 1); + strncat(path, ending, PATH_MAX - strlen(path) - 1); } // Replace @N with a unique integer if (strstr(path, "@N")) { - char tempPath[PATH_MAX]; + char* tempPath = (char*)malloc(PATH_MAX); for (i = 1; i < 1000; i++) { char number[4]; snprintf(number, sizeof(number), "%03d", i); - strncpy(tempPath, path, sizeof(tempPath)); - replaceAll(tempPath, "@N", number, sizeof(tempPath)); + strcpy(tempPath, path); + replaceAll(tempPath, "@N", number, PATH_MAX); struct stat mFileInfo; if (stat(tempPath, &mFileInfo) != 0) { // if the direcotry does not exist, break @@ -96,10 +98,13 @@ char* LocalCapture::createUniqueDirectory(const char* initialPath, const char* e handleException(); } - strncpy(path, tempPath, sizeof(path)); + output = strdup(tempPath); + free(tempPath); + } else { + output = strdup(path); } - char* output = strdup(path); + free(path); return output; } @@ -184,13 +189,14 @@ int LocalCapture::removeDirAndAllContents(char *path) { } void LocalCapture::copyImages(ImageLinkList* ptr) { - char dstfilename[PATH_MAX]; + char* dstfilename = (char*)malloc(PATH_MAX); while (ptr) { - strncpy(dstfilename, gSessionData.apcDir, sizeof(dstfilename)); + strncpy(dstfilename, gSessionData.apcDir, PATH_MAX); + dstfilename[PATH_MAX - 1] = 0; // strncpy does not guarantee a null-terminated string if (gSessionData.apcDir[strlen(gSessionData.apcDir) - 1] != '/') - strncat(dstfilename, "/", sizeof(dstfilename)); - strncat(dstfilename, util->getFilePart(ptr->path), sizeof(dstfilename) - strlen(dstfilename) - 1); + strncat(dstfilename, "/", PATH_MAX - strlen(dstfilename) - 1); + strncat(dstfilename, util->getFilePart(ptr->path), PATH_MAX - strlen(dstfilename) - 1); if (util->copyFile(ptr->path, dstfilename)) logg->logMessage("copied file %s to %s", ptr->path, dstfilename); else @@ -198,4 +204,5 @@ void LocalCapture::copyImages(ImageLinkList* ptr) { ptr = ptr->next; } + free(dstfilename); } diff --git a/daemon/LocalCapture.h b/daemon/LocalCapture.h index f2db593..0bb6f94 100644 --- a/daemon/LocalCapture.h +++ b/daemon/LocalCapture.h @@ -9,7 +9,7 @@ #ifndef __LOCAL_CAPTURE_H__ #define __LOCAL_CAPTURE_H__ -#include "ReadSession.h" +#include "SessionXML.h" class LocalCapture { public: diff --git a/daemon/Logging.cpp b/daemon/Logging.cpp index 972a83f..d34209c 100644 --- a/daemon/Logging.cpp +++ b/daemon/Logging.cpp @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #include #include diff --git a/daemon/Logging.h b/daemon/Logging.h index 4579f7c..cd8d7cd 100644 --- a/daemon/Logging.h +++ b/daemon/Logging.h @@ -9,13 +9,16 @@ #ifndef __LOGGING_H__ #define __LOGGING_H__ +#include +#include +#include #ifdef WIN32 #include +#define GATOR_PATH_MAX MAX_PATH #else #include +#define GATOR_PATH_MAX PATH_MAX #endif -#include -#include #define DRIVER_ERROR "\n Driver issue:\n >> gator.ko must be built against the current kernel version & configuration\n >> gator.ko should be co-located with gatord in the same directory\n >> OR insmod gator.ko prior to launching gatord" @@ -25,14 +28,14 @@ public: ~Logging(); void logError(const char* file, int line, const char* fmt, ...); void logMessage(const char* fmt, ...); - void SetWarningFile(char* path) {strncpy(mWarningXMLPath, path, sizeof(mWarningXMLPath) - 1);} + void SetWarningFile(char* path) {strncpy(mWarningXMLPath, path, GATOR_PATH_MAX); mWarningXMLPath[GATOR_PATH_MAX - 1] = 0;} char* getLastError() {return mErrBuf;} char* getLastMessage() {return mLogBuf;} private: - char mWarningXMLPath[4096]; - char mErrBuf[4096]; - char mLogBuf[4096]; + char mWarningXMLPath[GATOR_PATH_MAX]; + char mErrBuf[4096]; // Arbitrarily large buffer to hold a string + char mLogBuf[4096]; // Arbitrarily large buffer to hold a string bool mDebug; bool mFileCreated; #ifdef WIN32 diff --git a/daemon/Makefile b/daemon/Makefile index 2ccc886..2a41e31 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -29,7 +29,7 @@ all: $(TARGET) $(CPP) $(INCLUDES) -c $(CFLAGS) -o $@ $< $(TARGET): convert $(TGT_OBJS) - $(CPP) -s -o $@ $(TGT_OBJS) -lc -lrt + $(CPP) -s -o $@ $(TGT_OBJS) -lc -lrt -lpthread rm events_xml.h configuration_xml.h convert: diff --git a/daemon/OlySocket.cpp b/daemon/OlySocket.cpp index d95210c..9b031dc 100644 --- a/daemon/OlySocket.cpp +++ b/daemon/OlySocket.cpp @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #ifdef WIN32 #include @@ -46,11 +45,10 @@ OlySocket::OlySocket(int port, bool multiple) { } } -// Implement client socket for windows -/*OlySocket::OlySocket(int port, char* host) { +OlySocket::OlySocket(int port, char* host) { fdServer = 0; createClientSocket(host, port); -}*/ +} OlySocket::~OlySocket() { if (mSocketID > 0) { @@ -79,9 +77,10 @@ void OlySocket::closeServerSocket() { fdServer = 0; } -// Implement for windows -/* void OlySocket::createClientSocket(char* hostname, int portno) { +#ifdef WIN32 + // TODO: Implement for Windows +#else char buf[32]; struct addrinfo hints, *res, *res0; @@ -113,8 +112,8 @@ void OlySocket::createClientSocket(char* hostname, int portno) { logg->logError(__FILE__, __LINE__, "Could not connect to client socket. Ensure ARM Streamline is running."); handleException(); } +#endif } -*/ void OlySocket::createSingleServerConnection(int port) { createServerSocket(port); diff --git a/daemon/OlySocket.h b/daemon/OlySocket.h index 5e110aa..9ba6ee8 100644 --- a/daemon/OlySocket.h +++ b/daemon/OlySocket.h @@ -30,7 +30,7 @@ public: private: char* strError; int mSocketID, fdServer; - // void createClientSocket(char* hostname, int port); + void createClientSocket(char* hostname, int port); void createSingleServerConnection(int port); void createServerSocket(int port); }; diff --git a/daemon/OlyUtility.cpp b/daemon/OlyUtility.cpp index 5c3bfcc..6216726 100644 --- a/daemon/OlyUtility.cpp +++ b/daemon/OlyUtility.cpp @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #include #include @@ -110,8 +109,9 @@ int OlyUtility::appendToDisk(const char* path, const char* data) { * The dstFile will be overwritten if it exists. * 0 is returned on an error; otherwise 1. */ +#define TRANSFER_SIZE 1024 int OlyUtility::copyFile(const char * srcFile, const char * dstFile) { - char buffer[1024]; + char* buffer = (char*)malloc(TRANSFER_SIZE); FILE * f_src = fopen(srcFile,"rb"); if (!f_src) { return 0; @@ -122,8 +122,8 @@ int OlyUtility::copyFile(const char * srcFile, const char * dstFile) { return 0; } while (!feof(f_src)) { - int num_bytes_read = fread(buffer, 1, sizeof(buffer), f_src); - if (num_bytes_read < (int)sizeof(buffer) && !feof(f_src)) { + int num_bytes_read = fread(buffer, 1, TRANSFER_SIZE, f_src); + if (num_bytes_read < TRANSFER_SIZE && !feof(f_src)) { fclose(f_src); fclose(f_dst); return 0; @@ -137,6 +137,7 @@ int OlyUtility::copyFile(const char * srcFile, const char * dstFile) { } fclose(f_src); fclose(f_dst); + free(buffer); return 1; } diff --git a/daemon/ReadSession.cpp b/daemon/ReadSession.cpp deleted file mode 100644 index 1aaf4d8..0000000 --- a/daemon/ReadSession.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Copyright (C) ARM Limited 2010-2011. 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. - */ - -typedef unsigned long long uint64_t; -#include -#include -#include -#include "ReadSession.h" -#include "Logging.h" - -extern void handleException(); - -static const char* TAG_SESSION = "session"; -static const char* TAG_IMAGE = "image"; - -static const char* ATTR_VERSION = "version"; -static const char* ATTR_TITLE = "title"; -static const char* ATTR_UUID = "uuid"; -static const char* ATTR_CALL_STACK_UNWINDING = "call_stack_unwinding"; -static const char* ATTR_BUFFER_MODE = "buffer_mode"; -static const char* ATTR_SAMPLE_RATE = "sample_rate"; -static const char* ATTR_TARGET_PATH = "target_path"; -static const char* ATTR_OUTPUT_PATH = "output_path"; -static const char* ATTR_DURATION = "duration"; -static const char* ATTR_PATH = "path"; - -ReadSession::ReadSession(const char * str) { - parameters.title = 0; - parameters.uuid[0] = 0; - parameters.target_path = 0; - parameters.output_path = 0; - parameters.buffer_mode[0] = 0; - parameters.sample_rate[0] = 0; - parameters.duration = 0; - parameters.call_stack_unwinding = false; - parameters.images = NULL; - mPath = 0; - mSessionXML = (char*)str; - logg->logMessage(mSessionXML); -} - -ReadSession::~ReadSession() { - if (mPath != 0) { - free(mSessionXML); - } -} - -void ReadSession::parse() { - XMLReader reader(mSessionXML); - char * tag = reader.nextTag(); - while(tag != 0) { - if (strcmp(tag, TAG_SESSION) == 0) { - sessionTag(&reader); - return; - } - tag = reader.nextTag(); - } - - logg->logError(__FILE__, __LINE__, "No session tag found in the session.xml file"); - handleException(); -} - -void ReadSession::sessionTag(XMLReader* in) { - char tempBuffer[PATH_MAX]; - int version = in->getAttributeAsInteger(ATTR_VERSION, 0); - if (version != 1) { - logg->logError(__FILE__, __LINE__, "Invalid session.xml version: %d", version); - handleException(); - } - - in->getAttribute(ATTR_TITLE, tempBuffer, sizeof(tempBuffer), "unnamed"); - parameters.title = strdup(tempBuffer); // freed when the child process exits - if (parameters.title == NULL) { - logg->logError(__FILE__, __LINE__, "failed to allocate parameters.title (%d bytes)", strlen(tempBuffer)); - handleException(); - } - in->getAttribute(ATTR_UUID, parameters.uuid, sizeof(parameters.uuid), ""); - parameters.duration = in->getAttributeAsInteger(ATTR_DURATION, 0); - parameters.call_stack_unwinding = in->getAttributeAsBoolean(ATTR_CALL_STACK_UNWINDING, true); - in->getAttribute(ATTR_BUFFER_MODE, parameters.buffer_mode, sizeof(parameters.buffer_mode), "normal"); - in->getAttribute(ATTR_SAMPLE_RATE, parameters.sample_rate, sizeof(parameters.sample_rate), ""); - in->getAttribute(ATTR_TARGET_PATH, tempBuffer, sizeof(tempBuffer), ""); - parameters.target_path = strdup(tempBuffer); // freed when the child process exits - if (parameters.target_path == NULL) { - logg->logError(__FILE__, __LINE__, "failed to allocate parameters.target_path (%d bytes)", strlen(tempBuffer)); - handleException(); - } - in->getAttribute(ATTR_OUTPUT_PATH, tempBuffer, sizeof(tempBuffer), ""); - parameters.output_path = strdup(tempBuffer); // freed when the child process exits - if (parameters.output_path == NULL) { - logg->logError(__FILE__, __LINE__, "failed to allocate parameters.output_path (%d bytes)", strlen(tempBuffer)); - handleException(); - } - - char * tag = in->nextTag(); - while(tag != 0) { - if (strcmp(tag, TAG_IMAGE) == 0) { - sessionImage(in); - } - tag = in->nextTag(); - } -} - -void ReadSession::sessionImage(XMLReader* in) { - int length = in->getAttributeLength(ATTR_PATH); - struct ImageLinkList *image; - - image = (struct ImageLinkList *)malloc(sizeof(struct ImageLinkList)); - image->path = (char *)malloc(length + 1); - in->getAttribute(ATTR_PATH, image->path, length + 1, ""); - image->next = parameters.images; - parameters.images = image; -} diff --git a/daemon/ReadSession.h b/daemon/ReadSession.h deleted file mode 100644 index b2e3eae..0000000 --- a/daemon/ReadSession.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (C) ARM Limited 2010-2011. 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. - */ - -#ifndef READ_SESSION_H -#define READ_SESSION_H - -#include "XMLReader.h" -#include "SessionData.h" - -struct ConfigParameters { - char* title; // status title - char uuid[64]; // universal unique identifier - char* target_path; // target path of where to write to disk - char* output_path; // host path of where to write to disk - char buffer_mode[64]; // buffer mode, "streaming", "low", "normal", "high" defines oneshot and buffer size - char sample_rate[64]; // capture mode, "high", "normal", or "low" - int duration; // length of profile in seconds - bool call_stack_unwinding; // whether stack unwinding is performed - struct ImageLinkList *images; // linked list of image strings -}; - -class ReadSession { -public: - ReadSession(const char * str); - ~ReadSession(); - void parse(); - ConfigParameters parameters; -private: - char* mSessionXML; - char* mPath; - void sessionTag(XMLReader* in); - void sessionImage(XMLReader* in); -}; - -#endif // READ_SESSION_H diff --git a/daemon/RequestXML.cpp b/daemon/RequestXML.cpp index cdc1e8e..3dd7a43 100644 --- a/daemon/RequestXML.cpp +++ b/daemon/RequestXML.cpp @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #include #include diff --git a/daemon/Sender.cpp b/daemon/Sender.cpp index 547d425..c547d67 100644 --- a/daemon/Sender.cpp +++ b/daemon/Sender.cpp @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #include #include @@ -22,6 +21,7 @@ extern void handleException(); Sender::Sender(OlySocket* socket) { dataFile = NULL; + dataSocket = NULL; // Set up the socket connection if (socket) { @@ -44,6 +44,8 @@ Sender::Sender(OlySocket* socket) { gSessionData.mWaitingOnCommand = true; logg->logMessage("Completed magic sequence"); } + + pthread_mutex_init(&sendMutex, NULL); } Sender::~Sender() { @@ -72,10 +74,13 @@ void Sender::writeData(const char* data, int length, int type) { return; } + // Multiple threads call writeData() + pthread_mutex_lock(&sendMutex); + // Send data over the socket connection if (dataSocket) { // Start alarm - alarm(5); + alarm(8); // Send data over the socket, sending the type and size first logg->logMessage("Sending data with length %d", length); @@ -96,4 +101,6 @@ void Sender::writeData(const char* data, int length, int type) { handleException(); } } + + pthread_mutex_unlock(&sendMutex); } diff --git a/daemon/Sender.h b/daemon/Sender.h index 9584c10..147f190 100644 --- a/daemon/Sender.h +++ b/daemon/Sender.h @@ -10,6 +10,7 @@ #define __SENDER_H__ #include +#include #include "OlySocket.h" enum { @@ -31,6 +32,7 @@ private: OlySocket* dataSocket; FILE* dataFile; char* dataFileName; + pthread_mutex_t sendMutex; }; #endif //__SENDER_H__ diff --git a/daemon/SessionData.cpp b/daemon/SessionData.cpp index 0672804..f84253a 100644 --- a/daemon/SessionData.cpp +++ b/daemon/SessionData.cpp @@ -6,10 +6,9 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #include "SessionData.h" -#include "ReadSession.h" +#include "SessionXML.h" #include "Logging.h" extern void handleException(); @@ -56,7 +55,7 @@ void SessionData::initializeCounters() { } void SessionData::parseSessionXML(char* xmlString) { - ReadSession session(xmlString); + SessionXML session(xmlString); session.parse(); // Parameter error checking diff --git a/daemon/SessionData.h b/daemon/SessionData.h index 7e8ce3c..f3ae4a3 100644 --- a/daemon/SessionData.h +++ b/daemon/SessionData.h @@ -13,7 +13,7 @@ #define MAX_STRING_LEN 80 #define MAX_DESCRIPTION_LEN 400 -#define PROTOCOL_VERSION 6 +#define PROTOCOL_VERSION 7 #define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions struct ImageLinkList { diff --git a/daemon/SessionXML.cpp b/daemon/SessionXML.cpp new file mode 100644 index 0000000..5034e48 --- /dev/null +++ b/daemon/SessionXML.cpp @@ -0,0 +1,119 @@ +/** + * Copyright (C) ARM Limited 2010-2011. 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 +#include +#include +#include "SessionXML.h" +#include "Logging.h" + +extern void handleException(); + +static const char* TAG_SESSION = "session"; +static const char* TAG_IMAGE = "image"; + +static const char* ATTR_VERSION = "version"; +static const char* ATTR_TITLE = "title"; +static const char* ATTR_UUID = "uuid"; +static const char* ATTR_CALL_STACK_UNWINDING = "call_stack_unwinding"; +static const char* ATTR_BUFFER_MODE = "buffer_mode"; +static const char* ATTR_SAMPLE_RATE = "sample_rate"; +static const char* ATTR_TARGET_PATH = "target_path"; +static const char* ATTR_OUTPUT_PATH = "output_path"; +static const char* ATTR_DURATION = "duration"; +static const char* ATTR_PATH = "path"; + +SessionXML::SessionXML(const char * str) { + parameters.title = 0; + parameters.uuid[0] = 0; + parameters.target_path = 0; + parameters.output_path = 0; + parameters.buffer_mode[0] = 0; + parameters.sample_rate[0] = 0; + parameters.duration = 0; + parameters.call_stack_unwinding = false; + parameters.images = NULL; + mPath = 0; + mSessionXML = (char*)str; + logg->logMessage(mSessionXML); +} + +SessionXML::~SessionXML() { + if (mPath != 0) { + free(mSessionXML); + } +} + +void SessionXML::parse() { + XMLReader reader(mSessionXML); + char * tag = reader.nextTag(); + while(tag != 0) { + if (strcmp(tag, TAG_SESSION) == 0) { + sessionTag(&reader); + return; + } + tag = reader.nextTag(); + } + + logg->logError(__FILE__, __LINE__, "No session tag found in the session.xml file"); + handleException(); +} + +void SessionXML::sessionTag(XMLReader* in) { + char* tempBuffer = (char*)malloc(PATH_MAX); + int version = in->getAttributeAsInteger(ATTR_VERSION, 0); + if (version != 1) { + logg->logError(__FILE__, __LINE__, "Invalid session.xml version: %d", version); + handleException(); + } + + in->getAttribute(ATTR_TITLE, tempBuffer, PATH_MAX, "unnamed"); + parameters.title = strdup(tempBuffer); // freed when the child process exits + if (parameters.title == NULL) { + logg->logError(__FILE__, __LINE__, "failed to allocate parameters.title (%d bytes)", strlen(tempBuffer)); + handleException(); + } + in->getAttribute(ATTR_UUID, parameters.uuid, sizeof(parameters.uuid), ""); + parameters.duration = in->getAttributeAsInteger(ATTR_DURATION, 0); + parameters.call_stack_unwinding = in->getAttributeAsBoolean(ATTR_CALL_STACK_UNWINDING, true); + in->getAttribute(ATTR_BUFFER_MODE, parameters.buffer_mode, sizeof(parameters.buffer_mode), "normal"); + in->getAttribute(ATTR_SAMPLE_RATE, parameters.sample_rate, sizeof(parameters.sample_rate), ""); + in->getAttribute(ATTR_TARGET_PATH, tempBuffer, PATH_MAX, ""); + parameters.target_path = strdup(tempBuffer); // freed when the child process exits + if (parameters.target_path == NULL) { + logg->logError(__FILE__, __LINE__, "failed to allocate parameters.target_path (%d bytes)", strlen(tempBuffer)); + handleException(); + } + in->getAttribute(ATTR_OUTPUT_PATH, tempBuffer, PATH_MAX, ""); + parameters.output_path = strdup(tempBuffer); // freed when the child process exits + if (parameters.output_path == NULL) { + logg->logError(__FILE__, __LINE__, "failed to allocate parameters.output_path (%d bytes)", strlen(tempBuffer)); + handleException(); + } + + free(tempBuffer); + + char * tag = in->nextTag(); + while(tag != 0) { + if (strcmp(tag, TAG_IMAGE) == 0) { + sessionImage(in); + } + tag = in->nextTag(); + } +} + +void SessionXML::sessionImage(XMLReader* in) { + int length = in->getAttributeLength(ATTR_PATH); + struct ImageLinkList *image; + + image = (struct ImageLinkList *)malloc(sizeof(struct ImageLinkList)); + image->path = (char *)malloc(length + 1); + in->getAttribute(ATTR_PATH, image->path, length + 1, ""); + image->next = parameters.images; + parameters.images = image; +} diff --git a/daemon/SessionXML.h b/daemon/SessionXML.h new file mode 100644 index 0000000..b52b57f --- /dev/null +++ b/daemon/SessionXML.h @@ -0,0 +1,40 @@ +/** + * Copyright (C) ARM Limited 2010-2011. 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. + */ + +#ifndef SESSION_XML_H +#define SESSION_XML_H + +#include "XMLReader.h" +#include "SessionData.h" + +struct ConfigParameters { + char* title; // status title + char uuid[64]; // universal unique identifier + char* target_path; // target path of where to write to disk + char* output_path; // host path of where to write to disk + char buffer_mode[64]; // buffer mode, "streaming", "low", "normal", "high" defines oneshot and buffer size + char sample_rate[64]; // capture mode, "high", "normal", or "low" + int duration; // length of profile in seconds + bool call_stack_unwinding; // whether stack unwinding is performed + struct ImageLinkList *images; // linked list of image strings +}; + +class SessionXML { +public: + SessionXML(const char * str); + ~SessionXML(); + void parse(); + ConfigParameters parameters; +private: + char* mSessionXML; + char* mPath; + void sessionTag(XMLReader* in); + void sessionImage(XMLReader* in); +}; + +#endif // SESSION_XML_H diff --git a/daemon/StreamlineSetup.cpp b/daemon/StreamlineSetup.cpp index 8473f8f..80a4ebb 100644 --- a/daemon/StreamlineSetup.cpp +++ b/daemon/StreamlineSetup.cpp @@ -6,8 +6,6 @@ * published by the Free Software Foundation. */ -typedef long long int64_t; -typedef unsigned long long uint64_t; #include #include #include @@ -235,13 +233,13 @@ void StreamlineSetup::sendProtocol() { } void StreamlineSetup::sendEvents() { -#include "events_xml.h" - char path[PATH_MAX]; - char * buffer; +#include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len + char* path = (char*)malloc(PATH_MAX);; + char* buffer; unsigned int size = 0; - util->getApplicationFullPath(path, sizeof(path)); - strncat(path, "events.xml", sizeof(path) - strlen(path) - 1); + util->getApplicationFullPath(path, PATH_MAX); + strncat(path, "events.xml", PATH_MAX - strlen(path) - 1); buffer = util->readFromDisk(path, &size); if (buffer == NULL) { logg->logMessage("Unable to locate events.xml, using default"); @@ -253,6 +251,7 @@ void StreamlineSetup::sendEvents() { if (buffer != (char*)events_xml) { free(buffer); } + free(path); } void StreamlineSetup::sendConfiguration() { @@ -263,7 +262,7 @@ void StreamlineSetup::sendConfiguration() { } void StreamlineSetup::sendDefaults() { -#include "configuration_xml.h" +#include "configuration_xml.h" // defines and initializes char configuration_xml[] and int configuration_xml_len // Send the config built into the binary char* xml = (char*)configuration_xml; unsigned int size = configuration_xml_len; @@ -306,14 +305,15 @@ void StreamlineSetup::sendCounters() { } void StreamlineSetup::writeConfiguration(char* xml) { - char path[PATH_MAX]; + char* path = (char*)malloc(PATH_MAX); - util->getApplicationFullPath(path, sizeof(path)); - strncat(path, "configuration.xml", sizeof(path) - strlen(path) - 1); + util->getApplicationFullPath(path, PATH_MAX); + strncat(path, "configuration.xml", PATH_MAX - strlen(path) - 1); if (util->writeToDisk(path, xml) < 0) { - logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", path); + logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify write permissions to this path.", path); handleException(); } new ConfigurationXML(); + free(path); } diff --git a/daemon/XMLOut.cpp b/daemon/XMLOut.cpp index 540f103..647e799 100644 --- a/daemon/XMLOut.cpp +++ b/daemon/XMLOut.cpp @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #include #include @@ -58,7 +57,7 @@ void XMLOut::writeData(const char *format, ...) { vsnprintf(temp_buffer, sizeof(temp_buffer), format, ap); va_end(ap); - strncat(xml_string, temp_buffer, sizeof(xml_string)-strlen(xml_string)-1); + strncat(xml_string, temp_buffer, sizeof(xml_string) - strlen(xml_string) - 1); } const XMLOut & XMLOut::xmlHeader(void) { diff --git a/daemon/XMLOut.h b/daemon/XMLOut.h index 057222c..479cfa9 100644 --- a/daemon/XMLOut.h +++ b/daemon/XMLOut.h @@ -12,8 +12,8 @@ class XMLOut { int indent; bool incomplete; - char temp_buffer[4096]; - char xml_string[64*1024]; + char temp_buffer[4096]; // arbitrarilly large buffer to hold variable arguments + char xml_string[64*1024]; // arbitrarilly large buffer to hold an xml file output by the daemon void writeTabs(); void encodeAttributeData(const char* data); diff --git a/daemon/XMLReader.cpp b/daemon/XMLReader.cpp index 6766dfd..45231ed 100644 --- a/daemon/XMLReader.cpp +++ b/daemon/XMLReader.cpp @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #include #include @@ -23,7 +22,7 @@ XMLReader::~XMLReader() { } char* XMLReader::nextTag() { - static char tag[128]; + static char tag[128]; // arbitrarily set max tag size to 127 characters + nul // Check if past the end of the root tag if (mNoMore) return NULL; @@ -117,7 +116,7 @@ int XMLReader::getAttributeAsInteger(const char* name, int defValue) { if (value[0] == '0' && value[1] == 'x') { return (int) strtoul(&value[2], (char**)NULL, 16); } - return atoi(value); + return strtol(value, NULL, 10); } bool XMLReader::getAttributeAsBoolean(const char* name, bool defValue) { @@ -138,7 +137,7 @@ bool XMLReader::getAttributeAsBoolean(const char* name, bool defValue) { } int XMLReader::getAttributeLength(const char* name) { - char searchString[128]; + char searchString[128]; // arbitrarily large amount // Determine search string by ending the name with =" if (strlen(name) > sizeof(searchString) - 3) return 0; diff --git a/daemon/main.cpp b/daemon/main.cpp index 4e8f38b..cf28bfc 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -6,7 +6,6 @@ * published by the Free Software Foundation. */ -typedef unsigned long long uint64_t; #include #include #include @@ -24,7 +23,7 @@ typedef unsigned long long uint64_t; #include "Logging.h" #include "OlyUtility.h" -#define DEBUG false +#define DEBUG false extern Child* child; extern void handleException(); @@ -33,6 +32,7 @@ static pthread_mutex_t numSessions_mutex; static int numSessions = 0; static OlySocket* socket = NULL; static bool driverRunningAtStart = false; +static bool driverMountedAtStart = false; struct cmdline_t { int port; @@ -51,10 +51,35 @@ void cleanUp() { // CTRL C Signal Handler void handler(int signum) { logg->logMessage("Received signal %d, gator daemon exiting", signum); + + // Case 1: both child and parent receive the signal + if (numSessions > 0) { + // Arbitrary sleep of 1 second to give time for the child to exit; + // if something bad happens, continue the shutdown process regardless + sleep(1); + } + + // Case 2: only the parent received the signal if (numSessions > 0) { - // Kill child threads + // Kill child threads - the first signal exits gracefully logg->logMessage("Killing process group as %d child was running when signal was received", numSessions); kill(0, SIGINT); + + // Give time for the child to exit + sleep(1); + + if (numSessions > 0) { + // The second signal force kills the child + logg->logMessage("Force kill the child"); + kill(0, SIGINT); + // Again, sleep for 1 second + sleep(1); + + if (numSessions > 0) { + // Something bad has really happened; the child is not exiting and therefore may hold the /dev/gator resource open + printf("Unable to kill the gatord child process, thus gator.ko may still be loaded.\n"); + } + } } cleanUp(); @@ -88,6 +113,8 @@ int mountGatorFS() { } int setupFilesystem() { + int retval; + // Verify root permissions uid_t euid = geteuid(); if (euid) { @@ -95,20 +122,34 @@ int setupFilesystem() { handleException(); } - if (mountGatorFS() >= 0) { + retval = mountGatorFS(); + if (retval == 1) { logg->logMessage("Driver already running at startup"); driverRunningAtStart = true; + } else if (retval == 0) { + logg->logMessage("Driver already mounted at startup"); + driverRunningAtStart = driverMountedAtStart = true; } else { - // Load driver - char command[512]; - strcpy(command, "insmod "); - if (util->getApplicationFullPath(&command[7], sizeof(command) - 64) != 0) { + char command[256]; // arbitrarily large amount + + // Is the driver co-located in the same directory? + if (util->getApplicationFullPath(command, sizeof(command)) != 0) { // allow some buffer space logg->logMessage("Unable to determine the full path of gatord, the cwd will be used"); } + strcat(command, "gator.ko"); + if (access(command, F_OK) == -1) { + logg->logError(__FILE__, __LINE__, "Unable to locate gator.ko driver:\n >>> gator.ko should be co-located with gatord in the same directory\n >>> OR insmod gator.ko prior to launching gatord"); + handleException(); + } + + // Load driver + strcpy(command, "insmod "); + util->getApplicationFullPath(&command[7], sizeof(command) - 64); // allow some buffer space strcat(command, "gator.ko >/dev/null 2>&1"); + if (system(command) != 0) { logg->logMessage("Unable to load gator.ko driver with command: %s", command); - logg->logError(__FILE__, __LINE__, "Unable to load (insmod) gator.ko driver. %s", DRIVER_ERROR); + logg->logError(__FILE__, __LINE__, "Unable to load (insmod) gator.ko driver:\n >>> gator.ko must be built against the current kernel version & configuration\n >>> See dmesg for more details"); handleException(); } @@ -122,12 +163,13 @@ int setupFilesystem() { } int shutdownFilesystem() { - umount("/dev/gator"); - if (driverRunningAtStart == true || system("rmmod gator >/dev/null 2>&1") == 0) { - return 0; - } + if (driverMountedAtStart == false) + umount("/dev/gator"); + if (driverRunningAtStart == false) + if (system("rmmod gator >/dev/null 2>&1") != 0) + return -1; - return -1; + return 0; // success } struct cmdline_t parseCommandLine(int argc, char** argv) { @@ -137,8 +179,8 @@ struct cmdline_t parseCommandLine(int argc, char** argv) { for (int i = 1; i < argc; i++) { // Is the argument a number? - if (atoi(argv[i]) > 0) { - cmdline.port = atoi(argv[i]); + if (strtol(argv[i], NULL, 10) > 0) { + cmdline.port = strtol(argv[i], NULL, 10); continue; } @@ -217,7 +259,6 @@ int main(int argc, char** argv, char *envp[]) { logg->logError(__FILE__, __LINE__, "Fork process failed. Please power cycle the target device if this error persists."); } else if (pid == 0) { // Child - strncpy(argv[0],"gatorc",strlen(argv[0])); // rename command line name to gatorc socket->closeServerSocket(); child = new Child(socket, numSessions + 1); child->run(); diff --git a/driver/Makefile b/driver/Makefile index de59957..b3981ff 100644 --- a/driver/Makefile +++ b/driver/Makefile @@ -1,5 +1,8 @@ ifneq ($(KERNELRELEASE),) +# Uncomment the following line to enable kernel stack unwinding within gator, or update gator_backtrace.c +# EXTRA_CFLAGS += -DGATOR_KERNEL_STACK_UNWINDING + obj-m := gator.o gator-y := gator_main.o \ @@ -12,8 +15,13 @@ gator-y := gator_main.o \ gator-y += gator_events_mmaped.o ifneq ($(GATOR_WITH_MALI_SUPPORT),) +ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx) +gator-y += gator_events_mali_t6xx.o +else gator-y += gator_events_mali.o endif +EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT) +endif gator-$(CONFIG_ARM) += gator_events_armv6.o \ gator_events_armv7.o \ diff --git a/driver/gator_annotate.c b/driver/gator_annotate.c index e096d15..ee5a160 100644 --- a/driver/gator_annotate.c +++ b/driver/gator_annotate.c @@ -27,27 +27,35 @@ static bool collect_annotations = false; static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count, loff_t *offset) { char tempBuffer[512]; - int retval, remaining, size; + int remaining, size; + uint32_t tid; if (*offset) return -EINVAL; // determine size to capture - remaining = ANNOTATE_SIZE - annotatePos - 256; // pad for headers and release size = count < sizeof(tempBuffer) ? count : sizeof(tempBuffer); - size = size < remaining ? size : remaining; - if (size <= 0) { - wake_up(&gator_buffer_wait); - return 0; + + // note: copy may be for naught if remaining is zero, but better to do the copy outside of the spinlock + if (file == NULL) { + // copy from kernel + memcpy(tempBuffer, buf, size); + + // set the thread id to the kernel thread, not the current thread + tid = -1; + } else { + // copy from user space + if (copy_from_user(tempBuffer, buf, size) != 0) + return -EINVAL; + tid = current->pid; } - // copy from user space - retval = copy_from_user(tempBuffer, buf, size); - if (retval == 0) { - // synchronize shared variables annotateBuf and annotatePos - spin_lock(&annotate_lock); - if (collect_annotations && annotateBuf) { - uint32_t tid = current->pid; + // synchronize shared variables annotateBuf and annotatePos + spin_lock(&annotate_lock); + if (collect_annotations && annotateBuf) { + remaining = ANNOTATE_SIZE - annotatePos - 256; // pad for headers and release + size = size < remaining ? size : remaining; + if (size > 0) { uint64_t time = gator_get_time(); uint32_t cpuid = smp_processor_id(); int pos = annotatePos; @@ -58,17 +66,20 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t memcpy(&annotateBuf[pos], tempBuffer, size); annotatePos = pos + size; } - spin_unlock(&annotate_lock); + } + spin_unlock(&annotate_lock); - // return the number of bytes written - retval = size; - } else { - retval = -EINVAL; + if (size <= 0) { + wake_up(&gator_buffer_wait); + return 0; } - return retval; + // return the number of bytes written + return size; } +#include "gator_annotate_kernel.c" + static int annotate_release(struct inode *inode, struct file *file) { int remaining = ANNOTATE_SIZE - annotatePos; diff --git a/driver/gator_annotate_kernel.c b/driver/gator_annotate_kernel.c new file mode 100644 index 0000000..4f690e8 --- /dev/null +++ b/driver/gator_annotate_kernel.c @@ -0,0 +1,91 @@ +/** + * Copyright (C) ARM Limited 2011. 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. + * + */ + +static void kannotate_write(char* ptr, unsigned int size) +{ + int retval; + int pos = 0; + loff_t offset = 0; + while (pos < size) { + retval = annotate_write(NULL, &ptr[pos], size - pos, &offset); + if (retval < 0) { + printk(KERN_WARNING "gator: kannotate_write failed with return value %d\n", retval); + return; + } + pos += retval; + } +} + +// String annotation +void gator_annotate(char* string) +{ + printk(KERN_ERR "module: %s\n", string); + kannotate_write(string, strlen(string) + 1); +} +EXPORT_SYMBOL(gator_annotate); + +// String annotation with color +void gator_annotate_color(int color, char* string) +{ + kannotate_write((char*)&color, sizeof(color)); + kannotate_write(string, strlen(string) + 1); +} +EXPORT_SYMBOL(gator_annotate_color); + +// Terminate an annotation +void gator_annotate_end(void) +{ + char nul = 0; + kannotate_write(&nul, sizeof(nul)); +} +EXPORT_SYMBOL(gator_annotate_end); + +// Image annotation with optional string +void gator_annotate_visual(char* data, unsigned int length, char* string) +{ + long long visual_annotation = 0x011c | (strlen(string) << 16) | ((long long)length << 32); + kannotate_write((char*)&visual_annotation, 8); + kannotate_write(string, strlen(string)); + kannotate_write(data, length); +} +EXPORT_SYMBOL(gator_annotate_visual); + +// Marker annotation +void gator_annotate_marker(void) +{ + int marker_annotation = 0x00021c; + kannotate_write((char*)&marker_annotation, 3); +} +EXPORT_SYMBOL(gator_annotate_marker); + +// Marker annotation with a string +void gator_annotate_marker_str(char* string) +{ + int marker_annotation = 0x021c; + kannotate_write((char*)&marker_annotation, 2); + kannotate_write(string, strlen(string) + 1); +} +EXPORT_SYMBOL(gator_annotate_marker_str); + +// Marker annotation with a color +void gator_annotate_marker_color(int color) +{ + long long marker_annotation = (0x021c | ((long long)color << 16)) & 0x0000ffffffffffffLL; + kannotate_write((char*)&marker_annotation, 7); +} +EXPORT_SYMBOL(gator_annotate_marker_color); + +// Marker annotationw ith a string and color +void gator_annotate_marker_color_str(int color, char* string) +{ + long long marker_annotation = 0x021c | ((long long)color << 16); + kannotate_write((char*)&marker_annotation, 6); + kannotate_write(string, strlen(string) + 1); +} +EXPORT_SYMBOL(gator_annotate_marker_color_str); diff --git a/driver/gator_backtrace.c b/driver/gator_backtrace.c index b5b0e63..fc81233 100644 --- a/driver/gator_backtrace.c +++ b/driver/gator_backtrace.c @@ -23,6 +23,7 @@ static void arm_backtrace_eabi(int cpu, int buftype, struct pt_regs * const regs struct frame_tail_eabi *ptrtail; struct frame_tail_eabi buftail; unsigned long fp = regs->ARM_fp; + unsigned long sp = regs->ARM_sp; unsigned long lr = regs->ARM_lr; int is_user_mode = user_mode(regs); @@ -34,7 +35,7 @@ static void arm_backtrace_eabi(int cpu, int buftype, struct pt_regs * const regs gator_add_trace(cpu, buftype, lr); /* check tail is valid */ - if (fp == 0) { + if (fp == 0 || fp < sp) { return; } @@ -66,3 +67,50 @@ static void arm_backtrace_eabi(int cpu, int buftype, struct pt_regs * const regs } #endif } + +#if defined(__arm__) +static DEFINE_PER_CPU(int, backtrace_buffer); +static int report_trace(struct stackframe *frame, void *d) +{ + struct module *mod; + unsigned int *depth = d, addr = frame->pc, cookie = NO_COOKIE, cpu = smp_processor_id(); + + if (*depth) { + mod = __module_address(addr); + if (mod) { + cookie = get_cookie(cpu, per_cpu(backtrace_buffer, cpu), current, NULL, mod, true); + addr = addr - (unsigned long)mod->module_core; + } + gator_buffer_write_packed_int(cpu, per_cpu(backtrace_buffer, cpu), addr & ~1); + gator_buffer_write_packed_int(cpu, per_cpu(backtrace_buffer, cpu), cookie); + (*depth)--; + } + + return *depth == 0; +} +#endif + +// Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile +// #define GATOR_KERNEL_STACK_UNWINDING +static void kernel_backtrace(int cpu, int buftype, struct pt_regs * const regs) +{ +#if defined(__arm__) +#ifdef GATOR_KERNEL_STACK_UNWINDING + int depth = gator_backtrace_depth; +#else + int depth = 1; +#endif + struct stackframe frame; + if (depth == 0) + depth = 1; + frame.fp = regs->ARM_fp; + frame.sp = regs->ARM_sp; + frame.lr = regs->ARM_lr; + frame.pc = regs->ARM_pc; + per_cpu(backtrace_buffer, cpu) = buftype; + walk_stackframe(&frame, report_trace, &depth); +#else + gator_buffer_write_packed_int(cpu, buftype, PC_REG & ~1); + gator_buffer_write_packed_int(cpu, buftype, NO_COOKIE); +#endif +} diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c index a646fb2..c0c4b9c 100644 --- a/driver/gator_cookies.c +++ b/driver/gator_cookies.c @@ -122,12 +122,18 @@ static void wq_cookie_handler(struct work_struct *unused) int cpu = smp_processor_id(); unsigned int cookie, commit; - commit = per_cpu(translate_buffer_write, cpu); - while (per_cpu(translate_buffer_read, cpu) != commit) { - task = (struct task_struct *)translate_buffer_read_int(cpu); - vma = (struct vm_area_struct *)translate_buffer_read_int(cpu); - cookie = get_cookie(cpu, TIMER_BUF, task, vma, NULL, false); + mutex_lock(&start_mutex); + + if (gator_started != 0) { + commit = per_cpu(translate_buffer_write, cpu); + while (per_cpu(translate_buffer_read, cpu) != commit) { + task = (struct task_struct *)translate_buffer_read_int(cpu); + vma = (struct vm_area_struct *)translate_buffer_read_int(cpu); + cookie = get_cookie(cpu, TIMER_BUF, task, vma, NULL, false); + } } + + mutex_unlock(&start_mutex); } // Retrieve full name from proc/pid/cmdline for java processes on Android diff --git a/driver/gator_ebs.c b/driver/gator_ebs.c index 9b55347..8b4b5ff 100644 --- a/driver/gator_ebs.c +++ b/driver/gator_ebs.c @@ -95,16 +95,19 @@ static int gator_event_sampling_start(void) int irq, i; if (IS_ERR(pmu_device)) { - pr_err("gator: event based sampling is not supported as the kernel function reserve_pmu() failed"); + pr_err("gator: event based sampling is not supported as the kernel function reserve_pmu() failed\n"); return -1; } - init_pmu(ARM_PMU_DEVICE_CPU); + // init_pmu sets the irq affinity, therefore we do not care if it fails for single core + if (init_pmu(ARM_PMU_DEVICE_CPU) != 0 && gator_cpu_cores > 1) { + pr_err("gator: unable to initialize the pmu\n"); + goto out_ebs_start; + } + if (pmu_device->num_resources == 0) { pr_err("gator: no irqs for PMUs defined\n"); - release_pmu(pmu_device); - pmu_device = NULL; - return -1; + goto out_ebs_start; } for (i = 0; i < pmu_device->num_resources; ++i) { @@ -121,9 +124,7 @@ static int gator_event_sampling_start(void) if (irq >= 0) free_irq(irq, NULL); } - release_pmu(pmu_device); - pmu_device = NULL; - return -1; + goto out_ebs_start; } } } @@ -135,6 +136,17 @@ static int gator_event_sampling_start(void) #endif return 0; + +#if LINUX_PMU_SUPPORT +out_ebs_start: +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) + release_pmu(pmu_device); +#else + release_pmu(ARM_PMU_DEVICE_CPU); +#endif + pmu_device = NULL; + return -1; +#endif } static void gator_event_sampling_stop(void) @@ -148,8 +160,13 @@ static void gator_event_sampling_stop(void) free_irq(irq, NULL); } } - if (!IS_ERR(pmu_device)) + if (!IS_ERR(pmu_device)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) release_pmu(pmu_device); +#else + release_pmu(ARM_PMU_DEVICE_CPU); +#endif + } pmu_device = NULL; #endif } diff --git a/driver/gator_events_armv7.c b/driver/gator_events_armv7.c index 58855f8..e1434e2 100644 --- a/driver/gator_events_armv7.c +++ b/driver/gator_events_armv7.c @@ -204,6 +204,7 @@ static void gator_events_armv7_online(void) static void gator_events_armv7_offline(void) { + // disbale all counters, including PMCCNTR; overflow IRQs will not be signaled armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); } diff --git a/driver/gator_main.c b/driver/gator_main.c index 91744ad..36e951b 100644 --- a/driver/gator_main.c +++ b/driver/gator_main.c @@ -7,7 +7,7 @@ * */ -static unsigned long gator_protocol_version = 6; +static unsigned long gator_protocol_version = 7; #include #include @@ -17,6 +17,8 @@ static unsigned long gator_protocol_version = 6; #include #include #include +#include +#include #include #include "gator.h" @@ -51,7 +53,7 @@ static unsigned long gator_protocol_version = 6; /****************************************************************************** * DEFINES ******************************************************************************/ -#define TIMER_BUFFER_SIZE_DEFAULT (256*1024) +#define TIMER_BUFFER_SIZE_DEFAULT (512*1024) #define EVENT_BUFFER_SIZE_DEFAULT (128*1024) #define NO_COOKIE 0UL @@ -267,11 +269,12 @@ static void gator_add_trace(int cpu, int buftype, unsigned int address) static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs) { - struct module *mod; - unsigned int addr, cookie = 0; int inKernel = regs ? !user_mode(regs) : 1; unsigned long exec_cookie = inKernel ? NO_COOKIE : get_exec_cookie(cpu, buftype, current); + if (!regs) + return; + gator_buffer_write_packed_int(cpu, buftype, MESSAGE_START_BACKTRACE); gator_buffer_write_packed_int64(cpu, buftype, gator_get_time()); gator_buffer_write_packed_int(cpu, buftype, exec_cookie); @@ -279,25 +282,15 @@ static void gator_add_sample(int cpu, int buftype, struct pt_regs * const regs) gator_buffer_write_packed_int(cpu, buftype, (unsigned int)current->pid); gator_buffer_write_packed_int(cpu, buftype, inKernel); - // get_irq_regs() will return NULL outside of IRQ context (e.g. nested IRQ) - if (regs) { - if (inKernel) { - addr = PC_REG; - mod = __module_address(addr); - if (mod) { - cookie = get_cookie(cpu, buftype, current, NULL, mod, true); - addr = addr - (unsigned long)mod->module_core; - } - gator_buffer_write_packed_int(cpu, buftype, addr & ~1); - gator_buffer_write_packed_int(cpu, buftype, cookie); - } else { - // Cookie+PC - gator_add_trace(cpu, buftype, PC_REG); - - // Backtrace - if (gator_backtrace_depth) - arm_backtrace_eabi(cpu, buftype, regs, gator_backtrace_depth); - } + if (inKernel) { + kernel_backtrace(cpu, buftype, regs); + } else { + // Cookie+PC + gator_add_trace(cpu, buftype, PC_REG); + + // Backtrace + if (gator_backtrace_depth) + arm_backtrace_eabi(cpu, buftype, regs, gator_backtrace_depth); } gator_buffer_write_packed_int(cpu, buftype, MESSAGE_END_BACKTRACE); @@ -352,11 +345,12 @@ static void gator_timer_interrupt(void) } } else if (gi->read64) { len = gi->read64(&buffer64); - if (len > 0) + if (len > 0) { gator_buffer_write_packed_int(cpu, buftype, len); for (i = 0; i < len; i++) { gator_buffer_write_packed_int64(cpu, buftype, buffer64[i]); } + } } } gator_buffer_write_packed_int(cpu, buftype, 0); @@ -460,29 +454,28 @@ static uint64_t gator_get_time(void) struct timespec ts; uint64_t timestamp; - ktime_get_ts(&ts); + getnstimeofday(&ts); timestamp = timespec_to_ns(&ts); return timestamp; } /****************************************************************************** - * cpu online notifier + * cpu online and pm notifiers ******************************************************************************/ -static int __cpuinit gator_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) +static int __cpuinit gator_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { long cpu = (long)hcpu; switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - smp_call_function_single(cpu, __gator_timer_online, NULL, 1); - break; case CPU_DOWN_PREPARE: case CPU_DOWN_PREPARE_FROZEN: smp_call_function_single(cpu, __gator_timer_offline, NULL, 1); break; + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + smp_call_function_single(cpu, __gator_timer_online, NULL, 1); + break; } return NOTIFY_OK; @@ -492,13 +485,45 @@ static struct notifier_block __refdata gator_cpu_notifier = { .notifier_call = gator_cpu_notify, }; +// n.b. calling "on_each_cpu" only runs on those that are online +// Registered linux events are not disabled, so their counters will continue to collect +static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy) +{ + switch (event) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + unregister_hotcpu_notifier(&gator_cpu_notifier); + unregister_scheduler_tracepoints(); + on_each_cpu(trace_sched_insert_idle, NULL, 1); + on_each_cpu(__gator_timer_offline, NULL, 1); + break; + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + on_each_cpu(__gator_timer_online, NULL, 1); + register_scheduler_tracepoints(); + register_hotcpu_notifier(&gator_cpu_notifier); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block gator_pm_notifier = { + .notifier_call = gator_pm_notify, +}; + static int gator_notifier_start(void) { - return register_hotcpu_notifier(&gator_cpu_notifier); + int retval; + retval = register_hotcpu_notifier(&gator_cpu_notifier); + if (retval == 0) + retval = register_pm_notifier(&gator_pm_notifier); + return retval; } static void gator_notifier_stop(void) { + unregister_pm_notifier(&gator_pm_notifier); unregister_hotcpu_notifier(&gator_cpu_notifier); } diff --git a/driver/gator_trace_sched.c b/driver/gator_trace_sched.c index 7c0bd47..0225bfb 100644 --- a/driver/gator_trace_sched.c +++ b/driver/gator_trace_sched.c @@ -14,13 +14,6 @@ #define SCHED_SWITCH 1 #define SCHED_PROCESS_FREE 2 -#define FIELD_TYPE 0 -#define FIELD_TIME 1 -#define FIELD_PARAM1 2 -#define FIELD_PARAM2 3 -#define FIELD_PARAM3 4 -#define FIELDS_PER_SCHED 5 - #define SCHEDSIZE (8*1024) #define TASK_MAP_ENTRIES 1024 /* must be power of 2 */ #define TASK_MAX_COLLISIONS 2 @@ -31,7 +24,13 @@ static DEFINE_PER_CPU(int, theSchedPos); static DEFINE_PER_CPU(int, theSchedErr); static DEFINE_PER_CPU(uint64_t *, taskname_keys); -void emit_pid_name(uint64_t time, struct task_struct* task) +enum { + STATE_CONTENTION = 0, + STATE_WAIT_ON_IO, + STATE_WAIT_ON_OTHER +}; + +void emit_pid_name(struct task_struct* task) { bool found = false; unsigned long flags; @@ -68,55 +67,92 @@ void emit_pid_name(uint64_t time, struct task_struct* task) // disable interrupts to synchronize with hrtimer populating timer buf local_irq_save(flags); gator_buffer_write_packed_int(cpu, TIMER_BUF, MESSAGE_PID_NAME); - gator_buffer_write_packed_int64(cpu, TIMER_BUF, time); + gator_buffer_write_packed_int64(cpu, TIMER_BUF, gator_get_time()); gator_buffer_write_packed_int(cpu, TIMER_BUF, task->pid); gator_buffer_write_string(cpu, TIMER_BUF, taskcomm); local_irq_restore(flags); } } -static void probe_sched_write(int type, int param1, int param2, int param3) +static void probe_sched_write(int type, struct task_struct* task, struct task_struct* old_task) { + int schedPos, cookie = 0, state = 0; unsigned long flags; + uint64_t *schedBuf, time; int cpu = smp_processor_id(); - uint64_t time = gator_get_time(); - uint64_t *schedBuf; - int schedPos, cookie = param3; + int pid = task->pid; + int tgid = task->tgid; if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)]) return; - if (param3) { + if (type == SCHED_SWITCH) { // do as much work as possible before disabling interrupts - struct task_struct *task = (struct task_struct *)param3; cookie = get_exec_cookie(cpu, TIMER_BUF, task); - emit_pid_name(time, task); + emit_pid_name(task); + if (old_task->state == 0) + state = STATE_CONTENTION; + else if (old_task->in_iowait) + state = STATE_WAIT_ON_IO; + else + state = STATE_WAIT_ON_OTHER; } // disable interrupts to synchronize with gator_trace_sched_read(); spinlocks not needed since percpu buffers are used local_irq_save(flags); + time = gator_get_time(); schedPos = per_cpu(theSchedPos, cpu); schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)]; - if (schedPos < (SCHEDSIZE-100)) { + if (schedPos < (SCHEDSIZE - 100)) { // capture - schedBuf[schedPos+FIELD_TYPE] = type; - schedBuf[schedPos+FIELD_TIME] = time; - schedBuf[schedPos+FIELD_PARAM1] = param1; - schedBuf[schedPos+FIELD_PARAM2] = param2; - schedBuf[schedPos+FIELD_PARAM3] = cookie; - per_cpu(theSchedPos, cpu) = schedPos + FIELDS_PER_SCHED; + schedBuf[schedPos++] = type; + schedBuf[schedPos++] = time; + schedBuf[schedPos++] = pid; + schedBuf[schedPos++] = tgid; + schedBuf[schedPos++] = cookie; + schedBuf[schedPos++] = state; } else if (!per_cpu(theSchedErr, cpu)) { per_cpu(theSchedErr, cpu) = 1; - schedBuf[schedPos+FIELD_TYPE] = SCHED_OVERFLOW; - schedBuf[schedPos+FIELD_TIME] = time; - schedBuf[schedPos+FIELD_PARAM1] = 0; - schedBuf[schedPos+FIELD_PARAM2] = 0; - schedBuf[schedPos+FIELD_PARAM3] = 0; - per_cpu(theSchedPos, cpu) = schedPos + FIELDS_PER_SCHED; + schedBuf[schedPos++] = SCHED_OVERFLOW; + schedBuf[schedPos++] = time; + schedBuf[schedPos++] = 0; + schedBuf[schedPos++] = 0; + schedBuf[schedPos++] = 0; + schedBuf[schedPos++] = 0; pr_debug("gator: tracepoint overflow\n"); } + per_cpu(theSchedPos, cpu) = schedPos; + local_irq_restore(flags); +} + +// special case used during a suspend of the system +static void trace_sched_insert_idle(void* unused) +{ + unsigned long flags; + uint64_t *schedBuf; + int schedPos, cpu = smp_processor_id(); + + if (!per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)]) + return; + + local_irq_save(flags); + + schedPos = per_cpu(theSchedPos, cpu); + schedBuf = per_cpu(theSchedBuf, cpu)[per_cpu(theSchedSel, cpu)]; + + if (schedPos < (SCHEDSIZE - (6 * 8))) { + // capture + schedBuf[schedPos++] = SCHED_SWITCH; + schedBuf[schedPos++] = gator_get_time(); + schedBuf[schedPos++] = 0; // idle pid is zero + schedBuf[schedPos++] = 0; // idle tid is zero + schedBuf[schedPos++] = 0; // idle cookie is zero + schedBuf[schedPos++] = STATE_WAIT_ON_OTHER; + } + + per_cpu(theSchedPos, cpu) = schedPos; local_irq_restore(flags); } @@ -126,12 +162,12 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *pre GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next)) #endif { - probe_sched_write(SCHED_SWITCH, next->pid, next->tgid, (int)next); + probe_sched_write(SCHED_SWITCH, next, prev); } GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p)) { - probe_sched_write(SCHED_PROCESS_FREE, p->pid, 0, 0); + probe_sched_write(SCHED_PROCESS_FREE, p, 0); } int gator_trace_sched_init(void) @@ -139,6 +175,25 @@ int gator_trace_sched_init(void) return 0; } +static int register_scheduler_tracepoints(void) { + // register tracepoints + if (GATOR_REGISTER_TRACE(sched_switch)) + goto fail_sched_switch; + if (GATOR_REGISTER_TRACE(sched_process_free)) + goto fail_sched_process_free; + pr_debug("gator: registered tracepoints\n"); + + return 0; + + // unregister tracepoints on error +fail_sched_process_free: + GATOR_UNREGISTER_TRACE(sched_switch); +fail_sched_switch: + pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); + + return -1; +} + int gator_trace_sched_start(void) { int cpu, size; @@ -159,30 +214,20 @@ int gator_trace_sched_start(void) memset(per_cpu(taskname_keys, cpu), 0, size); } - // register tracepoints - if (GATOR_REGISTER_TRACE(sched_switch)) - goto fail_sched_switch; - if (GATOR_REGISTER_TRACE(sched_process_free)) - goto fail_sched_process_free; - pr_debug("gator: registered tracepoints\n"); - - return 0; + return register_scheduler_tracepoints(); +} - // unregister tracepoints on error -fail_sched_process_free: +static void unregister_scheduler_tracepoints(void) +{ GATOR_UNREGISTER_TRACE(sched_switch); -fail_sched_switch: - pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); - - return -1; + GATOR_UNREGISTER_TRACE(sched_process_free); + pr_debug("gator: unregistered tracepoints\n"); } void gator_trace_sched_stop(void) { int cpu; - GATOR_UNREGISTER_TRACE(sched_switch); - GATOR_UNREGISTER_TRACE(sched_process_free); - pr_debug("gator: unregistered tracepoints\n"); + unregister_scheduler_tracepoints(); for_each_present_cpu(cpu) { kfree(per_cpu(theSchedBuf, cpu)[0]); -- cgit v1.2.3