From e31266f78058409d18d48e0afa8339e77322b17f Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Mon, 4 Aug 2014 15:47:44 +0100 Subject: gator: Version 5.19 Signed-off-by: Jon Medhurst --- tools/gator/daemon/Android.mk | 6 +- tools/gator/daemon/Application.mk | 1 + tools/gator/daemon/Buffer.cpp | 36 +++- tools/gator/daemon/Buffer.h | 11 +- tools/gator/daemon/CapturedXML.cpp | 11 +- tools/gator/daemon/CapturedXML.h | 2 +- tools/gator/daemon/Child.cpp | 45 ++--- tools/gator/daemon/Child.h | 2 +- tools/gator/daemon/ConfigurationXML.cpp | 10 +- tools/gator/daemon/Counter.h | 4 + tools/gator/daemon/DriverSource.cpp | 53 +++++- tools/gator/daemon/DriverSource.h | 5 + tools/gator/daemon/EventsXML.cpp | 16 +- tools/gator/daemon/EventsXML.h | 5 +- tools/gator/daemon/ExternalSource.cpp | 177 +++++++++++++++++++- tools/gator/daemon/ExternalSource.h | 11 +- tools/gator/daemon/FSDriver.cpp | 212 +++++++++++++++++++++++ tools/gator/daemon/FSDriver.h | 44 +++++ tools/gator/daemon/Fifo.h | 2 +- tools/gator/daemon/Hwmon.cpp | 16 +- tools/gator/daemon/KMod.cpp | 11 +- tools/gator/daemon/LocalCapture.h | 2 +- tools/gator/daemon/Logging.h | 2 +- tools/gator/daemon/Makefile | 8 +- tools/gator/daemon/Makefile_aarch64 | 9 +- tools/gator/daemon/MaliVideoDriver.cpp | 253 ++++++++++++++++++++++++++++ tools/gator/daemon/MaliVideoDriver.h | 50 ++++++ tools/gator/daemon/Monitor.cpp | 11 +- tools/gator/daemon/Monitor.h | 1 + tools/gator/daemon/OlySocket.cpp | 77 +++------ tools/gator/daemon/OlySocket.h | 14 +- tools/gator/daemon/PerfDriver.cpp | 92 +++++++--- tools/gator/daemon/PerfDriver.h | 6 +- tools/gator/daemon/PerfGroup.cpp | 28 +++- tools/gator/daemon/PerfGroup.h | 2 + tools/gator/daemon/PerfSource.cpp | 14 +- tools/gator/daemon/Proc.cpp | 106 ++++++++---- tools/gator/daemon/Proc.h | 2 +- tools/gator/daemon/Sender.h | 2 +- tools/gator/daemon/SessionData.cpp | 55 ++++-- tools/gator/daemon/SessionData.h | 17 +- tools/gator/daemon/SessionXML.cpp | 8 +- tools/gator/daemon/StreamlineSetup.cpp | 2 +- tools/gator/daemon/StreamlineSetup.h | 4 +- tools/gator/daemon/UEvent.cpp | 3 +- tools/gator/daemon/UserSpaceSource.cpp | 14 +- tools/gator/daemon/UserSpaceSource.h | 2 +- tools/gator/daemon/c++.cpp | 40 +++++ tools/gator/daemon/common.mk | 16 +- tools/gator/daemon/defaults.xml | 5 + tools/gator/daemon/escape.c | 2 +- tools/gator/daemon/events-CCI-400.xml | 21 +-- tools/gator/daemon/events-CCN-504.xml | 9 - tools/gator/daemon/events-Cortex-A53.xml | 84 ---------- tools/gator/daemon/events-Cortex-A57.xml | 84 ---------- tools/gator/daemon/events-Filesystem.xml | 11 ++ tools/gator/daemon/events-L2C-310.xml | 30 ++-- tools/gator/daemon/events-Linux.xml | 5 +- tools/gator/daemon/events-Mali-4xx.xml | 126 +++++++------- tools/gator/daemon/events-Mali-T6xx.xml | 26 ++- tools/gator/daemon/events-Mali-T6xx_hw.xml | 33 +--- tools/gator/daemon/events-Mali-V500.xml | 29 ++++ tools/gator/daemon/main.cpp | 260 +++++++++++++++++------------ 63 files changed, 1562 insertions(+), 683 deletions(-) create mode 100644 tools/gator/daemon/Application.mk create mode 100644 tools/gator/daemon/FSDriver.cpp create mode 100644 tools/gator/daemon/FSDriver.h create mode 100644 tools/gator/daemon/MaliVideoDriver.cpp create mode 100644 tools/gator/daemon/MaliVideoDriver.h create mode 100644 tools/gator/daemon/c++.cpp create mode 100644 tools/gator/daemon/events-Filesystem.xml create mode 100644 tools/gator/daemon/events-Mali-V500.xml (limited to 'tools') diff --git a/tools/gator/daemon/Android.mk b/tools/gator/daemon/Android.mk index 045d028fda5f..44c069cc7e24 100644 --- a/tools/gator/daemon/Android.mk +++ b/tools/gator/daemon/Android.mk @@ -3,7 +3,7 @@ include $(CLEAR_VARS) XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h) -LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -DETCDIR=\"/etc\" -Ilibsensors +LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -pthread -DETCDIR=\"/etc\" -Ilibsensors LOCAL_SRC_FILES := \ Buffer.cpp \ @@ -15,12 +15,14 @@ LOCAL_SRC_FILES := \ DynBuf.cpp \ EventsXML.cpp \ ExternalSource.cpp \ + FSDriver.cpp \ Fifo.cpp \ Hwmon.cpp \ KMod.cpp \ LocalCapture.cpp \ Logging.cpp \ main.cpp \ + MaliVideoDriver.cpp \ Monitor.cpp \ OlySocket.cpp \ OlyUtility.cpp \ @@ -55,7 +57,7 @@ LOCAL_SRC_FILES := \ mxml/mxml-set.c \ mxml/mxml-string.c -LOCAL_C_INCLUDES := $(LOCAL_PATH) +LOCAL_C_INCLUDES := $(LOCAL_PATH) LOCAL_MODULE := gatord LOCAL_MODULE_TAGS := optional diff --git a/tools/gator/daemon/Application.mk b/tools/gator/daemon/Application.mk new file mode 100644 index 000000000000..631ba54148d1 --- /dev/null +++ b/tools/gator/daemon/Application.mk @@ -0,0 +1 @@ +APP_PLATFORM := android-8 diff --git a/tools/gator/daemon/Buffer.cpp b/tools/gator/daemon/Buffer.cpp index 93557dabed9f..dd19f7f8be76 100644 --- a/tools/gator/daemon/Buffer.cpp +++ b/tools/gator/daemon/Buffer.cpp @@ -15,11 +15,12 @@ #define mask (mSize - 1) enum { - CODE_PEA = 1, - CODE_KEYS = 2, - CODE_FORMAT = 3, - CODE_MAPS = 4, - CODE_COMM = 5, + CODE_PEA = 1, + CODE_KEYS = 2, + CODE_FORMAT = 3, + CODE_MAPS = 4, + CODE_COMM = 5, + CODE_KEYS_OLD = 6, }; // Summary Frame Messages @@ -167,7 +168,7 @@ void Buffer::check(const uint64_t time) { } } -void Buffer::packInt(int32_t x) { +void Buffer::packInt(char *const buf, const int size, int &writePos, int32_t x) { int packedBytes = 0; int more = true; while (more) { @@ -181,11 +182,15 @@ void Buffer::packInt(int32_t x) { b |= 0x80; } - mBuf[(mWritePos + packedBytes) & mask] = b; + buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b; packedBytes++; } - mWritePos = (mWritePos + packedBytes) & mask; + writePos = (writePos + packedBytes) & /*mask*/(size - 1); +} + +void Buffer::packInt(int32_t x) { + packInt(mBuf, mSize, mWritePos, x); } void Buffer::packInt64(int64_t x) { @@ -320,6 +325,21 @@ void Buffer::keys(const int count, const __u64 *const ids, const int *const keys check(1); } +void Buffer::keysOld(const int keyCount, const int *const keys, const int bytes, const char *const buf) { + if (checkSpace((2 + keyCount) * MAXSIZE_PACK32 + bytes)) { + packInt(CODE_KEYS_OLD); + packInt(keyCount); + for (int i = 0; i < keyCount; ++i) { + packInt(keys[i]); + } + writeBytes(buf, bytes); + } else { + logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs"); + handleException(); + } + check(1); +} + void Buffer::format(const int length, const char *const format) { if (checkSpace(MAXSIZE_PACK32 + length + 1)) { packInt(CODE_FORMAT); diff --git a/tools/gator/daemon/Buffer.h b/tools/gator/daemon/Buffer.h index 50237771860c..2de1b97ac091 100644 --- a/tools/gator/daemon/Buffer.h +++ b/tools/gator/daemon/Buffer.h @@ -54,6 +54,7 @@ public: // Perf Attrs messages void pea(const struct perf_event_attr *const pea, int key); void keys(const int count, const __u64 *const ids, const int *const keys); + void keysOld(const int keyCount, const int *const keys, const int bytes, const char *const buf); void format(const int length, const char *const format); void maps(const int pid, const int tid, const char *const maps); void comm(const int pid, const int tid, const char *const image, const char *const comm); @@ -64,6 +65,11 @@ public: // Prefer a new member to using these functions if possible char *getWritePos() { return mBuf + mWritePos; } void advanceWrite(int bytes) { mWritePos = (mWritePos + bytes) & /*mask*/(mSize - 1); } + static void packInt(char *const buf, const int size, int &writePos, int32_t x); + void packInt(int32_t x); + void packInt64(int64_t x); + void writeBytes(const void *const data, size_t count); + void writeString(const char *const str); static void writeLEInt(unsigned char *buf, int v) { buf[0] = (v >> 0) & 0xFF; @@ -76,11 +82,6 @@ private: bool commitReady() const; bool checkSpace(int bytes); - void packInt(int32_t x); - void packInt64(int64_t x); - void writeBytes(const void *const data, size_t count); - void writeString(const char *const str); - const int32_t mCore; const int32_t mBufType; const int mSize; diff --git a/tools/gator/daemon/CapturedXML.cpp b/tools/gator/daemon/CapturedXML.cpp index cf79b72a1166..4a11415a00c9 100644 --- a/tools/gator/daemon/CapturedXML.cpp +++ b/tools/gator/daemon/CapturedXML.cpp @@ -33,7 +33,7 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) { captured = mxmlNewElement(xml, "captured"); mxmlElementSetAttr(captured, "version", "1"); if (gSessionData->perf.isSetup()) { - mxmlElementSetAttr(captured, "type", "Perf"); + mxmlElementSetAttr(captured, "type", "Perf"); } mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION); if (includeTime) { // Send the following only after the capture is complete @@ -66,10 +66,15 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) { mxml_node_t *const node = mxmlNewElement(counters, "counter"); mxmlElementSetAttrf(node, "key", "0x%x", counter.getKey()); mxmlElementSetAttr(node, "type", counter.getType()); - mxmlElementSetAttrf(node, "event", "0x%x", counter.getEvent()); + if (counter.getEvent() != -1) { + mxmlElementSetAttrf(node, "event", "0x%x", counter.getEvent()); + } if (counter.getCount() > 0) { mxmlElementSetAttrf(node, "count", "%d", counter.getCount()); } + if (counter.getCores() > 0) { + mxmlElementSetAttrf(node, "cores", "%d", counter.getCores()); + } } } @@ -89,7 +94,7 @@ void CapturedXML::write(char* path) { // Set full path snprintf(file, PATH_MAX, "%s/captured.xml", path); - + char* xml = getXML(true); if (util->writeToDisk(file, xml) < 0) { logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); diff --git a/tools/gator/daemon/CapturedXML.h b/tools/gator/daemon/CapturedXML.h index efc1e52bdba3..ed08c44bc3ff 100644 --- a/tools/gator/daemon/CapturedXML.h +++ b/tools/gator/daemon/CapturedXML.h @@ -23,4 +23,4 @@ private: const char * mxmlWhitespaceCB(mxml_node_t *node, int where); -#endif //__CAPTURED_XML_H__ +#endif //__CAPTURED_XML_H__ diff --git a/tools/gator/daemon/Child.cpp b/tools/gator/daemon/Child.cpp index ca33561ffdca..1901ecc6a724 100644 --- a/tools/gator/daemon/Child.cpp +++ b/tools/gator/daemon/Child.cpp @@ -26,13 +26,13 @@ #include "Driver.h" #include "PerfSource.h" #include "DriverSource.h" -#include "UserSpaceSource.h" #include "ExternalSource.h" +#include "UserSpaceSource.h" static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads static Source *primarySource = NULL; -static Source *userSpaceSource = NULL; static Source *externalSource = NULL; +static Source *userSpaceSource = NULL; static Sender* sender = NULL; // Shared by Child.cpp and spawned threads Child* child = NULL; // shared by Child.cpp and main.cpp @@ -147,16 +147,16 @@ static void *senderThread(void *) { prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0); sem_wait(&haltPipeline); - while (!primarySource->isDone() || (userSpaceSource != NULL && !userSpaceSource->isDone()) || (externalSource != NULL && !externalSource->isDone())) { + while (!primarySource->isDone() || + !externalSource->isDone() || + (userSpaceSource != NULL && !userSpaceSource->isDone())) { sem_wait(&senderSem); primarySource->write(sender); + externalSource->write(sender); if (userSpaceSource != NULL) { userSpaceSource->write(sender); } - if (externalSource != NULL) { - externalSource->write(sender); - } } // write end-of-capture sequence @@ -202,6 +202,10 @@ void Child::initialization() { void Child::endSession() { gSessionData->mSessionIsActive = false; primarySource->interrupt(); + externalSource->interrupt(); + if (userSpaceSource != NULL) { + userSpaceSource->interrupt(); + } sem_post(&haltPipeline); } @@ -227,9 +231,9 @@ void Child::run() { // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated if (!gSessionData->perf.isSetup()) { - primarySource = new DriverSource(&senderSem, &startProfile); + primarySource = new DriverSource(&senderSem, &startProfile); } else { - primarySource = new PerfSource(&senderSem, &startProfile); + primarySource = new PerfSource(&senderSem, &startProfile); } // Initialize all drivers @@ -280,11 +284,18 @@ void Child::run() { thread_creation_success = false; } else if (socket && pthread_create(&stopThreadID, NULL, stopThread, NULL)) { thread_creation_success = false; - } else if (pthread_create(&senderThreadID, NULL, senderThread, NULL)){ + } else if (pthread_create(&senderThreadID, NULL, senderThread, NULL)) { thread_creation_success = false; } - if (gSessionData->hwmon.countersEnabled()) { + externalSource = new ExternalSource(&senderSem); + if (!externalSource->prepare()) { + logg->logError(__FILE__, __LINE__, "Unable to prepare for capture"); + handleException(); + } + externalSource->start(); + + if (gSessionData->hwmon.countersEnabled() || gSessionData->fsDriver.countersEnabled()) { userSpaceSource = new UserSpaceSource(&senderSem); if (!userSpaceSource->prepare()) { logg->logError(__FILE__, __LINE__, "Unable to prepare for capture"); @@ -292,14 +303,6 @@ void Child::run() { } userSpaceSource->start(); } - if (access("/tmp/gator", F_OK) == 0) { - externalSource = new ExternalSource(&senderSem); - if (!externalSource->prepare()) { - logg->logError(__FILE__, __LINE__, "Unable to prepare for capture"); - handleException(); - } - externalSource->start(); - } if (!thread_creation_success) { logg->logError(__FILE__, __LINE__, "Failed to create gator threads"); @@ -312,12 +315,10 @@ void Child::run() { // Start profiling primarySource->run(); - if (externalSource != NULL) { - externalSource->join(); - } if (userSpaceSource != NULL) { userSpaceSource->join(); } + externalSource->join(); // Wait for the other threads to exit pthread_join(senderThreadID, NULL); @@ -337,8 +338,8 @@ void Child::run() { logg->logMessage("Profiling ended."); - delete externalSource; delete userSpaceSource; + delete externalSource; delete primarySource; delete sender; delete localCapture; diff --git a/tools/gator/daemon/Child.h b/tools/gator/daemon/Child.h index 9e206d7113b8..a306a7760819 100644 --- a/tools/gator/daemon/Child.h +++ b/tools/gator/daemon/Child.h @@ -30,4 +30,4 @@ private: Child &operator=(const Child &); }; -#endif //__CHILD_H__ +#endif //__CHILD_H__ diff --git a/tools/gator/daemon/ConfigurationXML.cpp b/tools/gator/daemon/ConfigurationXML.cpp index fd479f2452cd..6590dd389196 100644 --- a/tools/gator/daemon/ConfigurationXML.cpp +++ b/tools/gator/daemon/ConfigurationXML.cpp @@ -21,12 +21,13 @@ static const char* ATTR_COUNTER = "counter"; static const char* ATTR_REVISION = "revision"; static const char* ATTR_EVENT = "event"; static const char* ATTR_COUNT = "count"; +static const char* ATTR_CORES = "cores"; ConfigurationXML::ConfigurationXML() { const char * configuration_xml; unsigned int configuration_xml_len; getDefaultConfigurationXml(configuration_xml, configuration_xml_len); - + char path[PATH_MAX]; getPath(path); @@ -53,7 +54,7 @@ ConfigurationXML::ConfigurationXML() { break; } - + validate(); } @@ -82,7 +83,7 @@ int ConfigurationXML::parse(const char* configurationXML) { node = mxmlGetFirstChild(tree); while (node && mxmlGetType(node) != MXML_ELEMENT) node = mxmlWalkNext(node, tree, MXML_NO_DESCEND); - + ret = configurationsTag(node); node = mxmlGetFirstChild(node); @@ -127,7 +128,7 @@ void ConfigurationXML::validate(void) { #define CONFIGURATION_REVISION 3 int ConfigurationXML::configurationsTag(mxml_node_t *node) { const char* revision_string; - + revision_string = mxmlElementGetAttr(node, ATTR_REVISION); if (!revision_string) { return 1; //revision issue; @@ -158,6 +159,7 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) { if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER)); if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16)); if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10)); + if (mxmlElementGetAttr(node, ATTR_CORES)) counter.setCores(strtol(mxmlElementGetAttr(node, ATTR_CORES), NULL, 10)); if (counter.getCount() > 0) { gSessionData->mIsEBS = true; } diff --git a/tools/gator/daemon/Counter.h b/tools/gator/daemon/Counter.h index 689174573e4e..5202aa046362 100644 --- a/tools/gator/daemon/Counter.h +++ b/tools/gator/daemon/Counter.h @@ -27,6 +27,7 @@ public: mEnabled = false; mEvent = -1; mCount = 0; + mCores = -1; mKey = 0; mDriver = NULL; } @@ -35,6 +36,7 @@ public: void setEnabled(const bool enabled) { mEnabled = enabled; } void setEvent(const int event) { mEvent = event; } void setCount(const int count) { mCount = count; } + void setCores(const int cores) { mCores = cores; } void setKey(const int key) { mKey = key; } void setDriver(Driver *const driver) { mDriver = driver; } @@ -42,6 +44,7 @@ public: bool isEnabled() const { return mEnabled; } int getEvent() const { return mEvent; } int getCount() const { return mCount; } + int getCores() const { return mCores; } int getKey() const { return mKey; } Driver *getDriver() const { return mDriver; } @@ -54,6 +57,7 @@ private: bool mEnabled; int mEvent; int mCount; + int mCores; int mKey; Driver *mDriver; }; diff --git a/tools/gator/daemon/DriverSource.cpp b/tools/gator/daemon/DriverSource.cpp index f78ec6b7ce41..11d3095ef6d2 100644 --- a/tools/gator/daemon/DriverSource.cpp +++ b/tools/gator/daemon/DriverSource.cpp @@ -12,19 +12,24 @@ #include #include +#include #include +#include "Buffer.h" #include "Child.h" +#include "DynBuf.h" #include "Fifo.h" #include "Logging.h" +#include "Proc.h" #include "Sender.h" #include "SessionData.h" extern Child *child; -DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) { +DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mBuffer(NULL), mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) { int driver_version = 0; + mBuffer = new Buffer(0, FRAME_PERF_ATTRS, 4*1024*1024, senderSem); if (readIntDriver("/dev/gator/version", &driver_version) == -1) { logg->logError(__FILE__, __LINE__, "Error reading gator driver version"); handleException(); @@ -43,7 +48,7 @@ DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mFifo(NULL), handleException(); } else { // Release version mismatch - logg->logError(__FILE__, __LINE__, + logg->logError(__FILE__, __LINE__, "gator driver version \"%d\" is different than gator daemon version \"%d\".\n" ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION); handleException(); @@ -87,6 +92,28 @@ bool DriverSource::prepare() { return true; } +void DriverSource::bootstrapThread() { + prctl(PR_SET_NAME, (unsigned long)&"gatord-bootstrap", 0, 0, 0); + + DynBuf printb; + DynBuf b1; + DynBuf b2; + DynBuf b3; + + if (!readProc(mBuffer, false, &printb, &b1, &b2, &b3)) { + logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__); + handleException(); + } + + mBuffer->commit(1); + mBuffer->setDone(); +} + +void *DriverSource::bootstrapThreadStatic(void *arg) { + static_cast(arg)->bootstrapThread(); + return NULL; +} + void DriverSource::run() { // Get the initial pointer to the collect buffer char *collectBuffer = mFifo->start(); @@ -138,6 +165,12 @@ void DriverSource::run() { sem_post(mStartProfile); + pthread_t bootstrapThreadID; + if (pthread_create(&bootstrapThreadID, NULL, bootstrapThreadStatic, this) != 0) { + logg->logError(__FILE__, __LINE__, "Unable to start the gator_bootstrap thread"); + handleException(); + } + // Collect Data do { // This command will stall until data is received from the driver @@ -164,6 +197,8 @@ void DriverSource::run() { } while (bytesCollected > 0); logg->logMessage("Exit collect data loop"); + + pthread_join(bootstrapThreadID, NULL); } void DriverSource::interrupt() { @@ -174,7 +209,7 @@ void DriverSource::interrupt() { } bool DriverSource::isDone() { - return mLength <= 0; + return mLength <= 0 && (mBuffer == NULL || mBuffer->isDone()); } void DriverSource::write(Sender *sender) { @@ -182,6 +217,16 @@ void DriverSource::write(Sender *sender) { if (data != NULL) { sender->writeData(data, mLength, RESPONSE_APC_DATA); mFifo->release(); + // Assume the summary packet is in the first block received from the driver + gSessionData->mSentSummary = true; + } + if (mBuffer != NULL && !mBuffer->isDone()) { + mBuffer->write(sender); + if (mBuffer->isDone()) { + Buffer *buf = mBuffer; + mBuffer = NULL; + delete buf; + } } } @@ -227,7 +272,7 @@ int DriverSource::readInt64Driver(const char *fullpath, int64_t *value) { char *endptr; errno = 0; *value = strtoll(data, &endptr, 10); - if (errno != 0 || *endptr != '\n') { + if (errno != 0 || (*endptr != '\n' && *endptr != '\0')) { logg->logMessage("Invalid value in file %s", fullpath); return -1; } diff --git a/tools/gator/daemon/DriverSource.h b/tools/gator/daemon/DriverSource.h index dcf1078a239c..ec27b0815bbf 100644 --- a/tools/gator/daemon/DriverSource.h +++ b/tools/gator/daemon/DriverSource.h @@ -14,6 +14,7 @@ #include "Source.h" +class Buffer; class Fifo; class DriverSource : public Source { @@ -37,6 +38,10 @@ public: static int writeReadDriver(const char *path, int64_t *value); private: + static void *bootstrapThreadStatic(void *arg); + void bootstrapThread(); + + Buffer *mBuffer; Fifo *mFifo; sem_t *const mSenderSem; sem_t *const mStartProfile; diff --git a/tools/gator/daemon/EventsXML.cpp b/tools/gator/daemon/EventsXML.cpp index a07a046f3353..cf0192ef671f 100644 --- a/tools/gator/daemon/EventsXML.cpp +++ b/tools/gator/daemon/EventsXML.cpp @@ -13,7 +13,7 @@ #include "OlyUtility.h" #include "SessionData.h" -char* EventsXML::getXML() { +mxml_node_t *EventsXML::getTree() { #include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len char path[PATH_MAX]; mxml_node_t *xml; @@ -38,6 +38,12 @@ char* EventsXML::getXML() { xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK); } + return xml; +} + +char *EventsXML::getXML() { + mxml_node_t *xml = getTree(); + // Add dynamic events from the drivers mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND); if (!events) { @@ -48,19 +54,19 @@ char* EventsXML::getXML() { driver->writeEvents(events); } - char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB); + char *string = mxmlSaveAllocString(xml, mxmlWhitespaceCB); mxmlDelete(xml); return string; } -void EventsXML::write(const char* path) { +void EventsXML::write(const char *path) { char file[PATH_MAX]; // Set full path snprintf(file, PATH_MAX, "%s/events.xml", path); - - char* buf = getXML(); + + char *buf = getXML(); if (util->writeToDisk(file, buf) < 0) { logg->logError(__FILE__, __LINE__, "Error writing %s\nPlease verify the path.", file); handleException(); diff --git a/tools/gator/daemon/EventsXML.h b/tools/gator/daemon/EventsXML.h index 6cd1560f7d4e..ff7a02fd3c78 100644 --- a/tools/gator/daemon/EventsXML.h +++ b/tools/gator/daemon/EventsXML.h @@ -9,9 +9,12 @@ #ifndef EVENTS_XML #define EVENTS_XML +#include "mxml/mxml.h" + class EventsXML { public: - char* getXML(); + mxml_node_t *getTree(); + char *getXML(); void write(const char* path); }; diff --git a/tools/gator/daemon/ExternalSource.cpp b/tools/gator/daemon/ExternalSource.cpp index fe5824b04812..b6ec301d0c08 100644 --- a/tools/gator/daemon/ExternalSource.cpp +++ b/tools/gator/daemon/ExternalSource.cpp @@ -8,41 +8,195 @@ #include "ExternalSource.h" +#include #include +#include #include "Logging.h" #include "OlySocket.h" #include "SessionData.h" -ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 1024, senderSem), mSock("/tmp/gator") { +static const char MALI_VIDEO[] = "\0mali-video"; +static const char MALI_VIDEO_STARTUP[] = "\0mali-video-startup"; +static const char MALI_VIDEO_V1[] = "MALI_VIDEO 1\n"; + +static bool setNonblock(const int fd) { + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags < 0) { + logg->logMessage("fcntl getfl failed"); + return false; + } + + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) { + logg->logMessage("fcntl setfl failed"); + return false; + } + + return true; +} + +ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 128*1024, senderSem), mMonitor(), mMveStartupUds(MALI_VIDEO_STARTUP, sizeof(MALI_VIDEO_STARTUP)), mInterruptFd(-1), mMveUds(-1) { + sem_init(&mBufferSem, 0, 0); } ExternalSource::~ExternalSource() { } +void ExternalSource::waitFor(const uint64_t currTime, const int bytes) { + while (mBuffer.bytesAvailable() <= bytes) { + mBuffer.check(currTime); + sem_wait(&mBufferSem); + } +} + +void ExternalSource::configureConnection(const int fd, const char *const handshake, size_t size) { + if (!setNonblock(fd)) { + logg->logError(__FILE__, __LINE__, "Unable to set nonblock on fh"); + handleException(); + } + + if (!mMonitor.add(fd)) { + logg->logError(__FILE__, __LINE__, "Unable to add fh to monitor"); + handleException(); + } + + // Write the handshake to the circular buffer + waitFor(1, Buffer::MAXSIZE_PACK32 + 4 + size - 1); + mBuffer.packInt(fd); + mBuffer.writeLEInt((unsigned char *)mBuffer.getWritePos(), size - 1); + mBuffer.advanceWrite(4); + mBuffer.writeBytes(handshake, size - 1); +} + +bool ExternalSource::connectMve() { + if (!gSessionData->maliVideo.countersEnabled()) { + return true; + } + + mMveUds = OlySocket::connect(MALI_VIDEO, sizeof(MALI_VIDEO)); + if (mMveUds < 0) { + return false; + } + + if (!gSessionData->maliVideo.start(mMveUds)) { + return false; + } + + configureConnection(mMveUds, MALI_VIDEO_V1, sizeof(MALI_VIDEO_V1)); + + return true; +} + bool ExternalSource::prepare() { + if (!mMonitor.init() || !setNonblock(mMveStartupUds.getFd()) || !mMonitor.add(mMveStartupUds.getFd())) { + return false; + } + + connectMve(); + return true; } void ExternalSource::run() { - prctl(PR_SET_NAME, (unsigned long)&"gatord-uds", 0, 0, 0); + int pipefd[2]; + + prctl(PR_SET_NAME, (unsigned long)&"gatord-external", 0, 0, 0); + + if (pipe(pipefd) != 0) { + logg->logError(__FILE__, __LINE__, "pipe failed"); + handleException(); + } + mInterruptFd = pipefd[1]; + + if (!mMonitor.add(pipefd[0])) { + logg->logError(__FILE__, __LINE__, "Monitor::add failed"); + handleException(); + } while (gSessionData->mSessionIsActive) { - // Will be aborted when the socket is closed at the end of the capture - int length = mSock.receive(mBuffer.getWritePos(), mBuffer.contiguousSpaceAvailable()); - if (length <= 0) { - break; + struct epoll_event events[16]; + // Clear any pending sem posts + while (sem_trywait(&mBufferSem) == 0); + int ready = mMonitor.wait(events, ARRAY_LENGTH(events), -1); + if (ready < 0) { + logg->logError(__FILE__, __LINE__, "Monitor::wait failed"); + handleException(); } - mBuffer.advanceWrite(length); - mBuffer.check(0); + const uint64_t currTime = getTime(); + + for (int i = 0; i < ready; ++i) { + const int fd = events[i].data.fd; + if (fd == mMveStartupUds.getFd()) { + // Mali Video Engine says it's alive + int client = mMveStartupUds.acceptConnection(); + // Don't read from this connection, establish a new connection to Mali-V500 + close(client); + if (!connectMve()) { + logg->logError(__FILE__, __LINE__, "Unable to configure incoming Mali video connection"); + handleException(); + } + } else if (fd == pipefd[0]) { + // Means interrupt has been called and mSessionIsActive should be reread + } else { + while (true) { + waitFor(currTime, Buffer::MAXSIZE_PACK32 + 4); + + mBuffer.packInt(fd); + char *const bytesPos = mBuffer.getWritePos(); + mBuffer.advanceWrite(4); + const int contiguous = mBuffer.contiguousSpaceAvailable(); + const int bytes = read(fd, mBuffer.getWritePos(), contiguous); + if (bytes < 0) { + if (errno == EAGAIN) { + // Nothing left to read, and Buffer convention dictates that writePos can't go backwards + mBuffer.writeLEInt((unsigned char *)bytesPos, 0); + break; + } + // Something else failed, close the socket + mBuffer.writeLEInt((unsigned char *)bytesPos, -1); + close(fd); + break; + } else if (bytes == 0) { + // The other side is closed + mBuffer.writeLEInt((unsigned char *)bytesPos, -1); + close(fd); + break; + } + + mBuffer.writeLEInt((unsigned char *)bytesPos, bytes); + mBuffer.advanceWrite(bytes); + + // Short reads also mean nothing is left to read + if (bytes < contiguous) { + break; + } + } + } + } + + // Only call mBufferCheck once per iteration + mBuffer.check(currTime); } mBuffer.setDone(); + + mInterruptFd = -1; + close(pipefd[0]); + close(pipefd[1]); } void ExternalSource::interrupt() { - // Do nothing + if (mInterruptFd >= 0) { + int8_t c = 0; + // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread + if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) { + logg->logError(__FILE__, __LINE__, "write failed"); + handleException(); + } + } } bool ExternalSource::isDone() { @@ -50,7 +204,12 @@ bool ExternalSource::isDone() { } void ExternalSource::write(Sender *sender) { + // Don't send external data until the summary packet is sent so that monotonic delta is available + if (!gSessionData->mSentSummary) { + return; + } if (!mBuffer.isDone()) { mBuffer.write(sender); + sem_post(&mBufferSem); } } diff --git a/tools/gator/daemon/ExternalSource.h b/tools/gator/daemon/ExternalSource.h index 2052bdf2823e..2e7ed27df255 100644 --- a/tools/gator/daemon/ExternalSource.h +++ b/tools/gator/daemon/ExternalSource.h @@ -12,6 +12,7 @@ #include #include "Buffer.h" +#include "Monitor.h" #include "OlySocket.h" #include "Source.h" @@ -29,8 +30,16 @@ public: void write(Sender *sender); private: + void waitFor(const uint64_t currTime, const int bytes); + void configureConnection(const int fd, const char *const handshake, size_t size); + bool connectMve(); + + sem_t mBufferSem; Buffer mBuffer; - OlySocket mSock; + Monitor mMonitor; + OlyServerSocket mMveStartupUds; + int mInterruptFd; + int mMveUds; // Intentionally unimplemented ExternalSource(const ExternalSource &); diff --git a/tools/gator/daemon/FSDriver.cpp b/tools/gator/daemon/FSDriver.cpp new file mode 100644 index 000000000000..40c8df1af222 --- /dev/null +++ b/tools/gator/daemon/FSDriver.cpp @@ -0,0 +1,212 @@ +/** + * Copyright (C) ARM Limited 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 "FSDriver.h" + +#include +#include +#include +#include +#include + +#include "Buffer.h" +#include "Counter.h" +#include "DriverSource.h" +#include "Logging.h" +#include "SessionData.h" + +class FSCounter { +public: + FSCounter(FSCounter *next, char *name, const char *regex); + ~FSCounter(); + + FSCounter *getNext() const { return next; } + int getKey() const { return key; } + bool isEnabled() const { return enabled; } + void setEnabled(const bool enabled) { this->enabled = enabled; } + const char *getName() const { return name; } + int64_t read(); + +private: + FSCounter *const next; + regex_t reg; + char *name; + const int key; + int enabled : 1, + useRegex : 1; + + // Intentionally unimplemented + FSCounter(const FSCounter &); + FSCounter &operator=(const FSCounter &); +}; + +FSCounter::FSCounter(FSCounter *next, char *name, const char *regex) : next(next), name(name), key(getEventKey()), enabled(false), useRegex(regex != NULL) { + if (useRegex) { + int result = regcomp(®, regex, REG_EXTENDED); + if (result != 0) { + char buf[128]; + regerror(result, ®, buf, sizeof(buf)); + logg->logError(__FILE__, __LINE__, "Invalid regex '%s': %s", regex, buf); + handleException(); + } + } +} + +FSCounter::~FSCounter() { + free(name); + if (useRegex) { + regfree(®); + } +} + +int64_t FSCounter::read() { + int64_t value; + if (useRegex) { + char buf[4096]; + size_t pos = 0; + const int fd = open(name, O_RDONLY); + if (fd < 0) { + goto fail; + } + while (pos < sizeof(buf) - 1) { + const ssize_t bytes = ::read(fd, buf + pos, sizeof(buf) - pos - 1); + if (bytes < 0) { + goto fail; + } else if (bytes == 0) { + break; + } + pos += bytes; + } + close(fd); + buf[pos] = '\0'; + + regmatch_t match[2]; + int result = regexec(®, buf, 2, match, 0); + if (result != 0) { + regerror(result, ®, buf, sizeof(buf)); + logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", name, buf); + handleException(); + } + + if (match[1].rm_so < 0) { + logg->logError(__FILE__, __LINE__, "Parsing %s failed", name); + handleException(); + } + char *endptr; + errno = 0; + value = strtoll(buf + match[1].rm_so, &endptr, 0); + if (errno != 0) { + logg->logError(__FILE__, __LINE__, "Parsing %s failed: %s", name, strerror(errno)); + handleException(); + } + } else { + if (DriverSource::readInt64Driver(name, &value) != 0) { + goto fail; + } + } + return value; + + fail: + logg->logError(__FILE__, __LINE__, "Unable to read %s", name); + handleException(); +} + +FSDriver::FSDriver() : counters(NULL) { +} + +FSDriver::~FSDriver() { + while (counters != NULL) { + FSCounter * counter = counters; + counters = counter->getNext(); + delete counter; + } +} + +void FSDriver::setup(mxml_node_t *const xml) { + // fs driver does not currently work with perf + if (gSessionData->perf.isSetup()) { + return; + } + + mxml_node_t *node = xml; + while (true) { + node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND); + if (node == NULL) { + break; + } + const char *counter = mxmlElementGetAttr(node, "counter"); + if ((counter != NULL) && (counter[0] == '/')) { + const char *regex = mxmlElementGetAttr(node, "regex"); + counters = new FSCounter(counters, strdup(counter), regex); + } + } +} + +FSCounter *FSDriver::findCounter(const Counter &counter) const { + for (FSCounter * fsCounter = counters; fsCounter != NULL; fsCounter = fsCounter->getNext()) { + if (strcmp(fsCounter->getName(), counter.getType()) == 0) { + return fsCounter; + } + } + + return NULL; +} + +bool FSDriver::claimCounter(const Counter &counter) const { + return findCounter(counter) != NULL; +} + +bool FSDriver::countersEnabled() const { + for (FSCounter *counter = counters; counter != NULL; counter = counter->getNext()) { + if (counter->isEnabled()) { + return true; + } + } + return false; +} + +void FSDriver::resetCounters() { + for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) { + counter->setEnabled(false); + } +} + +void FSDriver::setupCounter(Counter &counter) { + FSCounter *const fsCounter = findCounter(counter); + if (fsCounter == NULL) { + counter.setEnabled(false); + return; + } + fsCounter->setEnabled(true); + counter.setKey(fsCounter->getKey()); +} + +int FSDriver::writeCounters(mxml_node_t *root) const { + int count = 0; + for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) { + if (access(counter->getName(), R_OK) == 0) { + mxml_node_t *node = mxmlNewElement(root, "counter"); + mxmlElementSetAttr(node, "name", counter->getName()); + ++count; + } + } + + return count; +} + +void FSDriver::start() { +} + +void FSDriver::read(Buffer * const buffer) { + for (FSCounter * counter = counters; counter != NULL; counter = counter->getNext()) { + if (!counter->isEnabled()) { + continue; + } + buffer->event(counter->getKey(), counter->read()); + } +} diff --git a/tools/gator/daemon/FSDriver.h b/tools/gator/daemon/FSDriver.h new file mode 100644 index 000000000000..ef3955362331 --- /dev/null +++ b/tools/gator/daemon/FSDriver.h @@ -0,0 +1,44 @@ +/** + * Copyright (C) ARM Limited 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. + */ + +#ifndef FSDRIVER_H +#define FSDRIVER_H + +#include "Driver.h" + +class Buffer; +class FSCounter; + +class FSDriver : public Driver { +public: + FSDriver(); + ~FSDriver(); + + void setup(mxml_node_t *const xml); + + bool claimCounter(const Counter &counter) const; + bool countersEnabled() const; + void resetCounters(); + void setupCounter(Counter &counter); + + int writeCounters(mxml_node_t *root) const; + + void start(); + void read(Buffer * buffer); + +private: + FSCounter *findCounter(const Counter &counter) const; + + FSCounter *counters; + + // Intentionally unimplemented + FSDriver(const FSDriver &); + FSDriver &operator=(const FSDriver &); +}; + +#endif // FSDRIVER_H diff --git a/tools/gator/daemon/Fifo.h b/tools/gator/daemon/Fifo.h index 7dd7426132d8..bdda3f549b50 100644 --- a/tools/gator/daemon/Fifo.h +++ b/tools/gator/daemon/Fifo.h @@ -45,4 +45,4 @@ private: Fifo &operator=(const Fifo &); }; -#endif //__FIFO_H__ +#endif //__FIFO_H__ diff --git a/tools/gator/daemon/Hwmon.cpp b/tools/gator/daemon/Hwmon.cpp index 778f30755dfe..e44424743ef0 100644 --- a/tools/gator/daemon/Hwmon.cpp +++ b/tools/gator/daemon/Hwmon.cpp @@ -28,6 +28,7 @@ public: const char *getTitle() const { return title; } bool isDuplicate() const { return duplicate; } const char *getDisplay() const { return display; } + const char *getCounterClass() const { return counter_class; } const char *getUnit() const { return unit; } int getModifier() const { return modifier; } @@ -58,6 +59,7 @@ private: char *label; const char *title; const char *display; + const char *counter_class; const char *unit; int modifier; double previous_value; @@ -87,7 +89,8 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co case SENSORS_FEATURE_IN: title = "Voltage"; input = SENSORS_SUBFEATURE_IN_INPUT; - display = "average"; + display = "maximum"; + counter_class = "absolute"; unit = "V"; modifier = 1000; monotonic = false; @@ -96,6 +99,7 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co title = "Fan"; input = SENSORS_SUBFEATURE_FAN_INPUT; display = "average"; + counter_class = "absolute"; unit = "RPM"; modifier = 1; monotonic = false; @@ -104,6 +108,7 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co title = "Temperature"; input = SENSORS_SUBFEATURE_TEMP_INPUT; display = "maximum"; + counter_class = "absolute"; unit = "°C"; modifier = 1000; monotonic = false; @@ -111,7 +116,8 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co case SENSORS_FEATURE_POWER: title = "Power"; input = SENSORS_SUBFEATURE_POWER_INPUT; - display = "average"; + display = "maximum"; + counter_class = "absolute"; unit = "W"; modifier = 1000000; monotonic = false; @@ -120,6 +126,7 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co title = "Energy"; input = SENSORS_SUBFEATURE_ENERGY_INPUT; display = "accumulate"; + counter_class = "delta"; unit = "J"; modifier = 1000000; monotonic = true; @@ -127,7 +134,8 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co case SENSORS_FEATURE_CURR: title = "Current"; input = SENSORS_SUBFEATURE_CURR_INPUT; - display = "average"; + display = "maximum"; + counter_class = "absolute"; unit = "A"; modifier = 1000; monotonic = false; @@ -136,6 +144,7 @@ HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, co title = "Humidity"; input = SENSORS_SUBFEATURE_HUMIDITY_INPUT; display = "average"; + counter_class = "absolute"; unit = "%"; modifier = 1000; monotonic = false; @@ -311,6 +320,7 @@ void Hwmon::writeEvents(mxml_node_t *root) const { mxmlElementSetAttr(node, "name", counter->getLabel()); } mxmlElementSetAttr(node, "display", counter->getDisplay()); + mxmlElementSetAttr(node, "class", counter->getCounterClass()); mxmlElementSetAttr(node, "units", counter->getUnit()); if (counter->getModifier() != 1) { mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier()); diff --git a/tools/gator/daemon/KMod.cpp b/tools/gator/daemon/KMod.cpp index 9300002f3fb2..73e123d2f14e 100644 --- a/tools/gator/daemon/KMod.cpp +++ b/tools/gator/daemon/KMod.cpp @@ -58,10 +58,15 @@ void KMod::setupCounter(Counter &counter) { return; } + int value = 0; snprintf(text, sizeof(text), "%s/key", base); - int key = 0; - DriverSource::readIntDriver(text, &key); - counter.setKey(key); + DriverSource::readIntDriver(text, &value); + counter.setKey(value); + + snprintf(text, sizeof(text), "%s/cores", base); + if (DriverSource::readIntDriver(text, &value) == 0) { + counter.setCores(value); + } snprintf(text, sizeof(text), "%s/event", base); DriverSource::writeDriver(text, counter.getEvent()); diff --git a/tools/gator/daemon/LocalCapture.h b/tools/gator/daemon/LocalCapture.h index aadeccecf0cc..b1e7219795cf 100644 --- a/tools/gator/daemon/LocalCapture.h +++ b/tools/gator/daemon/LocalCapture.h @@ -23,4 +23,4 @@ private: int removeDirAndAllContents(char* path); }; -#endif //__LOCAL_CAPTURE_H__ +#endif //__LOCAL_CAPTURE_H__ diff --git a/tools/gator/daemon/Logging.h b/tools/gator/daemon/Logging.h index 6ae328046989..4934bb079754 100644 --- a/tools/gator/daemon/Logging.h +++ b/tools/gator/daemon/Logging.h @@ -33,4 +33,4 @@ extern Logging* logg; extern void handleException() __attribute__ ((noreturn)); -#endif //__LOGGING_H__ +#endif //__LOGGING_H__ diff --git a/tools/gator/daemon/Makefile b/tools/gator/daemon/Makefile index 24ee94045470..2ed49fdb688b 100644 --- a/tools/gator/daemon/Makefile +++ b/tools/gator/daemon/Makefile @@ -8,14 +8,14 @@ # targets run 'make SOFTFLOAT=1 SYSROOT=/path/to/sysroot', see # README_Streamline.txt for more details -CPP = $(CROSS_COMPILE)g++ -GCC = $(CROSS_COMPILE)gcc +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ # -mthumb-interwork is required for interworking to ARM or Thumb stdlibc -CFLAGS += -mthumb-interwork +CPPFLAGS += -mthumb-interwork ifeq ($(SOFTFLOAT),1) - CFLAGS += -marm -march=armv4t -mfloat-abi=soft + CPPFLAGS += -marm -march=armv4t -mfloat-abi=soft LDFLAGS += -marm -march=armv4t -mfloat-abi=soft endif ifneq ($(SYSROOT),) diff --git a/tools/gator/daemon/Makefile_aarch64 b/tools/gator/daemon/Makefile_aarch64 index 10b4b4a71ab1..efd1fa002182 100644 --- a/tools/gator/daemon/Makefile_aarch64 +++ b/tools/gator/daemon/Makefile_aarch64 @@ -4,12 +4,9 @@ # # Uncomment and define CROSS_COMPILE if it is not already defined -# CROSS_COMPILE=/path/to/cross-compiler/arm-linux-gnueabihf- -# NOTE: This toolchain uses the hardfloat abi by default. For non-hardfloat -# targets it is necessary to add options -# '-marm -march=armv4t -mfloat-abi=soft'. +# CROSS_COMPILE=/path/to/cross-compiler/aarch64-linux-gnu- -CPP = $(CROSS_COMPILE)g++ -GCC = $(CROSS_COMPILE)gcc +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ include common.mk diff --git a/tools/gator/daemon/MaliVideoDriver.cpp b/tools/gator/daemon/MaliVideoDriver.cpp new file mode 100644 index 000000000000..18b413b01a37 --- /dev/null +++ b/tools/gator/daemon/MaliVideoDriver.cpp @@ -0,0 +1,253 @@ +/** + * Copyright (C) ARM Limited 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 "MaliVideoDriver.h" + +#include + +#include "Buffer.h" +#include "Counter.h" +#include "Logging.h" +#include "SessionData.h" + +// From instr/src/mve_instr_comm_protocol.h +typedef enum mve_instr_configuration_type { + MVE_INSTR_RAW = 1 << 0, + MVE_INSTR_COUNTERS = 1 << 1, + MVE_INSTR_EVENTS = 1 << 2, + MVE_INSTR_ACTIVITIES = 1 << 3, + + // Raw always pushed regardless + MVE_INSTR_PULL = 1 << 12, + // Raw always unpacked regardless + MVE_INSTR_PACKED_COMM = 1 << 13, + // Don’t send ACKt response + MVE_INSTR_NO_AUTO_ACK = 1 << 14, +} mve_instr_configuration_type_t; + +static const char COUNTER[] = "ARM_Mali-V500_cnt"; +static const char EVENT[] = "ARM_Mali-V500_evn"; +static const char ACTIVITY[] = "ARM_Mali-V500_act"; + +class MaliVideoCounter { +public: + MaliVideoCounter(MaliVideoCounter *next, const char *name, const MaliVideoCounterType type, const int id) : mNext(next), mName(name), mType(type), mId(id), mKey(getEventKey()), mEnabled(false) { + } + + ~MaliVideoCounter() { + delete mName; + } + + MaliVideoCounter *getNext() const { return mNext; } + const char *getName() const { return mName; } + MaliVideoCounterType getType() const { return mType; } + int getId() const { return mId; } + int getKey() const { return mKey; } + bool isEnabled() const { return mEnabled; } + void setEnabled(const bool enabled) { mEnabled = enabled; } + +private: + MaliVideoCounter *const mNext; + const char *const mName; + const MaliVideoCounterType mType; + // Mali Video id + const int mId; + // Streamline key + const int mKey; + bool mEnabled; +}; + +MaliVideoDriver::MaliVideoDriver() : mCounters(NULL), mActivityCount(0) { +} + +MaliVideoDriver::~MaliVideoDriver() { + while (mCounters != NULL) { + MaliVideoCounter *counter = mCounters; + mCounters = counter->getNext(); + delete counter; + } +} + +void MaliVideoDriver::setup(mxml_node_t *const xml) { + // hwmon does not currently work with perf + if (gSessionData->perf.isSetup()) { + return; + } + + mxml_node_t *node = xml; + while (true) { + node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND); + if (node == NULL) { + break; + } + const char *counter = mxmlElementGetAttr(node, "counter"); + if (counter == NULL) { + // Ignore + } else if (strncmp(counter, COUNTER, sizeof(COUNTER) - 1) == 0) { + const int i = strtol(counter + sizeof(COUNTER) - 1, NULL, 10); + mCounters = new MaliVideoCounter(mCounters, strdup(counter), MVCT_COUNTER, i); + } else if (strncmp(counter, EVENT, sizeof(EVENT) - 1) == 0) { + const int i = strtol(counter + sizeof(EVENT) - 1, NULL, 10); + mCounters = new MaliVideoCounter(mCounters, strdup(counter), MVCT_EVENT, i); + } else if (strcmp(counter, ACTIVITY) == 0) { + mCounters = new MaliVideoCounter(mCounters, strdup(ACTIVITY), MVCT_ACTIVITY, 0); + mActivityCount = 0; + while (true) { + char buf[32]; + snprintf(buf, sizeof(buf), "activity%i", mActivityCount + 1); + if (mxmlElementGetAttr(node, buf) == NULL) { + break; + } + ++mActivityCount; + } + } + } +} + +MaliVideoCounter *MaliVideoDriver::findCounter(const Counter &counter) const { + for (MaliVideoCounter *maliVideoCounter = mCounters; maliVideoCounter != NULL; maliVideoCounter = maliVideoCounter->getNext()) { + if (strcmp(maliVideoCounter->getName(), counter.getType()) == 0) { + return maliVideoCounter; + } + } + + return NULL; +} + +bool MaliVideoDriver::claimCounter(const Counter &counter) const { + return findCounter(counter) != NULL; +} + +bool MaliVideoDriver::countersEnabled() const { + for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { + if (counter->isEnabled()) { + return true; + } + } + return false; +} + +void MaliVideoDriver::resetCounters() { + for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { + counter->setEnabled(false); + } +} + +void MaliVideoDriver::setupCounter(Counter &counter) { + MaliVideoCounter *const maliVideoCounter = findCounter(counter); + if (maliVideoCounter == NULL) { + counter.setEnabled(false); + return; + } + maliVideoCounter->setEnabled(true); + counter.setKey(maliVideoCounter->getKey()); +} + +int MaliVideoDriver::writeCounters(mxml_node_t *root) const { + if (access("/dev/mv500", F_OK) != 0) { + return 0; + } + + int count = 0; + for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { + mxml_node_t *node = mxmlNewElement(root, "counter"); + mxmlElementSetAttr(node, "name", counter->getName()); + ++count; + } + + return count; +} + +void MaliVideoDriver::marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos) { + // size + int numEnabled = 0; + for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { + if (counter->isEnabled() && (counter->getType() == type)) { + ++numEnabled; + } + } + Buffer::packInt(buf, bufsize, pos, numEnabled*sizeof(uint32_t)); + for (MaliVideoCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { + if (counter->isEnabled() && (counter->getType() == type)) { + Buffer::packInt(buf, bufsize, pos, counter->getId()); + } + } +} + +bool MaliVideoDriver::start(const int mveUds) { + char buf[256]; + int pos = 0; + + // code - MVE_INSTR_STARTUP + buf[pos++] = 'C'; + buf[pos++] = 'L'; + buf[pos++] = 'N'; + buf[pos++] = 'T'; + // size + Buffer::packInt(buf, sizeof(buf), pos, sizeof(uint32_t)); + // client_version_number + Buffer::packInt(buf, sizeof(buf), pos, 1); + + // code - MVE_INSTR_CONFIGURE + buf[pos++] = 'C'; + buf[pos++] = 'N'; + buf[pos++] = 'F'; + buf[pos++] = 'G'; + // size + Buffer::packInt(buf, sizeof(buf), pos, 5*sizeof(uint32_t)); + // configuration + Buffer::packInt(buf, sizeof(buf), pos, MVE_INSTR_COUNTERS | MVE_INSTR_EVENTS | MVE_INSTR_ACTIVITIES | MVE_INSTR_PACKED_COMM); + // communication_protocol_version + Buffer::packInt(buf, sizeof(buf), pos, 1); + // data_protocol_version + Buffer::packInt(buf, sizeof(buf), pos, 1); + // sample_rate - convert samples/second to ms/sample + Buffer::packInt(buf, sizeof(buf), pos, 1000/gSessionData->mSampleRate); + // live_rate - convert ns/flush to ms/flush + Buffer::packInt(buf, sizeof(buf), pos, gSessionData->mLiveRate/1000000); + + // code - MVE_INSTR_ENABLE_COUNTERS + buf[pos++] = 'C'; + buf[pos++] = 'F'; + buf[pos++] = 'G'; + buf[pos++] = 'c'; + marshalEnable(MVCT_COUNTER, buf, sizeof(buf), pos); + + // code - MVE_INSTR_ENABLE_EVENTS + buf[pos++] = 'C'; + buf[pos++] = 'F'; + buf[pos++] = 'G'; + buf[pos++] = 'e'; + marshalEnable(MVCT_EVENT, buf, sizeof(buf), pos); + + /* + // code - MVE_INSTR_ENABLE_ACTIVITIES + buf[pos++] = 'C'; + buf[pos++] = 'F'; + buf[pos++] = 'G'; + buf[pos++] = 'a'; + // size + Buffer::packInt(buf, sizeof(buf), pos, mActivityCount*sizeof(uint32_t)); + for (int i = 0; i < mActivityCount; ++i) { + // activity_id + Buffer::packInt(buf, sizeof(buf), pos, i); + } + */ + + int written = 0; + while (written < pos) { + size_t bytes = ::write(mveUds, buf + written, pos - written); + if (bytes <= 0) { + logg->logMessage("%s(%s:%i): write failed", __FUNCTION__, __FILE__, __LINE__); + return false; + } + written += bytes; + } + + return true; +} diff --git a/tools/gator/daemon/MaliVideoDriver.h b/tools/gator/daemon/MaliVideoDriver.h new file mode 100644 index 000000000000..00cb80889a74 --- /dev/null +++ b/tools/gator/daemon/MaliVideoDriver.h @@ -0,0 +1,50 @@ +/** + * Copyright (C) ARM Limited 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. + */ + +#ifndef MALIVIDEODRIVER_H +#define MALIVIDEODRIVER_H + +#include "Driver.h" + +class MaliVideoCounter; + +enum MaliVideoCounterType { + MVCT_COUNTER, + MVCT_EVENT, + MVCT_ACTIVITY, +}; + +class MaliVideoDriver : public Driver { +public: + MaliVideoDriver(); + ~MaliVideoDriver(); + + void setup(mxml_node_t *const xml); + + bool claimCounter(const Counter &counter) const; + bool countersEnabled() const; + void resetCounters(); + void setupCounter(Counter &counter); + + int writeCounters(mxml_node_t *root) const; + + bool start(const int mveUds); + +private: + MaliVideoCounter *findCounter(const Counter &counter) const; + void marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos); + + MaliVideoCounter *mCounters; + int mActivityCount; + + // Intentionally unimplemented + MaliVideoDriver(const MaliVideoDriver &); + MaliVideoDriver &operator=(const MaliVideoDriver &); +}; + +#endif // MALIVIDEODRIVER_H diff --git a/tools/gator/daemon/Monitor.cpp b/tools/gator/daemon/Monitor.cpp index 90d5c47706c7..b34a15f0eb0c 100644 --- a/tools/gator/daemon/Monitor.cpp +++ b/tools/gator/daemon/Monitor.cpp @@ -18,8 +18,15 @@ Monitor::Monitor() : mFd(-1) { } Monitor::~Monitor() { - if (mFd >= -1) { - close(mFd); + if (mFd >= 0) { + ::close(mFd); + } +} + +void Monitor::close() { + if (mFd >= 0) { + ::close(mFd); + mFd = -1; } } diff --git a/tools/gator/daemon/Monitor.h b/tools/gator/daemon/Monitor.h index 6e268b6e1bed..7194e0e4ca50 100644 --- a/tools/gator/daemon/Monitor.h +++ b/tools/gator/daemon/Monitor.h @@ -16,6 +16,7 @@ public: Monitor(); ~Monitor(); + void close(); bool init(); bool add(const int fd); int wait(struct epoll_event *const events, int maxevents, int timeout); diff --git a/tools/gator/daemon/OlySocket.cpp b/tools/gator/daemon/OlySocket.cpp index 26e4768f3934..28774e36e510 100644 --- a/tools/gator/daemon/OlySocket.cpp +++ b/tools/gator/daemon/OlySocket.cpp @@ -9,6 +9,7 @@ #include "OlySocket.h" #include +#include #ifdef WIN32 #include #include @@ -43,16 +44,18 @@ OlyServerSocket::OlyServerSocket(int port) { createServerSocket(port); } -OlySocket::OlySocket(int port, const char* host) { - createClientSocket(host, port); -} - OlySocket::OlySocket(int socketID) : mSocketID(socketID) { } #ifndef WIN32 -OlyServerSocket::OlyServerSocket(const char* path) { +#define MIN(A, B) ({ \ + const __typeof__(A) __a = A; \ + const __typeof__(B) __b = B; \ + __a > __b ? __b : __a; \ +}) + +OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize) { // Create socket mFDServer = socket(PF_UNIX, SOCK_STREAM, 0); if (mFDServer < 0) { @@ -60,13 +63,11 @@ OlyServerSocket::OlyServerSocket(const char* path) { handleException(); } - unlink(path); - // Create sockaddr_in structure, ensuring non-populated fields are zero struct sockaddr_un sockaddr; memset((void*)&sockaddr, 0, sizeof(sockaddr)); sockaddr.sun_family = AF_UNIX; - strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1); + memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path))); sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0'; // Bind the socket to an address @@ -82,24 +83,25 @@ OlyServerSocket::OlyServerSocket(const char* path) { } } -OlySocket::OlySocket(const char* path) { - mSocketID = socket(PF_UNIX, SOCK_STREAM, 0); - if (mSocketID < 0) { - return; +int OlySocket::connect(const char* path, const size_t pathSize) { + int fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + return -1; } // Create sockaddr_in structure, ensuring non-populated fields are zero struct sockaddr_un sockaddr; memset((void*)&sockaddr, 0, sizeof(sockaddr)); sockaddr.sun_family = AF_UNIX; - strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1); + memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path))); sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0'; - if (connect(mSocketID, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { - close(mSocketID); - mSocketID = -1; - return; + if (::connect(fd, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { + close(fd); + return -1; } + + return fd; } #endif @@ -137,47 +139,6 @@ void OlyServerSocket::closeServerSocket() { mFDServer = 0; } -void OlySocket::createClientSocket(const char* hostname, int portno) { -#ifdef WIN32 - // TODO: Implement for Windows -#else - char buf[32]; - struct addrinfo hints, *res, *res0; - - snprintf(buf, sizeof(buf), "%d", portno); - mSocketID = -1; - memset((void*)&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - if (getaddrinfo(hostname, buf, &hints, &res0)) { - logg->logError(__FILE__, __LINE__, "Client socket failed to get address info for %s", hostname); - handleException(); - } - for (res=res0; res!=NULL; res = res->ai_next) { - if ( res->ai_family != PF_INET || res->ai_socktype != SOCK_STREAM ) { - continue; - } - mSocketID = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (mSocketID < 0) { - continue; - } - if (connect(mSocketID, res->ai_addr, res->ai_addrlen) < 0) { - close(mSocketID); - mSocketID = -1; - } - if (mSocketID > 0) { - break; - } - } - freeaddrinfo(res0); - if (mSocketID <= 0) { - logg->logError(__FILE__, __LINE__, "Could not connect to client socket. Ensure ARM Streamline is running."); - handleException(); - } -#endif -} - void OlyServerSocket::createServerSocket(int port) { int family = AF_INET6; diff --git a/tools/gator/daemon/OlySocket.h b/tools/gator/daemon/OlySocket.h index eab786b304bf..20c67cc695e1 100644 --- a/tools/gator/daemon/OlySocket.h +++ b/tools/gator/daemon/OlySocket.h @@ -9,13 +9,15 @@ #ifndef __OLY_SOCKET_H__ #define __OLY_SOCKET_H__ +#include + class OlySocket { public: - OlySocket(int port, const char* hostname); - OlySocket(int socketID); #ifndef WIN32 - OlySocket(const char* path); + static int connect(const char* path, const size_t pathSize); #endif + + OlySocket(int socketID); ~OlySocket(); void closeSocket(); @@ -29,21 +31,21 @@ public: private: int mSocketID; - - void createClientSocket(const char* hostname, int port); }; class OlyServerSocket { public: OlyServerSocket(int port); #ifndef WIN32 - OlyServerSocket(const char* path); + OlyServerSocket(const char* path, const size_t pathSize); #endif ~OlyServerSocket(); int acceptConnection(); void closeServerSocket(); + int getFd() { return mFDServer; } + private: int mFDServer; diff --git a/tools/gator/daemon/PerfDriver.cpp b/tools/gator/daemon/PerfDriver.cpp index 8e25c22f6798..ac97a077d266 100644 --- a/tools/gator/daemon/PerfDriver.cpp +++ b/tools/gator/daemon/PerfDriver.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "Buffer.h" #include "Config.h" @@ -30,7 +31,7 @@ struct gator_cpu { const int cpuid; // Human readable name - const char core_name[32]; + const char *const core_name; // gatorfs event and Perf PMU name const char *const pmnc_name; const int pmnc_counters; @@ -62,9 +63,20 @@ static const struct gator_cpu gator_cpus[] = { static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-"; static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_"; +struct uncore_counter { + // gatorfs event and Perf PMU name + const char *const name; + const int count; +}; + +static const struct uncore_counter uncore_counters[] = { + { "CCI_400", 4 }, + { "CCI_400-r1", 4 }, +}; + class PerfCounter { public: - PerfCounter(PerfCounter *next, const char *name, uint32_t type, uint64_t config) : mNext(next), mName(name), mType(type), mCount(0), mKey(getEventKey()), mConfig(config), mEnabled(false) {} + PerfCounter(PerfCounter *next, const char *name, uint32_t type, uint64_t config, bool perCpu) : mNext(next), mName(name), mType(type), mCount(0), mKey(getEventKey()), mConfig(config), mEnabled(false), mPerCpu(perCpu) {} ~PerfCounter() { delete [] mName; } @@ -79,6 +91,7 @@ public: void setConfig(const uint64_t config) { mConfig = config; } bool isEnabled() const { return mEnabled; } void setEnabled(const bool enabled) { mEnabled = enabled; } + bool isPerCpu() const { return mPerCpu; } private: PerfCounter *const mNext; @@ -87,10 +100,11 @@ private: int mCount; const int mKey; uint64_t mConfig; - bool mEnabled; + int mEnabled : 1, + mPerCpu : 1; }; -PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(false) { +PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(false), mLegacySupport(false) { } PerfDriver::~PerfDriver() { @@ -105,13 +119,27 @@ void PerfDriver::addCpuCounters(const char *const counterName, const int type, c int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1; char *name = new char[len]; snprintf(name, len, "%s_ccnt", counterName); - mCounters = new PerfCounter(mCounters, name, type, -1); + mCounters = new PerfCounter(mCounters, name, type, -1, true); for (int j = 0; j < numCounters; ++j) { len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1; name = new char[len]; snprintf(name, len, "%s_cnt%d", counterName, j); - mCounters = new PerfCounter(mCounters, name, type, -1); + mCounters = new PerfCounter(mCounters, name, type, -1, true); + } +} + +void PerfDriver::addUncoreCounters(const char *const counterName, const int type, const int numCounters) { + int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1; + char *name = new char[len]; + snprintf(name, len, "%s_ccnt", counterName); + mCounters = new PerfCounter(mCounters, name, type, -1, false); + + for (int j = 0; j < numCounters; ++j) { + len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1; + name = new char[len]; + snprintf(name, len, "%s_cnt%d", counterName, j); + mCounters = new PerfCounter(mCounters, name, type, -1, false); } } @@ -139,10 +167,16 @@ bool PerfDriver::setup() { } } - if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0)) { + if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 4, 0)) { logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__); return false; } + mLegacySupport = KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0); + + if (access(EVENTS_PATH, R_OK) != 0) { + logg->logMessage("%s(%s:%i): " EVENTS_PATH " does not exist, is CONFIG_TRACING enabled?", __FUNCTION__, __FILE__, __LINE__); + return false; + } // Add supported PMUs bool foundCpu = false; @@ -174,6 +208,21 @@ bool PerfDriver::setup() { foundCpu = true; addCpuCounters(gator_cpus[i].pmnc_name, type, gator_cpus[i].pmnc_counters); } + + for (int i = 0; i < ARRAY_LENGTH(uncore_counters); ++i) { + if (strcmp(dirent->d_name, uncore_counters[i].name) != 0) { + continue; + } + + int type; + char buf[256]; + snprintf(buf, sizeof(buf), PERF_DEVICES "/%s/type", dirent->d_name); + if (DriverSource::readIntDriver(buf, &type) != 0) { + continue; + } + + addUncoreCounters(uncore_counters[i].name, type, uncore_counters[i].count); + } } closedir(dir); @@ -203,12 +252,12 @@ bool PerfDriver::setup() { id = getTracepointId("irq/softirq_exit", &printb); if (id >= 0) { - mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id); + mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id, true); } id = getTracepointId("irq/irq_handler_exit", &printb); if (id >= 0) { - mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id); + mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id, true); } //Linux_block_rq_wr @@ -218,7 +267,7 @@ bool PerfDriver::setup() { id = getTracepointId(SCHED_SWITCH, &printb); if (id >= 0) { - mCounters = new PerfCounter(mCounters, "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id); + mCounters = new PerfCounter(mCounters, "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id, true); } //Linux_meminfo_memused @@ -227,7 +276,7 @@ bool PerfDriver::setup() { //Linux_power_cpu_freq //Linux_power_cpu_idle - mCounters = new PerfCounter(mCounters, "Linux_cpu_wait_contention", TYPE_DERIVED, -1); + mCounters = new PerfCounter(mCounters, "Linux_cpu_wait_contention", TYPE_DERIVED, -1, false); //Linux_cpu_wait_io @@ -252,15 +301,16 @@ bool PerfDriver::summary(Buffer *const buffer) { } const int64_t timestamp = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec; - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { - logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__); - return false; - } - const int64_t uptime = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec; + const int64_t uptime = getTime(); buffer->summary(timestamp, uptime, 0, buf); for (int i = 0; i < gSessionData->mCores; ++i) { + // Don't send information on a cpu we know nothing about + if (gSessionData->mCpuIds[i] == -1) { + continue; + } + int j; for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) { if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) { @@ -270,7 +320,11 @@ bool PerfDriver::summary(Buffer *const buffer) { if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) { buffer->coreName(i, gSessionData->mCpuIds[i], gator_cpus[j].core_name); } else { - snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]); + if (gSessionData->mCpuIds[i] == -1) { + snprintf(buf, sizeof(buf), "Unknown"); + } else { + snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]); + } buffer->coreName(i, gSessionData->mCpuIds[i], buf); } } @@ -326,10 +380,10 @@ int PerfDriver::writeCounters(mxml_node_t *root) const { return count; } -bool PerfDriver::enable(PerfGroup *group, Buffer *const buffer) const { +bool PerfDriver::enable(PerfGroup *const group, Buffer *const buffer) const { for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) { if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) { - if (!group->add(buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), 0, 0)) { + if (!group->add(buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), counter->getCount() > 0 ? PERF_SAMPLE_TID | PERF_SAMPLE_IP : 0, counter->isPerCpu() ? PERF_GROUP_PER_CPU : 0)) { logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__); return false; } diff --git a/tools/gator/daemon/PerfDriver.h b/tools/gator/daemon/PerfDriver.h index 3181b74f5570..2cae575a7059 100644 --- a/tools/gator/daemon/PerfDriver.h +++ b/tools/gator/daemon/PerfDriver.h @@ -27,6 +27,8 @@ public: PerfDriver(); ~PerfDriver(); + bool getLegacySupport() const { return mLegacySupport; } + bool setup(); bool summary(Buffer *const buffer); bool isSetup() const { return mIsSetup; } @@ -37,16 +39,18 @@ public: int writeCounters(mxml_node_t *root) const; - bool enable(PerfGroup *group, Buffer *const buffer) const; + bool enable(PerfGroup *const group, Buffer *const buffer) const; static long long getTracepointId(const char *const name, DynBuf *const printb); private: PerfCounter *findCounter(const Counter &counter) const; void addCpuCounters(const char *const counterName, const int type, const int numCounters); + void addUncoreCounters(const char *const counterName, const int type, const int numCounters); PerfCounter *mCounters; bool mIsSetup; + bool mLegacySupport; // Intentionally undefined PerfDriver(const PerfDriver &); diff --git a/tools/gator/daemon/PerfGroup.cpp b/tools/gator/daemon/PerfGroup.cpp index faf5fcaf15e6..2a0239f7c348 100644 --- a/tools/gator/daemon/PerfGroup.cpp +++ b/tools/gator/daemon/PerfGroup.cpp @@ -23,7 +23,9 @@ #define DEFAULT_PEA_ARGS(pea, additionalSampleType) \ pea.size = sizeof(pea); \ /* Emit time, read_format below, group leader id, and raw tracepoint info */ \ - pea.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_IDENTIFIER | additionalSampleType; \ + pea.sample_type = (gSessionData->perf.getLegacySupport() \ + ? PERF_SAMPLE_TID | PERF_SAMPLE_IP | PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_ID \ + : PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_IDENTIFIER ) | additionalSampleType; \ /* Emit emit value in group format */ \ pea.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP; \ /* start out disabled */ \ @@ -39,6 +41,7 @@ static int sys_perf_event_open(struct perf_event_attr *const attr, const pid_t p PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb) { memset(&mAttrs, 0, sizeof(mAttrs)); + memset(&mPerCpu, 0, sizeof(mPerCpu)); memset(&mKeys, -1, sizeof(mKeys)); memset(&mFds, -1, sizeof(mFds)); } @@ -75,6 +78,7 @@ bool PerfGroup::add(Buffer *const buffer, const int key, const __u32 type, const mAttrs[i].freq = (flags & PERF_GROUP_FREQ ? 1 : 0); mAttrs[i].task = (flags & PERF_GROUP_TASK ? 1 : 0); mAttrs[i].sample_id_all = (flags & PERF_GROUP_SAMPLE_ID_ALL ? 1 : 0); + mPerCpu[i] = (flags & PERF_GROUP_PER_CPU); mKeys[i] = key; @@ -91,13 +95,17 @@ bool PerfGroup::prepareCPU(const int cpu) { continue; } + if ((cpu != 0) && !mPerCpu[i]) { + continue; + } + const int offset = i * gSessionData->mCores; if (mFds[cpu + offset] >= 0) { logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__); return false; } - logg->logMessage("%s(%s:%i): perf_event_open cpu: %i type: %lli config: %lli sample: %lli sample_type: %lli", __FUNCTION__, __FILE__, __LINE__, cpu, (long long)mAttrs[i].type, (long long)mAttrs[i].config, (long long)mAttrs[i].sample_period, (long long)mAttrs[i].sample_type); + logg->logMessage("%s(%s:%i): perf_event_open cpu: %i type: %lli config: %lli sample: %lli sample_type: 0x%llx pinned: %i mmap: %i comm: %i freq: %i task: %i sample_id_all: %i", __FUNCTION__, __FILE__, __LINE__, cpu, (long long)mAttrs[i].type, (long long)mAttrs[i].config, (long long)mAttrs[i].sample_period, (long long)mAttrs[i].sample_type, mAttrs[i].pinned, mAttrs[i].mmap, mAttrs[i].comm, mAttrs[i].freq, mAttrs[i].task, mAttrs[i].sample_id_all); mFds[cpu + offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, i == 0 ? -1 : mFds[cpu], i == 0 ? 0 : PERF_FLAG_FD_OUTPUT); if (mFds[cpu + offset] < 0) { logg->logMessage("%s(%s:%i): failed %s", __FUNCTION__, __FILE__, __LINE__, strerror(errno)); @@ -125,7 +133,9 @@ int PerfGroup::onlineCPU(const int cpu, const bool start, Buffer *const buffer, } coreKeys[idCount] = mKeys[i]; - if (ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0) { + if (!gSessionData->perf.getLegacySupport() && ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0 && + // Workaround for running 32-bit gatord on 64-bit systems, kernel patch in the works + ioctl(fd, (PERF_EVENT_IOC_ID & ~IOCSIZE_MASK) | (8 << _IOC_SIZESHIFT), &ids[idCount]) != 0) { logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__); return false; } @@ -137,7 +147,17 @@ int PerfGroup::onlineCPU(const int cpu, const bool start, Buffer *const buffer, return false; } - buffer->keys(idCount, ids, coreKeys); + if (!gSessionData->perf.getLegacySupport()) { + buffer->keys(idCount, ids, coreKeys); + } else { + char buf[1024]; + ssize_t bytes = read(mFds[cpu], buf, sizeof(buf)); + if (bytes < 0) { + logg->logMessage("read failed"); + return false; + } + buffer->keysOld(idCount, coreKeys, bytes, buf); + } if (start) { for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) { diff --git a/tools/gator/daemon/PerfGroup.h b/tools/gator/daemon/PerfGroup.h index af496d41334c..3f1e2bb4d1c8 100644 --- a/tools/gator/daemon/PerfGroup.h +++ b/tools/gator/daemon/PerfGroup.h @@ -24,6 +24,7 @@ enum PerfGroupFlags { PERF_GROUP_FREQ = 1 << 2, PERF_GROUP_TASK = 1 << 3, PERF_GROUP_SAMPLE_ID_ALL = 1 << 4, + PERF_GROUP_PER_CPU = 1 << 5, }; class PerfGroup { @@ -43,6 +44,7 @@ public: private: // +1 for the group leader struct perf_event_attr mAttrs[MAX_PERFORMANCE_COUNTERS + 1]; + bool mPerCpu[MAX_PERFORMANCE_COUNTERS + 1]; int mKeys[MAX_PERFORMANCE_COUNTERS + 1]; int mFds[NR_CPUS * (MAX_PERFORMANCE_COUNTERS + 1)]; PerfBuffer *const mPb; diff --git a/tools/gator/daemon/PerfSource.cpp b/tools/gator/daemon/PerfSource.cpp index 1f1cb1988f00..ecfaa66832bd 100644 --- a/tools/gator/daemon/PerfSource.cpp +++ b/tools/gator/daemon/PerfSource.cpp @@ -37,7 +37,7 @@ static bool sendTracepointFormat(Buffer *const buffer, const char *const name, D return true; } -PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(0, FRAME_PERF_ATTRS, 1024*1024, senderSem), mCountersBuf(), mCountersGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) { +PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(0, FRAME_PERF_ATTRS, 4*1024*1024, senderSem), mCountersBuf(), mCountersGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) { long l = sysconf(_SC_PAGE_SIZE); if (l < 0) { logg->logError(__FILE__, __LINE__, "Unable to obtain the page size"); @@ -74,6 +74,9 @@ bool PerfSource::prepare() { DynBuf b3; long long schedSwitchId; + // Reread cpuinfo since cores may have changed since startup + gSessionData->readCpuInfo(); + if (0 || !mMonitor.init() || !mUEvent.init() @@ -83,14 +86,14 @@ bool PerfSource::prepare() { || !sendTracepointFormat(&mBuffer, SCHED_SWITCH, &printb, &b1) // Only want RAW but not IP on sched_switch and don't want TID on SAMPLE_ID - || !mCountersGroup.add(&mBuffer, 100/**/, PERF_TYPE_TRACEPOINT, schedSwitchId, 1, PERF_SAMPLE_RAW, PERF_GROUP_MMAP | PERF_GROUP_COMM | PERF_GROUP_TASK | PERF_GROUP_SAMPLE_ID_ALL) + || !mCountersGroup.add(&mBuffer, 100/**/, PERF_TYPE_TRACEPOINT, schedSwitchId, 1, PERF_SAMPLE_RAW, PERF_GROUP_MMAP | PERF_GROUP_COMM | PERF_GROUP_TASK | PERF_GROUP_SAMPLE_ID_ALL | PERF_GROUP_PER_CPU) // Only want TID and IP but not RAW on timer - || (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && !mCountersGroup.add(&mBuffer, 99/**/, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP, 0)) + || (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && !mCountersGroup.add(&mBuffer, 99/**/, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP, PERF_GROUP_PER_CPU)) || !gSessionData->perf.enable(&mCountersGroup, &mBuffer) || 0) { - logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.12 or later?", __FUNCTION__, __FILE__, __LINE__); + logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.4 or later?", __FUNCTION__, __FILE__, __LINE__); return false; } @@ -134,7 +137,7 @@ bool PerfSource::prepare() { return false; } - if (!readProc(&mBuffer, &printb, &b1, &b2, &b3)) { + if (!readProc(&mBuffer, true, &printb, &b1, &b2, &b3)) { logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__); return false; } @@ -260,6 +263,7 @@ bool PerfSource::isDone () { void PerfSource::write (Sender *sender) { if (!mSummary.isDone()) { mSummary.write(sender); + gSessionData->mSentSummary = true; } if (!mBuffer.isDone()) { mBuffer.write(sender); diff --git a/tools/gator/daemon/Proc.cpp b/tools/gator/daemon/Proc.cpp index e0b9e2259cf9..9f01770d6609 100644 --- a/tools/gator/daemon/Proc.cpp +++ b/tools/gator/daemon/Proc.cpp @@ -57,14 +57,57 @@ static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf return true; } -static bool readProcTask(Buffer *const buffer, const int pid, const char *const image, DynBuf *const printb, DynBuf *const b) { +static const char *readProcExe(DynBuf *const printb, const int pid, const int tid, DynBuf *const b) { + if (tid == -1 ? !printb->printf("/proc/%i/exe", pid) + : !printb->printf("/proc/%i/task/%i/exe", pid, tid)) { + logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + return NULL; + } + + const int err = b->readlink(printb->getBuf()); + const char *image; + if (err == 0) { + image = strrchr(b->getBuf(), '/'); + if (image == NULL) { + image = b->getBuf(); + } else { + ++image; + } + } else if (err == -ENOENT) { + // readlink /proc/[pid]/exe returns ENOENT for kernel threads + image = "\0"; + } else { + logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__); + return NULL; + } + + // Android apps are run by app_process but the cmdline is changed to reference the actual app name + if (strcmp(image, "app_process") != 0) { + return image; + } + + if (tid == -1 ? !printb->printf("/proc/%i/cmdline", pid) + : !printb->printf("/proc/%i/task/%i/cmdline", pid, tid)) { + logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + return NULL; + } + + if (!b->read(printb->getBuf())) { + logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__); + return NULL; + } + + return b->getBuf(); +} + +static bool readProcTask(Buffer *const buffer, const int pid, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2) { bool result = false; - if (!b->printf("/proc/%i/task", pid)) { + if (!b1->printf("/proc/%i/task", pid)) { logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); return result; } - DIR *task = opendir(b->getBuf()); + DIR *task = opendir(b1->getBuf()); if (task == NULL) { logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__); return result; @@ -84,11 +127,17 @@ static bool readProcTask(Buffer *const buffer, const int pid, const char *const goto fail; } ProcStat ps; - if (!readProcStat(&ps, printb->getBuf(), b)) { + if (!readProcStat(&ps, printb->getBuf(), b1)) { logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__); goto fail; } + const char *const image = readProcExe(printb, pid, tid, b2); + if (image == NULL) { + logg->logMessage("%s(%s:%i): readImage failed", __FUNCTION__, __FILE__, __LINE__); + goto fail; + } + buffer->comm(pid, tid, image, ps.comm); } @@ -100,7 +149,7 @@ static bool readProcTask(Buffer *const buffer, const int pid, const char *const return result; } -bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) { +bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) { bool result = false; DIR *proc = opendir("/proc"); @@ -128,42 +177,29 @@ bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynB goto fail; } - if (!printb->printf("/proc/%i/exe", pid)) { - logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); - goto fail; - } - const int err = b1->readlink(printb->getBuf()); - const char *image; - if (err == 0) { - image = strrchr(b1->getBuf(), '/'); - if (image == NULL) { - image = b1->getBuf(); - } else { - ++image; + if (sendMaps) { + if (!printb->printf("/proc/%i/maps", pid)) { + logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); + goto fail; + } + if (!b2->read(printb->getBuf())) { + logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__); + // This is not a fatal error - the process just doesn't exist any more + continue; } - } else if (err == -ENOENT) { - // readlink /proc/[pid]/exe returns ENOENT for kernel threads - image = "\0"; - } else { - logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__); - goto fail; - } - if (!printb->printf("/proc/%i/maps", pid)) { - logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__); - goto fail; + buffer->maps(pid, pid, b2->getBuf()); } - if (!b2->read(printb->getBuf())) { - logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__); - // This is not a fatal error - the process just doesn't exist any more - continue; - } - - buffer->maps(pid, pid, b2->getBuf()); if (ps.numThreads <= 1) { + const char *const image = readProcExe(printb, pid, -1, b1); + if (image == NULL) { + logg->logMessage("%s(%s:%i): readImage failed", __FUNCTION__, __FILE__, __LINE__); + goto fail; + } + buffer->comm(pid, pid, image, ps.comm); } else { - if (!readProcTask(buffer, pid, image, printb, b3)) { + if (!readProcTask(buffer, pid, printb, b1, b3)) { logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__); goto fail; } diff --git a/tools/gator/daemon/Proc.h b/tools/gator/daemon/Proc.h index 057b6109848a..31c2eecb7aeb 100644 --- a/tools/gator/daemon/Proc.h +++ b/tools/gator/daemon/Proc.h @@ -12,6 +12,6 @@ class Buffer; class DynBuf; -bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3); +bool readProc(Buffer *const buffer, bool sendMaps, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3); #endif // PROC_H diff --git a/tools/gator/daemon/Sender.h b/tools/gator/daemon/Sender.h index 4c359dba82f8..33b6cc3c5d8d 100644 --- a/tools/gator/daemon/Sender.h +++ b/tools/gator/daemon/Sender.h @@ -39,4 +39,4 @@ private: Sender &operator=(const Sender &); }; -#endif //__SENDER_H__ +#endif //__SENDER_H__ diff --git a/tools/gator/daemon/SessionData.cpp b/tools/gator/daemon/SessionData.cpp index c169299af872..14d995fc39fa 100644 --- a/tools/gator/daemon/SessionData.cpp +++ b/tools/gator/daemon/SessionData.cpp @@ -9,6 +9,7 @@ #include "SessionData.h" #include +#include #include "SessionXML.h" #include "Logging.h" @@ -27,6 +28,15 @@ void SessionData::initialize() { mSessionIsActive = false; mLocalCapture = false; mOneShot = false; + mSentSummary = 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); readCpuInfo(); mConfigurationXMLPath = NULL; mSessionXMLPath = NULL; @@ -91,10 +101,9 @@ void SessionData::parseSessionXML(char* xmlString) { void SessionData::readCpuInfo() { char temp[256]; // arbitrarily large amount strcpy(mCoreName, "unknown"); - memset(&mCpuIds, -1, sizeof(mCpuIds)); mMaxCpuId = -1; - FILE* f = fopen("/proc/cpuinfo", "r"); + 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'."); @@ -102,10 +111,18 @@ void SessionData::readCpuInfo() { } bool foundCoreName = false; - int processor = 0; + int processor = -1; while (fgets(temp, sizeof(temp), f)) { - if (strlen(temp) > 0) { - temp[strlen(temp) - 1] = 0; // Replace the line feed with a null + 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) { + temp[len - 1] = '\0'; // Replace the line feed with a null } const bool foundHardware = strstr(temp, "Hardware") != 0; @@ -127,10 +144,15 @@ void SessionData::readCpuInfo() { } if (foundCPUPart) { - mCpuIds[processor] = strtol(position, NULL, 0); + 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 (mCpuIds[processor] > mMaxCpuId) { - mMaxCpuId = mCpuIds[processor]; + 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; } } @@ -142,10 +164,23 @@ void SessionData::readCpuInfo() { if (!foundCoreName) { logg->logMessage("Could not determine core name from /proc/cpuinfo\n" - "The core name in the captured xml file will be 'unknown'."); + "The core name in the captured xml file will be 'unknown'."); } fclose(f); - } +} + +uint64_t getTime() { + struct timespec ts; +#ifndef CLOCK_MONOTONIC_RAW + // Android doesn't have this defined but it was added in Linux 2.6.28 +#define CLOCK_MONOTONIC_RAW 4 +#endif + 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 diff --git a/tools/gator/daemon/SessionData.h b/tools/gator/daemon/SessionData.h index ea34240e2df7..835082d86c4b 100644 --- a/tools/gator/daemon/SessionData.h +++ b/tools/gator/daemon/SessionData.h @@ -13,12 +13,16 @@ #include "Config.h" #include "Counter.h" +#include "FSDriver.h" #include "Hwmon.h" +#include "MaliVideoDriver.h" #include "PerfDriver.h" -#define PROTOCOL_VERSION 18 +#define PROTOCOL_VERSION 19 #define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions +#define NS_PER_S ((uint64_t)1000000000) + struct ImageLinkList { char* path; struct ImageLinkList *next; @@ -32,9 +36,12 @@ public: ~SessionData(); void initialize(); void parseSessionXML(char* xmlString); + void readCpuInfo(); Hwmon hwmon; + FSDriver fsDriver; PerfDriver perf; + MaliVideoDriver maliVideo; char mCoreName[MAX_STRING_LEN]; struct ImageLinkList *mImages; @@ -49,7 +56,8 @@ public: bool mLocalCapture; bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled bool mIsEBS; - + bool mSentSummary; + int mBacktraceDepth; int mTotalBufferSize; // number of MB to use for the entire collection buffer int mSampleRate; @@ -57,7 +65,7 @@ public: int mDuration; int mCores; int mPageSize; - int mCpuIds[NR_CPUS]; + int *mCpuIds; int mMaxCpuId; // PMU Counters @@ -65,8 +73,6 @@ public: Counter mCounters[MAX_PERFORMANCE_COUNTERS]; private: - void readCpuInfo(); - // Intentionally unimplemented SessionData(const SessionData &); SessionData &operator=(const SessionData &); @@ -74,6 +80,7 @@ private: extern SessionData* gSessionData; +uint64_t getTime(); int getEventKey(); #endif // SESSION_DATA_H diff --git a/tools/gator/daemon/SessionXML.cpp b/tools/gator/daemon/SessionXML.cpp index 55b2f9280709..8cdc9409ca21 100644 --- a/tools/gator/daemon/SessionXML.cpp +++ b/tools/gator/daemon/SessionXML.cpp @@ -17,15 +17,15 @@ #include "SessionData.h" static const char* TAG_SESSION = "session"; -static const char* TAG_IMAGE = "image"; +static const char* TAG_IMAGE = "image"; -static const char* ATTR_VERSION = "version"; +static const char* ATTR_VERSION = "version"; 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_SAMPLE_RATE = "sample_rate"; static const char* ATTR_DURATION = "duration"; static const char* ATTR_PATH = "path"; -static const char* ATTR_LIVE_RATE = "live_rate"; +static const char* ATTR_LIVE_RATE = "live_rate"; SessionXML::SessionXML(const char *str) { parameters.buffer_mode[0] = 0; diff --git a/tools/gator/daemon/StreamlineSetup.cpp b/tools/gator/daemon/StreamlineSetup.cpp index caa665e67193..2b61eaeb290d 100644 --- a/tools/gator/daemon/StreamlineSetup.cpp +++ b/tools/gator/daemon/StreamlineSetup.cpp @@ -266,7 +266,7 @@ void StreamlineSetup::writeConfiguration(char* xml) { { ConfigurationXML configuration; } if (gSessionData->mCounterOverflow > 0) { - logg->logError(__FILE__, __LINE__, "Only %i performance counters counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow); + logg->logError(__FILE__, __LINE__, "Only %i performance counters are permitted, %i are selected", MAX_PERFORMANCE_COUNTERS, gSessionData->mCounterOverflow); handleException(); } } diff --git a/tools/gator/daemon/StreamlineSetup.h b/tools/gator/daemon/StreamlineSetup.h index 74bb197e35ff..b380f46b98f0 100644 --- a/tools/gator/daemon/StreamlineSetup.h +++ b/tools/gator/daemon/StreamlineSetup.h @@ -21,7 +21,7 @@ enum { COMMAND_APC_START = 2, COMMAND_APC_STOP = 3, COMMAND_DISCONNECT = 4, - COMMAND_PING = 5 + COMMAND_PING = 5 }; class StreamlineSetup { @@ -47,4 +47,4 @@ private: StreamlineSetup &operator=(const StreamlineSetup &); }; -#endif //__STREAMLINE_SETUP_H__ +#endif //__STREAMLINE_SETUP_H__ diff --git a/tools/gator/daemon/UEvent.cpp b/tools/gator/daemon/UEvent.cpp index 282e965fa67a..54d45751e3c9 100644 --- a/tools/gator/daemon/UEvent.cpp +++ b/tools/gator/daemon/UEvent.cpp @@ -8,11 +8,12 @@ #include "UEvent.h" -#include #include #include #include +#include + #include "Logging.h" static const char EMPTY[] = ""; diff --git a/tools/gator/daemon/UserSpaceSource.cpp b/tools/gator/daemon/UserSpaceSource.cpp index debe69636cff..8c328e0e0fb5 100644 --- a/tools/gator/daemon/UserSpaceSource.cpp +++ b/tools/gator/daemon/UserSpaceSource.cpp @@ -16,7 +16,6 @@ #include "Logging.h" #include "SessionData.h" -#define NS_PER_S ((uint64_t)1000000000) #define NS_PER_US 1000 extern Child *child; @@ -35,6 +34,7 @@ void UserSpaceSource::run() { prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0); gSessionData->hwmon.start(); + gSessionData->fsDriver.start(); int64_t monotonic_started = 0; while (monotonic_started <= 0) { @@ -48,16 +48,7 @@ void UserSpaceSource::run() { uint64_t next_time = 0; while (gSessionData->mSessionIsActive) { - struct timespec ts; -#ifndef CLOCK_MONOTONIC_RAW - // Android doesn't have this defined but it was added in Linux 2.6.28 -#define CLOCK_MONOTONIC_RAW 4 -#endif - if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) { - logg->logError(__FILE__, __LINE__, "Failed to get uptime"); - handleException(); - } - const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started; + const uint64_t curr_time = getTime() - monotonic_started; // Sample ten times a second ignoring gSessionData->mSampleRate next_time += NS_PER_S/10;//gSessionData->mSampleRate; if (next_time < curr_time) { @@ -67,6 +58,7 @@ void UserSpaceSource::run() { if (mBuffer.eventHeader(curr_time)) { gSessionData->hwmon.read(&mBuffer); + gSessionData->fsDriver.read(&mBuffer); // Only check after writing all counters so that time and corresponding counters appear in the same frame mBuffer.check(curr_time); } diff --git a/tools/gator/daemon/UserSpaceSource.h b/tools/gator/daemon/UserSpaceSource.h index fb5889d26ffb..9b3666016dc5 100644 --- a/tools/gator/daemon/UserSpaceSource.h +++ b/tools/gator/daemon/UserSpaceSource.h @@ -14,7 +14,7 @@ #include "Buffer.h" #include "Source.h" -// User space counters - currently just hwmon +// User space counters class UserSpaceSource : public Source { public: UserSpaceSource(sem_t *senderSem); diff --git a/tools/gator/daemon/c++.cpp b/tools/gator/daemon/c++.cpp new file mode 100644 index 000000000000..6041e5e96469 --- /dev/null +++ b/tools/gator/daemon/c++.cpp @@ -0,0 +1,40 @@ +/** + * Minimal set of C++ functions so that libstdc++ is not required + * + * 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 +#include + +void operator delete(void *ptr) { + if (ptr != NULL) { + free(ptr); + } +} + +void operator delete[](void *ptr) { + operator delete(ptr); +} + +void *operator new(size_t size) { + void *ptr = malloc(size == 0 ? 1 : size); + if (ptr == NULL) { + abort(); + } + return ptr; +} + +void *operator new[](size_t size) { + return operator new(size); +} + +extern "C" +void __cxa_pure_virtual() { + printf("pure virtual method called\n"); + abort(); +} diff --git a/tools/gator/daemon/common.mk b/tools/gator/daemon/common.mk index d9dc14606b07..769a92e51a35 100644 --- a/tools/gator/daemon/common.mk +++ b/tools/gator/daemon/common.mk @@ -5,16 +5,17 @@ # -Werror treats warnings as errors # -std=c++0x is the planned new c++ standard # -std=c++98 is the 1998 c++ standard -CFLAGS += -O3 -Wall -fno-exceptions -pthread -MMD -DETCDIR=\"/etc\" -Ilibsensors +CPPFLAGS += -O3 -Wall -fno-exceptions -pthread -MMD -DETCDIR=\"/etc\" -Ilibsensors CXXFLAGS += -fno-rtti -Wextra # -Weffc++ ifeq ($(WERROR),1) - CFLAGS += -Werror + CPPFLAGS += -Werror endif # -s strips the binary of debug info LDFLAGS += -s +LDLIBS += -lrt -lm -pthread TARGET = gatord C_SRC = $(wildcard mxml/*.c) $(wildcard libsensors/*.c) -CPP_SRC = $(wildcard *.cpp) +CXX_SRC = $(wildcard *.cpp) all: $(TARGET) @@ -35,14 +36,15 @@ libsensors/conf-parse.c: ; ./escape $< > $@ %.o: %.c - $(GCC) -c $(CFLAGS) -o $@ $< + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< %.o: %.cpp - $(CPP) -c $(CFLAGS) $(CXXFLAGS) -o $@ $< + $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< -$(TARGET): $(CPP_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o) - $(CPP) $(LDFLAGS) -o $@ $^ -lrt -pthread +$(TARGET): $(CXX_SRC:%.cpp=%.o) $(C_SRC:%.c=%.o) + $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ +# Intentionally ignore CC as a native binary is required escape: escape.c gcc $^ -o $@ diff --git a/tools/gator/daemon/defaults.xml b/tools/gator/daemon/defaults.xml index 5bf096cb2a45..39a0f656f7e6 100644 --- a/tools/gator/daemon/defaults.xml +++ b/tools/gator/daemon/defaults.xml @@ -58,5 +58,10 @@ + + + + + diff --git a/tools/gator/daemon/escape.c b/tools/gator/daemon/escape.c index c54aa1c3e75d..2b0863aaf425 100644 --- a/tools/gator/daemon/escape.c +++ b/tools/gator/daemon/escape.c @@ -6,7 +6,7 @@ * published by the Free Software Foundation. */ -/* +/* * The Makefile in the daemon folder builds and executes 'escape' * 'escape' creates configuration_xml.h from configuration.xml and events_xml.h from events-*.xml * these genereated xml files are then #included and built as part of the gatord binary diff --git a/tools/gator/daemon/events-CCI-400.xml b/tools/gator/daemon/events-CCI-400.xml index 4fa77117d2d8..20002efd1543 100644 --- a/tools/gator/daemon/events-CCI-400.xml +++ b/tools/gator/daemon/events-CCI-400.xml @@ -1,7 +1,6 @@ - - - - + + + - @@ -30,13 +28,11 @@ - - @@ -45,11 +41,9 @@ - - - - - + + + - @@ -79,13 +72,11 @@ - - diff --git a/tools/gator/daemon/events-CCN-504.xml b/tools/gator/daemon/events-CCN-504.xml index cfabf65949ed..6ef3e6483717 100644 --- a/tools/gator/daemon/events-CCN-504.xml +++ b/tools/gator/daemon/events-CCN-504.xml @@ -1,7 +1,6 @@ - - @@ -56,7 +54,6 @@ - - @@ -82,7 +78,6 @@ - - @@ -102,14 +96,12 @@ - - @@ -118,5 +110,4 @@ - diff --git a/tools/gator/daemon/events-Cortex-A53.xml b/tools/gator/daemon/events-Cortex-A53.xml index 577dcd94185e..5ba17907d5ab 100644 --- a/tools/gator/daemon/events-Cortex-A53.xml +++ b/tools/gator/daemon/events-Cortex-A53.xml @@ -1,171 +1,87 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/gator/daemon/events-Cortex-A57.xml b/tools/gator/daemon/events-Cortex-A57.xml index b7178c0c7427..fbe96c2d4eb2 100644 --- a/tools/gator/daemon/events-Cortex-A57.xml +++ b/tools/gator/daemon/events-Cortex-A57.xml @@ -1,171 +1,87 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/gator/daemon/events-Filesystem.xml b/tools/gator/daemon/events-Filesystem.xml new file mode 100644 index 000000000000..5feeb9014a63 --- /dev/null +++ b/tools/gator/daemon/events-Filesystem.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/tools/gator/daemon/events-L2C-310.xml b/tools/gator/daemon/events-L2C-310.xml index 4da4d1d63431..923fb90334d0 100644 --- a/tools/gator/daemon/events-L2C-310.xml +++ b/tools/gator/daemon/events-L2C-310.xml @@ -1,18 +1,18 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/tools/gator/daemon/events-Linux.xml b/tools/gator/daemon/events-Linux.xml index 4d677e15db7e..c306dd62208e 100644 --- a/tools/gator/daemon/events-Linux.xml +++ b/tools/gator/daemon/events-Linux.xml @@ -11,7 +11,6 @@ - - + + - diff --git a/tools/gator/daemon/events-Mali-4xx.xml b/tools/gator/daemon/events-Mali-4xx.xml index 5a71386830ba..0a95dfeb6485 100644 --- a/tools/gator/daemon/events-Mali-4xx.xml +++ b/tools/gator/daemon/events-Mali-4xx.xml @@ -1,34 +1,33 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -37,7 +36,6 @@ - @@ -96,11 +94,10 @@ - - + + - - - @@ -131,10 +126,9 @@ - - - - + + + - - - - - - - - - - - + + + + + + + + + - - - - + + + - - - - - - - - - - - + + + + + + + + + - + +