From 9b0375410d73fb0de515ee33e0dd7f054cd45a6f Mon Sep 17 00:00:00 2001 From: Drew Richardson Date: Mon, 16 Dec 2013 12:00:00 -0800 Subject: gator: Version 5.17 Signed-off-by: Drew Richardson --- README_Streamline.txt | 23 +- daemon/Buffer.cpp | 11 + daemon/Buffer.h | 5 + daemon/Child.cpp | 13 +- daemon/Child.h | 4 + daemon/ConfigurationXML.h | 4 + daemon/Driver.h | 6 +- daemon/Fifo.h | 4 + daemon/Hwmon.cpp | 4 + daemon/Hwmon.h | 4 + daemon/OlySocket.cpp | 23 +- daemon/Sender.h | 4 + daemon/SessionData.cpp | 12 +- daemon/SessionData.h | 6 +- daemon/SessionXML.h | 4 + daemon/StreamlineSetup.h | 4 + daemon/common.mk | 2 +- daemon/events-CCI-400.xml | 62 ++++- daemon/events-Linux.xml | 10 +- daemon/events-Mali-T6xx.xml | 10 + daemon/events-Mali-T6xx_hw.xml | 5 +- daemon/main.cpp | 25 +- driver/Makefile | 61 ++--- driver/gator.h | 6 +- driver/gator_annotate_kernel.c | 107 ++++++--- driver/gator_backtrace.c | 10 +- driver/gator_cookies.c | 36 ++- driver/gator_events.sh | 19 -- driver/gator_events_armv6.c | 7 - driver/gator_events_armv7.c | 7 - driver/gator_events_block.c | 2 - driver/gator_events_ccn-504.c | 192 +++++++++------ driver/gator_events_irq.c | 2 - driver/gator_events_l2c-310.c | 2 - driver/gator_events_mali_4xx.c | 30 +-- driver/gator_events_mali_common.c | 9 +- driver/gator_events_mali_common.h | 4 +- driver/gator_events_mali_t6xx.c | 60 ++++- driver/gator_events_mali_t6xx_hw.c | 46 +++- driver/gator_events_meminfo.c | 301 ++++++++++++++++++------ driver/gator_events_mmaped.c | 229 ------------------ driver/gator_events_mmapped.c | 209 ++++++++++++++++ driver/gator_events_net.c | 5 +- driver/gator_events_perf_pmu.c | 83 ++++++- driver/gator_events_sched.c | 2 - driver/gator_events_scorpion.c | 7 - driver/gator_main.c | 108 ++++++++- driver/gator_marshaling.c | 19 ++ driver/gator_trace_gpu.c | 6 +- driver/gator_trace_sched.c | 20 +- driver/mali/mali_mjollnir_profiling_gator_api.h | 15 +- driver/mali/mali_utgard_profiling_gator_api.h | 15 +- driver/mali_t6xx.mk | 11 +- 53 files changed, 1233 insertions(+), 642 deletions(-) delete mode 100644 driver/gator_events.sh delete mode 100644 driver/gator_events_mmaped.c create mode 100644 driver/gator_events_mmapped.c diff --git a/README_Streamline.txt b/README_Streamline.txt index 744c33f..99b70bd 100644 --- a/README_Streamline.txt +++ b/README_Streamline.txt @@ -2,12 +2,12 @@ *** Purpose *** Instructions on setting up ARM Streamline on the target. -The gator driver and gator daemon are required to run on the ARM linux target in order for ARM Streamline to operate. +The gator driver and gator daemon are required to run on the ARM Linux target in order for ARM Streamline to operate. The driver should be built as a module and the daemon must run with root permissions on the target. *** Introduction *** -A linux development environment with cross compiling tools is most likely required, depending on what is already created and provided. +A Linux development environment with cross compiling tools is most likely required, depending on what is already created and provided. -For users, the ideal environment is to be given a BSP with gatord and gator.ko already running on a properly configured kernel. In such a scenario, a development environment is not needed, root permission may or may not be needed (gatord must be executed with root permissions but can be automatically started, see below), and the user can run Streamline and profile the system without any setup. -The ideal development environment has the kernel source code available to be rebuilt, usually by cross-compiling on a host machine. This environment allows the greatest flexibility in configuring the kernel and building the gator driver module. -However, it is possible that a user/developer has a kernel but does not have the source code. In this scenario it may or may not be possible to obtain a valid profile. @@ -49,6 +49,8 @@ These may be verified on a running system using /proc/config.gz (if this file ex > zcat /proc/config.gz | grep CONFIG_PROFILING CONFIG_PROFILING=y +If a device tree is used it must include the pmu bindings, see Documentation/devicetree/bindings/arm/pmu.txt for details. + *** Checking the gator requirements *** (optional) Use the hrtimer_module utility to validate the kernel High Resolution Timer requirement. @@ -64,6 +66,17 @@ for example when using the linaro-toolchain-binaries make -C /home/username/kernel_2.6.32/ M=`pwd` ARCH=arm CROSS_COMPILE=/home/username/gcc-linaro-arm-linux-gnueabihf-4.7-2013.01-20130125_linux/bin/arm-linux-gnueabihf- modules If successful, a gator.ko module should be generated +It is also possible to integrate the gator.ko module into the kernel build system + cd /path/to/kernel/build/dir + cd drivers + mkdir gator + cp -r /path/to/gator/driver-src/* gator +Edit Makefile in the kernel drivers folder and add this to the end + obj-$(CONFIG_GATOR) += gator/ +Edit Kconfig in the kernel drivers folder and add this before the last endmenu + source "drivers/gator/Kconfig" +You can now select gator when using menuconfig while configuring the kernel and rebuild as directed + *** Building the gator daemon *** cd /path/to/gator/daemon-src @@ -96,6 +109,10 @@ The l2c-310 counter in gator_events_l2c-310.c contains hard coded offsets where Further, the l2c-310 counter can be disabled by providing an offset of zero, ex: insmod gator.ko l2c310_addr=0 +*** CCN-504 *** + +CCN-504 is disabled by default. To enable CCN-504, insmod gator module with the ccn504_addr= parameter where addr is the base address of the CCN-504 configuration register space (PERIPHBASE), ex: insmod gator.ko ccn504_addr=0x2E000000. + *** Compiling an application or shared library *** Recommended compiler settings: @@ -124,7 +141,7 @@ To work around the issue try upgrading to a later kernel or comment out the gato CONFIG_DEBUG_INFO must be enabled, see "Kernel configuration" section above. Use vmlinux as the image for debug symbols in Streamline. Drivers may be profiled using this method by statically linking the driver into the kernel image or adding the driver as an image to Streamline. -To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko. +To perform kernel stack unwinding and module unwinding, edit the Makefile to enable GATOR_KERNEL_STACK_UNWINDING and rebuild gator.ko or run "echo 1 > /sys/module/gator/parameters/kernel_stack_unwinding" as root on the target after gatord is started. *** Automatically start gator on boot (optional) *** diff --git a/daemon/Buffer.cpp b/daemon/Buffer.cpp index c7abbf3..090a715 100644 --- a/daemon/Buffer.cpp +++ b/daemon/Buffer.cpp @@ -193,6 +193,17 @@ bool Buffer::eventHeader (const uint64_t curr_time) { return retval; } +bool Buffer::eventTid (const int tid) { + bool retval = false; + if (checkSpace(2*MAXSIZE_PACK32)) { + packInt(1); // key of 1 indicates a tid + packInt(tid); + retval = true; + } + + return retval; +} + void Buffer::event (const int32_t key, const int32_t value) { if (checkSpace(2 * MAXSIZE_PACK32)) { packInt(key); diff --git a/daemon/Buffer.h b/daemon/Buffer.h index f820cfd..b3c8d78 100644 --- a/daemon/Buffer.h +++ b/daemon/Buffer.h @@ -32,6 +32,7 @@ public: void frame (); bool eventHeader (uint64_t curr_time); + bool eventTid (int tid); void event (int32_t key, int32_t value); void event64 (int64_t key, int64_t value); @@ -56,6 +57,10 @@ private: char *const buf; uint64_t commitTime; sem_t *const readerSem; + + // Intentionally unimplemented + Buffer(const Buffer &); + Buffer &operator=(const Buffer &); }; #endif // BUFFER_H diff --git a/daemon/Child.cpp b/daemon/Child.cpp index c054076..9ee2ef8 100644 --- a/daemon/Child.cpp +++ b/daemon/Child.cpp @@ -86,7 +86,7 @@ static void child_handler(int signum) { } } -static void* durationThread(void* pVoid) { +static void *durationThread(void *) { prctl(PR_SET_NAME, (unsigned long)&"gatord-duration", 0, 0, 0); sem_wait(&startProfile); if (gSessionData->mSessionIsActive) { @@ -102,7 +102,7 @@ static void* durationThread(void* pVoid) { return 0; } -static void* stopThread(void* pVoid) { +static void *stopThread(void *) { OlySocket* socket = child->socket; prctl(PR_SET_NAME, (unsigned long)&"gatord-stopper", 0, 0, 0); @@ -139,7 +139,7 @@ static void* stopThread(void* pVoid) { return 0; } -void* countersThread(void* pVoid) { +static void *countersThread(void *) { prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0); gSessionData->hwmon.start(); @@ -192,7 +192,7 @@ void* countersThread(void* pVoid) { return NULL; } -static void* senderThread(void* pVoid) { +static void *senderThread(void *) { int length = 1; char* data; char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0}; @@ -340,7 +340,8 @@ void Child::run() { thread_creation_success = false; } - if (gSessionData->hwmon.countersEnabled()) { + bool startcountersThread = gSessionData->hwmon.countersEnabled(); + if (startcountersThread) { if (pthread_create(&countersThreadID, NULL, countersThread, this)) { thread_creation_success = false; } @@ -378,7 +379,7 @@ void Child::run() { } while (bytesCollected > 0); logg->logMessage("Exit collect data loop"); - if (gSessionData->hwmon.countersEnabled()) { + if (startcountersThread) { pthread_join(countersThreadID, NULL); } diff --git a/daemon/Child.h b/daemon/Child.h index e39d182..0330e9d 100644 --- a/daemon/Child.h +++ b/daemon/Child.h @@ -26,6 +26,10 @@ private: int mNumConnections; void initialization(); + + // Intentionally unimplemented + Child(const Child &); + Child &operator=(const Child &); }; #endif //__CHILD_H__ diff --git a/daemon/ConfigurationXML.h b/daemon/ConfigurationXML.h index eba7dc4..5650f48 100644 --- a/daemon/ConfigurationXML.h +++ b/daemon/ConfigurationXML.h @@ -29,6 +29,10 @@ private: int parse(const char* xmlFile); int configurationsTag(mxml_node_t *node); void configurationTag(mxml_node_t *node); + + // Intentionally unimplemented + ConfigurationXML(const ConfigurationXML &); + ConfigurationXML &operator=(const ConfigurationXML &); }; #endif // COUNTERS_H diff --git a/daemon/Driver.h b/daemon/Driver.h index dd1dc27..f3a932f 100644 --- a/daemon/Driver.h +++ b/daemon/Driver.h @@ -29,7 +29,7 @@ public: // Emits available counters virtual void writeCounters(mxml_node_t *root) const = 0; // Emits possible dynamically generated events/counters - virtual void writeEvents(mxml_node_t *root) const {} + virtual void writeEvents(mxml_node_t *) const {} Driver *getNext() const { return next; } @@ -39,6 +39,10 @@ protected: private: static Driver *head; Driver *next; + + // Intentionally unimplemented + Driver(const Driver &); + Driver &operator=(const Driver &); }; #endif // DRIVER_H diff --git a/daemon/Fifo.h b/daemon/Fifo.h index ada42b9..d25cd68 100644 --- a/daemon/Fifo.h +++ b/daemon/Fifo.h @@ -39,6 +39,10 @@ private: sem_t* mReaderSem; char* mBuffer; bool mEnd; + + // Intentionally unimplemented + Fifo(const Fifo &); + Fifo &operator=(const Fifo &); }; #endif //__FIFO_H__ diff --git a/daemon/Hwmon.cpp b/daemon/Hwmon.cpp index 0792568..1d7c0da 100644 --- a/daemon/Hwmon.cpp +++ b/daemon/Hwmon.cpp @@ -63,6 +63,10 @@ private: double previous_value; sensors_subfeature_type input; + + // Intentionally unimplemented + HwmonCounter(const HwmonCounter &); + HwmonCounter &operator=(const HwmonCounter &); }; HwmonCounter::HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(key), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) { diff --git a/daemon/Hwmon.h b/daemon/Hwmon.h index 35981dc..46bb42e 100644 --- a/daemon/Hwmon.h +++ b/daemon/Hwmon.h @@ -34,6 +34,10 @@ private: HwmonCounter *findCounter(const Counter &counter) const; HwmonCounter *counters; + + // Intentionally unimplemented + Hwmon(const Hwmon &); + Hwmon &operator=(const Hwmon &); }; #endif // HWMON_H diff --git a/daemon/OlySocket.cpp b/daemon/OlySocket.cpp index 132510d..ab5c3c2 100644 --- a/daemon/OlySocket.cpp +++ b/daemon/OlySocket.cpp @@ -11,6 +11,7 @@ #include #ifdef WIN32 #include +#include #else #include #include @@ -126,11 +127,17 @@ void OlySocket::createSingleServerConnection(int port) { } void OlySocket::createServerSocket(int port) { + int family = AF_INET6; + // Create socket - mFDServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + mFDServer = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); if (mFDServer < 0) { - logg->logError(__FILE__, __LINE__, "Error creating server socket"); - handleException(); + family = AF_INET; + mFDServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (mFDServer < 0) { + logg->logError(__FILE__, __LINE__, "Error creating server socket"); + handleException(); + } } // Enable address reuse, another solution would be to create the server socket once and only close it when the object exits @@ -141,11 +148,11 @@ void OlySocket::createServerSocket(int port) { } // Create sockaddr_in structure, ensuring non-populated fields are zero - struct sockaddr_in sockaddr; - memset((void*)&sockaddr, 0, sizeof(struct sockaddr_in)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(port); - sockaddr.sin_addr.s_addr = INADDR_ANY; + struct sockaddr_in6 sockaddr; + memset((void*)&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin6_family = family; + sockaddr.sin6_port = htons(port); + sockaddr.sin6_addr = in6addr_any; // Bind the socket to an address if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) { diff --git a/daemon/Sender.h b/daemon/Sender.h index 8f23361..b388f03 100644 --- a/daemon/Sender.h +++ b/daemon/Sender.h @@ -33,6 +33,10 @@ private: FILE* mDataFile; char* mDataFileName; pthread_mutex_t mSendMutex; + + // Intentionally unimplemented + Sender(const Sender &); + Sender &operator=(const Sender &); }; #endif //__SENDER_H__ diff --git a/daemon/SessionData.cpp b/daemon/SessionData.cpp index 4068d4e..cf84407 100644 --- a/daemon/SessionData.cpp +++ b/daemon/SessionData.cpp @@ -44,13 +44,13 @@ void SessionData::parseSessionXML(char* xmlString) { SessionXML session(xmlString); session.parse(); - // Set session data values + // Set session data values - use prime numbers just below the desired value to reduce the chance of events firing at the same time if (strcmp(session.parameters.sample_rate, "high") == 0) { - mSampleRate = 10000; + mSampleRate = 9973; // 10000 } else if (strcmp(session.parameters.sample_rate, "normal") == 0) { - mSampleRate = 1000; + mSampleRate = 997; // 1000 } else if (strcmp(session.parameters.sample_rate, "low") == 0) { - mSampleRate = 100; + mSampleRate = 97; // 100 } else if (strcmp(session.parameters.sample_rate, "none") == 0) { mSampleRate = 0; } else { @@ -139,7 +139,9 @@ void SessionData::readCpuInfo() { } int getEventKey() { - // Start one after the gator.ko's value of 1 + // key 0 is reserved as a timestamp + // key 1 is reserved as the marker for thread specific counters + // Odd keys are assigned by the driver, even keys by the daemon static int key = 2; const int ret = key; diff --git a/daemon/SessionData.h b/daemon/SessionData.h index e72fa5d..c834251 100644 --- a/daemon/SessionData.h +++ b/daemon/SessionData.h @@ -16,7 +16,7 @@ #define MAX_PERFORMANCE_COUNTERS 50 -#define PROTOCOL_VERSION 16 +#define PROTOCOL_VERSION 17 #define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions struct ImageLinkList { @@ -62,6 +62,10 @@ public: private: void readCpuInfo(); + + // Intentionally unimplemented + SessionData(const SessionData &); + SessionData &operator=(const SessionData &); }; extern SessionData* gSessionData; diff --git a/daemon/SessionXML.h b/daemon/SessionXML.h index c7e3798..0fb03bd 100644 --- a/daemon/SessionXML.h +++ b/daemon/SessionXML.h @@ -33,6 +33,10 @@ private: char* mPath; void sessionTag(mxml_node_t *tree, mxml_node_t *node); void sessionImage(mxml_node_t *node); + + // Intentionally unimplemented + SessionXML(const SessionXML &); + SessionXML &operator=(const SessionXML &); }; #endif // SESSION_XML_H diff --git a/daemon/StreamlineSetup.h b/daemon/StreamlineSetup.h index 092d956..d6d9a6e 100644 --- a/daemon/StreamlineSetup.h +++ b/daemon/StreamlineSetup.h @@ -38,6 +38,10 @@ private: void sendDefaults(); void sendCounters(); void writeConfiguration(char* xml); + + // Intentionally unimplemented + StreamlineSetup(const StreamlineSetup &); + StreamlineSetup &operator=(const StreamlineSetup &); }; #endif //__STREAMLINE_SETUP_H__ diff --git a/daemon/common.mk b/daemon/common.mk index ee2415b..031d169 100644 --- a/daemon/common.mk +++ b/daemon/common.mk @@ -6,7 +6,7 @@ # -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 -CXXFLAGS += -fno-rtti +CXXFLAGS += -fno-rtti -Wextra # -Weffc++ ifeq ($(WERROR),1) CFLAGS += -Werror endif diff --git a/daemon/events-CCI-400.xml b/daemon/events-CCI-400.xml index 86db208..4fa7711 100644 --- a/daemon/events-CCI-400.xml +++ b/daemon/events-CCI-400.xml @@ -17,7 +17,7 @@ - + @@ -45,3 +45,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/daemon/events-Linux.xml b/daemon/events-Linux.xml index 4a30ad6..31a90a1 100644 --- a/daemon/events-Linux.xml +++ b/daemon/events-Linux.xml @@ -6,11 +6,11 @@ - - - - - + + + + + diff --git a/daemon/events-Mali-T6xx.xml b/daemon/events-Mali-T6xx.xml index 647e3d5..2465238 100644 --- a/daemon/events-Mali-T6xx.xml +++ b/daemon/events-Mali-T6xx.xml @@ -36,3 +36,13 @@ + + + + + + + diff --git a/daemon/events-Mali-T6xx_hw.xml b/daemon/events-Mali-T6xx_hw.xml index 8cfe7c3..03566cb 100644 --- a/daemon/events-Mali-T6xx_hw.xml +++ b/daemon/events-Mali-T6xx_hw.xml @@ -60,12 +60,15 @@ - + + + + diff --git a/daemon/main.cpp b/daemon/main.cpp index d1b0913..bfd36b9 100644 --- a/daemon/main.cpp +++ b/daemon/main.cpp @@ -93,7 +93,7 @@ static void handler(int signum) { } // Child exit Signal Handler -static void child_exit(int signum) { +static void child_exit(int) { int status; int pid = wait(&status); if (pid != -1) { @@ -106,13 +106,18 @@ static void child_exit(int signum) { static int udpPort(int port) { int s; - struct sockaddr_in sockaddr; + struct sockaddr_in6 sockaddr; int on; + int family = AF_INET6; - s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (s == -1) { - logg->logError(__FILE__, __LINE__, "socket failed"); - handleException(); + family = AF_INET; + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s == -1) { + logg->logError(__FILE__, __LINE__, "socket failed"); + handleException(); + } } on = 1; @@ -122,9 +127,9 @@ static int udpPort(int port) { } memset((void*)&sockaddr, 0, sizeof(sockaddr)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(port); - sockaddr.sin_addr.s_addr = INADDR_ANY; + sockaddr.sin6_family = family; + sockaddr.sin6_port = htons(port); + sockaddr.sin6_addr = in6addr_any; if (bind(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { logg->logError(__FILE__, __LINE__, "socket failed"); handleException(); @@ -173,7 +178,7 @@ static void* answerThread(void* pVoid) { for (;;) { char buf[128]; - struct sockaddr_in sockaddr; + struct sockaddr_in6 sockaddr; socklen_t addrlen; int read; addrlen = sizeof(sockaddr); @@ -386,7 +391,7 @@ static struct cmdline_t parseCommandLine(int argc, char** argv) { } // Gator data flow: collector -> collector fifo -> sender -int main(int argc, char** argv, char* envp[]) { +int main(int argc, char** argv) { // Ensure proper signal handling by making gatord the process group leader // e.g. it may not be the group leader when launched as 'sudo gatord' setsid(); diff --git a/driver/Makefile b/driver/Makefile index 0d4ca68..3dc9d05 100644 --- a/driver/Makefile +++ b/driver/Makefile @@ -3,7 +3,8 @@ ifneq ($(KERNELRELEASE),) # Uncomment the following line to enable kernel stack unwinding within gator, or update gator_backtrace.c # EXTRA_CFLAGS += -DGATOR_KERNEL_STACK_UNWINDING -obj-m := gator.o +CONFIG_GATOR ?= m +obj-$(CONFIG_GATOR) := gator.o gator-y := gator_main.o \ gator_events_irq.o \ @@ -11,23 +12,40 @@ gator-y := gator_main.o \ gator_events_net.o \ gator_events_block.o \ gator_events_meminfo.o \ - gator_events_perf_pmu.o - -gator-y += gator_events_mmaped.o + gator_events_perf_pmu.o \ + gator_events_mmapped.o \ +# Convert the old GATOR_WITH_MALI_SUPPORT to the new kernel flags ifneq ($(GATOR_WITH_MALI_SUPPORT),) -ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx) -gator-y += gator_events_mali_t6xx.o \ - gator_events_mali_t6xx_hw.o -include $(M)/mali_t6xx.mk -else -gator-y += gator_events_mali_4xx.o -endif -gator-y += gator_events_mali_common.o -EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT) -ifneq ($(GATOR_MALI_INTERFACE_STYLE),) -EXTRA_CFLAGS += -DGATOR_MALI_INTERFACE_STYLE=$(GATOR_MALI_INTERFACE_STYLE) + CONFIG_GATOR_WITH_MALI_SUPPORT := y + ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx) + CONFIG_GATOR_MALI_4XXMP := n + CONFIG_GATOR_MALI_T6XX := y + else + CONFIG_GATOR_MALI_4XXMP := y + CONFIG_GATOR_MALI_T6XX := n + endif + EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT) + ifneq ($(GATOR_MALI_INTERFACE_STYLE),) + EXTRA_CFLAGS += -DGATOR_MALI_INTERFACE_STYLE=$(GATOR_MALI_INTERFACE_STYLE) + endif endif + +ifeq ($(CONFIG_GATOR_WITH_MALI_SUPPORT),y) + ifeq ($(CONFIG_GATOR_MALI_T6XX),y) + gator-y += gator_events_mali_t6xx.o \ + gator_events_mali_t6xx_hw.o + include $(src)/mali_t6xx.mk + else + gator-y += gator_events_mali_4xx.o + endif + gator-y += gator_events_mali_common.o + + ifneq ($(CONFIG_GATOR_MALI_PATH),) + ccflags-y += -I$(CONFIG_GATOR_MALI_PATH) + endif + ccflags-$(CONFIG_GATOR_MALI_4XXMP) += -DMALI_SUPPORT=MALI_4xx + ccflags-$(CONFIG_GATOR_MALI_T6XX) += -DMALI_SUPPORT=MALI_T6xx endif # GATOR_TEST controls whether to include (=1) or exclude (=0) test code. @@ -42,17 +60,6 @@ gator-$(CONFIG_ARM) += gator_events_armv6.o \ gator-$(CONFIG_ARM64) += gator_events_ccn-504.o -$(obj)/gator_main.o: gator_events.h - -clean-files := gator_events.h - - chk_events.h = : - quiet_chk_events.h = echo ' CHK $@' -silent_chk_events.h = : -gator_events.h: FORCE - @$($(quiet)chk_events.h) - $(Q)cd $(obj) ; $(CONFIG_SHELL) $(obj)/gator_events.sh $@ - else all: @@ -63,7 +70,7 @@ all: $(error) clean: - rm -f *.o .*.cmd gator_events.h modules.order Module.symvers gator.ko gator.mod.c + rm -f *.o .*.cmd modules.order Module.symvers gator.ko gator.mod.c rm -rf .tmp_versions endif diff --git a/driver/gator.h b/driver/gator.h index 2e122da..d8981ed 100644 --- a/driver/gator.h +++ b/driver/gator.h @@ -112,14 +112,10 @@ struct gator_interface { void (*offline_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu' int (*read)(int **buffer); int (*read64)(long long **buffer); + int (*read_proc)(long long **buffer, struct task_struct *); struct list_head list; }; -// gator_events_init is used as a search term in gator_events.sh -#define gator_events_init(initfn) \ - static inline int __gator_events_init_test(void) \ - { return initfn(); } - int gator_events_install(struct gator_interface *interface); int gator_events_get_key(void); u32 gator_cpuid(void); diff --git a/driver/gator_annotate_kernel.c b/driver/gator_annotate_kernel.c index 4715f64..a406e48 100644 --- a/driver/gator_annotate_kernel.c +++ b/driver/gator_annotate_kernel.c @@ -29,11 +29,27 @@ static void kannotate_write(const char *ptr, unsigned int size) } } +static void marshal_u16(char *buf, u16 val) { + buf[0] = val & 0xff; + buf[1] = (val >> 8) & 0xff; +} + +static void marshal_u32(char *buf, u32 val) { + buf[0] = val & 0xff; + buf[1] = (val >> 8) & 0xff; + buf[2] = (val >> 16) & 0xff; + buf[3] = (val >> 24) & 0xff; +} + void gator_annotate_channel(int channel, const char *str) { - int str_size = strlen(str) & 0xffff; - long long header = ESCAPE_CODE | (STRING_ANNOTATION << 8) | (channel << 16) | ((long long)str_size << 48); - kannotate_write((char *)&header, sizeof(header)); + const u16 str_size = strlen(str) & 0xffff; + char header[8]; + header[0] = ESCAPE_CODE; + header[1] = STRING_ANNOTATION; + marshal_u32(header + 2, channel); + marshal_u16(header + 6, str_size); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } @@ -48,14 +64,14 @@ EXPORT_SYMBOL(gator_annotate); void gator_annotate_channel_color(int channel, int color, const char *str) { - int str_size = (strlen(str) + 4) & 0xffff; + const u16 str_size = (strlen(str) + 4) & 0xffff; char header[12]; header[0] = ESCAPE_CODE; header[1] = STRING_ANNOTATION; - *(u32 *)(&header[2]) = channel; - *(u16 *)(&header[6]) = str_size; - *(u32 *)(&header[8]) = color; - kannotate_write((char *)&header, sizeof(header)); + marshal_u32(header + 2, channel); + marshal_u16(header + 6, str_size); + marshal_u32(header + 8, color); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size - 4); } @@ -70,8 +86,12 @@ EXPORT_SYMBOL(gator_annotate_color); void gator_annotate_channel_end(int channel) { - long long header = ESCAPE_CODE | (STRING_ANNOTATION << 8) | (channel << 16); - kannotate_write((char *)&header, sizeof(header)); + char header[8]; + header[0] = ESCAPE_CODE; + header[1] = STRING_ANNOTATION; + marshal_u32(header + 2, channel); + marshal_u16(header + 6, 0); + kannotate_write(header, sizeof(header)); } EXPORT_SYMBOL(gator_annotate_channel_end); @@ -85,14 +105,14 @@ EXPORT_SYMBOL(gator_annotate_end); void gator_annotate_name_channel(int channel, int group, const char* str) { - int str_size = strlen(str) & 0xffff; + const u16 str_size = strlen(str) & 0xffff; char header[12]; header[0] = ESCAPE_CODE; header[1] = NAME_CHANNEL_ANNOTATION; - *(u32 *)(&header[2]) = channel; - *(u32 *)(&header[6]) = group; - *(u16 *)(&header[10]) = str_size; - kannotate_write((char *)&header, sizeof(header)); + marshal_u32(header + 2, channel); + marshal_u32(header + 6, group); + marshal_u16(header + 10, str_size); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } @@ -100,9 +120,13 @@ EXPORT_SYMBOL(gator_annotate_name_channel); void gator_annotate_name_group(int group, const char* str) { - int str_size = strlen(str) & 0xffff; - long long header = ESCAPE_CODE | (NAME_GROUP_ANNOTATION << 8) | (group << 16) | ((long long)str_size << 48); - kannotate_write((char *)&header, sizeof(header)); + const u16 str_size = strlen(str) & 0xffff; + char header[8]; + header[0] = ESCAPE_CODE; + header[1] = NAME_GROUP_ANNOTATION; + marshal_u32(header + 2, group); + marshal_u16(header + 6, str_size); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } @@ -110,11 +134,16 @@ EXPORT_SYMBOL(gator_annotate_name_group); void gator_annotate_visual(const char *data, unsigned int length, const char *str) { - int str_size = strlen(str) & 0xffff; - int visual_annotation = ESCAPE_CODE | (VISUAL_ANNOTATION << 8) | (str_size << 16); - kannotate_write((char *)&visual_annotation, sizeof(visual_annotation)); + const u16 str_size = strlen(str) & 0xffff; + char header[4]; + char header_length[4]; + header[0] = ESCAPE_CODE; + header[1] = VISUAL_ANNOTATION; + marshal_u16(header + 2, str_size); + marshal_u32(header_length, length); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); - kannotate_write((char *)&length, sizeof(length)); + kannotate_write(header_length, sizeof(header_length)); kannotate_write(data, length); } @@ -122,17 +151,23 @@ EXPORT_SYMBOL(gator_annotate_visual); void gator_annotate_marker(void) { - int header = ESCAPE_CODE | (MARKER_ANNOTATION << 8); - kannotate_write((char *)&header, sizeof(header)); + char header[4]; + header[0] = ESCAPE_CODE; + header[1] = MARKER_ANNOTATION; + marshal_u16(header + 2, 0); + kannotate_write(header, sizeof(header)); } EXPORT_SYMBOL(gator_annotate_marker); void gator_annotate_marker_str(const char *str) { - int str_size = strlen(str) & 0xffff; - int header = ESCAPE_CODE | (MARKER_ANNOTATION << 8) | (str_size << 16); - kannotate_write((char *)&header, sizeof(header)); + const u16 str_size = strlen(str) & 0xffff; + char header[4]; + header[0] = ESCAPE_CODE; + header[1] = MARKER_ANNOTATION; + marshal_u16(header + 2, str_size); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } @@ -140,17 +175,25 @@ EXPORT_SYMBOL(gator_annotate_marker_str); void gator_annotate_marker_color(int color) { - long long header = (ESCAPE_CODE | (MARKER_ANNOTATION << 8) | 0x00040000 | ((long long)color << 32)); - kannotate_write((char *)&header, sizeof(header)); + char header[8]; + header[0] = ESCAPE_CODE; + header[1] = MARKER_ANNOTATION; + marshal_u16(header + 2, 4); + marshal_u32(header + 4, color); + kannotate_write(header, sizeof(header)); } EXPORT_SYMBOL(gator_annotate_marker_color); void gator_annotate_marker_color_str(int color, const char *str) { - int str_size = (strlen(str) + 4) & 0xffff; - long long header = ESCAPE_CODE | (MARKER_ANNOTATION << 8) | (str_size << 16) | ((long long)color << 32); - kannotate_write((char *)&header, sizeof(header)); + const u16 str_size = (strlen(str) + 4) & 0xffff; + char header[8]; + header[0] = ESCAPE_CODE; + header[1] = MARKER_ANNOTATION; + marshal_u16(header + 2, str_size); + marshal_u32(header + 4, color); + kannotate_write(header, sizeof(header)); kannotate_write(str, str_size - 4); } diff --git a/driver/gator_backtrace.c b/driver/gator_backtrace.c index 0670d6c..ffacb49 100644 --- a/driver/gator_backtrace.c +++ b/driver/gator_backtrace.c @@ -132,13 +132,21 @@ static int report_trace(struct stackframe *frame, void *d) // Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile // #define GATOR_KERNEL_STACK_UNWINDING + +#if (defined(__arm__) || defined(__aarch64__)) && !defined(GATOR_KERNEL_STACK_UNWINDING) +// Disabled by default +MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding."); +bool kernel_stack_unwinding = 0; +module_param(kernel_stack_unwinding, bool, 0644); +#endif + static void kernel_backtrace(int cpu, struct pt_regs *const regs) { #if defined(__arm__) || defined(__aarch64__) #ifdef GATOR_KERNEL_STACK_UNWINDING int depth = gator_backtrace_depth; #else - int depth = 1; + int depth = (kernel_stack_unwinding ? gator_backtrace_depth : 1); #endif struct stackframe frame; if (depth == 0) diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c index 5f98a1c..91adfdd 100644 --- a/driver/gator_cookies.c +++ b/driver/gator_cookies.c @@ -8,7 +8,8 @@ */ #define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */ -#define TRANSLATE_SIZE 256 +#define TRANSLATE_BUFFER_SIZE 512 // must be a power of 2 - 512/4 = 128 entries +#define TRANSLATE_TEXT_SIZE 256 #define MAX_COLLISIONS 2 static uint32_t *gator_crc32_table; @@ -22,7 +23,7 @@ static DEFINE_PER_CPU(int, translate_buffer_read); static DEFINE_PER_CPU(int, translate_buffer_write); static DEFINE_PER_CPU(void **, translate_buffer); -static inline uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq); +static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq); static void wq_cookie_handler(struct work_struct *unused); DECLARE_WORK(cookie_work, wq_cookie_handler); static struct timer_list app_process_wake_up_timer; @@ -107,11 +108,13 @@ static void cookiemap_add(uint64_t key, uint32_t value) values[0] = value; } +#ifndef CONFIG_PREEMPT_RT_FULL static void translate_buffer_write_ptr(int cpu, void *x) { per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_write, cpu)++] = x; per_cpu(translate_buffer_write, cpu) &= translate_buffer_mask; } +#endif static void *translate_buffer_read_ptr(int cpu) { @@ -124,7 +127,7 @@ static void wq_cookie_handler(struct work_struct *unused) { struct task_struct *task; char *text; - int cpu = get_physical_cpu(); + int cpu = get_physical_cpu(), cookie; unsigned int commit; mutex_lock(&start_mutex); @@ -134,7 +137,8 @@ static void wq_cookie_handler(struct work_struct *unused) while (per_cpu(translate_buffer_read, cpu) != commit) { task = (struct task_struct *)translate_buffer_read_ptr(cpu); text = (char *)translate_buffer_read_ptr(cpu); - get_cookie(cpu, task, text, true); + cookie = get_cookie(cpu, task, text, true); + marshal_link(cookie, task->tgid, task->pid); } } @@ -156,15 +160,16 @@ static int translate_app_process(const char **text, int cpu, struct task_struct struct mm_struct *mm; struct page *page = NULL; struct vm_area_struct *page_vma; - int bytes, offset, retval = 0, ptr; + int bytes, offset, retval = 0; char *buf = per_cpu(translate_text, cpu); +#ifndef CONFIG_PREEMPT_RT_FULL // Push work into a work queue if in atomic context as the kernel functions below might sleep // Rely on the in_interrupt variable rather than in_irq() or in_interrupt() kernel functions, as the value of these functions seems // inconsistent during a context switch between android/linux versions if (!from_wq) { // Check if already in buffer - ptr = per_cpu(translate_buffer_read, cpu); + int ptr = per_cpu(translate_buffer_read, cpu); while (ptr != per_cpu(translate_buffer_write, cpu)) { if (per_cpu(translate_buffer, cpu)[ptr] == (void *)task) goto out; @@ -174,9 +179,11 @@ static int translate_app_process(const char **text, int cpu, struct task_struct translate_buffer_write_ptr(cpu, (void *)task); translate_buffer_write_ptr(cpu, (void *)*text); + // Not safe to call in RT-Preempt full in schedule switch context mod_timer(&app_process_wake_up_timer, jiffies + 1); goto out; } +#endif mm = get_task_mm(task); if (!mm) @@ -186,8 +193,8 @@ static int translate_app_process(const char **text, int cpu, struct task_struct addr = mm->arg_start; len = mm->arg_end - mm->arg_start; - if (len > TRANSLATE_SIZE) - len = TRANSLATE_SIZE; + if (len > TRANSLATE_TEXT_SIZE) + len = TRANSLATE_TEXT_SIZE; down_read(&mm->mmap_sem); while (len) { @@ -225,7 +232,7 @@ out: return retval; } -static inline uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq) +static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq) { unsigned long flags, cookie; uint64_t key; @@ -312,8 +319,7 @@ static int cookies_initialize(void) uint32_t crc, poly; int i, j, cpu, size, err = 0; - int translate_buffer_size = 512; // must be a power of 2 - translate_buffer_mask = translate_buffer_size / sizeof(per_cpu(translate_buffer, 0)[0]) - 1; + translate_buffer_mask = TRANSLATE_BUFFER_SIZE / sizeof(per_cpu(translate_buffer, 0)[0]) - 1; for_each_present_cpu(cpu) { per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu; @@ -334,7 +340,7 @@ static int cookies_initialize(void) } memset(per_cpu(cookie_values, cpu), 0, size); - per_cpu(translate_buffer, cpu) = (void **)kmalloc(translate_buffer_size, GFP_KERNEL); + per_cpu(translate_buffer, cpu) = (void **)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL); if (!per_cpu(translate_buffer, cpu)) { err = -ENOMEM; goto cookie_setup_error; @@ -343,7 +349,7 @@ static int cookies_initialize(void) per_cpu(translate_buffer_write, cpu) = 0; per_cpu(translate_buffer_read, cpu) = 0; - per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_SIZE, GFP_KERNEL); + per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_TEXT_SIZE, GFP_KERNEL); if (!per_cpu(translate_text, cpu)) { err = -ENOMEM; goto cookie_setup_error; @@ -353,6 +359,10 @@ static int cookies_initialize(void) // build CRC32 table poly = 0x04c11db7; gator_crc32_table = (uint32_t *)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL); + if (!gator_crc32_table) { + err = -ENOMEM; + goto cookie_setup_error; + } for (i = 0; i < 256; i++) { crc = i; for (j = 8; j > 0; j--) { diff --git a/driver/gator_events.sh b/driver/gator_events.sh deleted file mode 100644 index 5467dd6..0000000 --- a/driver/gator_events.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -EVENTS=`grep gator_events_init *.c | sed 's/.\+gator_events_init(\(.\+\)).\+/\1/'` - -( - echo /\* This file is auto generated \*/ - echo - for EVENT in $EVENTS; do - echo __weak int $EVENT\(void\)\; - done - echo - echo static int \(*gator_events_list[]\)\(void\) = { - for EVENT in $EVENTS; do - echo \ $EVENT, - done - echo }\; -) > $1.tmp - -cmp -s $1 $1.tmp && rm $1.tmp || mv $1.tmp $1 diff --git a/driver/gator_events_armv6.c b/driver/gator_events_armv6.c index 4f1bca6..dd79740 100644 --- a/driver/gator_events_armv6.c +++ b/driver/gator_events_armv6.c @@ -234,11 +234,4 @@ int gator_events_armv6_init(void) return gator_events_install(&gator_events_armv6_interface); } -gator_events_init(gator_events_armv6_init); - -#else -int gator_events_armv6_init(void) -{ - return -1; -} #endif diff --git a/driver/gator_events_armv7.c b/driver/gator_events_armv7.c index 58f2956..30881c8 100644 --- a/driver/gator_events_armv7.c +++ b/driver/gator_events_armv7.c @@ -309,11 +309,4 @@ int gator_events_armv7_init(void) return gator_events_install(&gator_events_armv7_interface); } -gator_events_init(gator_events_armv7_init); - -#else -int gator_events_armv7_init(void) -{ - return -1; -} #endif diff --git a/driver/gator_events_block.c b/driver/gator_events_block.c index 56c6a67..691ef25 100644 --- a/driver/gator_events_block.c +++ b/driver/gator_events_block.c @@ -151,5 +151,3 @@ int gator_events_block_init(void) return gator_events_install(&gator_events_block_interface); } - -gator_events_init(gator_events_block_init); diff --git a/driver/gator_events_ccn-504.c b/driver/gator_events_ccn-504.c index b91a9a1..b892319 100644 --- a/driver/gator_events_ccn-504.c +++ b/driver/gator_events_ccn-504.c @@ -6,23 +6,16 @@ * published by the Free Software Foundation. */ -/******************************************************************************* - * WARNING: This code is an experimental implementation of the CCN-504 hardware - * counters which has not been tested on the hardware. Commented debug - * statements are present and can be uncommented for diagnostic purposes. - ******************************************************************************/ - #include #include #include "gator.h" -#define PERIPHBASE 0x2E000000 - #define NUM_REGIONS 256 #define REGION_SIZE (64*1024) #define REGION_DEBUG 1 #define REGION_XP 64 +#define NUM_XPS 11 // DT (Debug) region #define PMEVCNTSR0 0x0150 @@ -34,27 +27,86 @@ // XP region #define DT_CONFIG 0x0300 +#define DT_CONTROL 0x0370 // Multiple #define PMU_EVENT_SEL 0x0600 #define OLY_ID 0xFF00 #define CCNT 4 -#define CNTMAX (4 + 1) +#define CNTMAX (CCNT + 1) #define get_pmu_event_id(event) (((event) >> 0) & 0xFF) #define get_node_type(event) (((event) >> 8) & 0xFF) #define get_region(event) (((event) >> 16) & 0xFF) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) + +// From kernel/params.c +#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \ + int param_set_##name(const char *val, struct kernel_param *kp) \ + { \ + tmptype l; \ + int ret; \ + \ + if (!val) return -EINVAL; \ + ret = strtolfn(val, 0, &l); \ + if (ret == -EINVAL || ((type)l != l)) \ + return -EINVAL; \ + *((type *)kp->arg) = l; \ + return 0; \ + } \ + int param_get_##name(char *buffer, struct kernel_param *kp) \ + { \ + return sprintf(buffer, format, *((type *)kp->arg)); \ + } + +#else + +// From kernel/params.c +#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \ + int param_set_##name(const char *val, const struct kernel_param *kp) \ + { \ + tmptype l; \ + int ret; \ + \ + ret = strtolfn(val, 0, &l); \ + if (ret < 0 || ((type)l != l)) \ + return ret < 0 ? ret : -EINVAL; \ + *((type *)kp->arg) = l; \ + return 0; \ + } \ + int param_get_##name(char *buffer, const struct kernel_param *kp) \ + { \ + return scnprintf(buffer, PAGE_SIZE, format, \ + *((type *)kp->arg)); \ + } \ + struct kernel_param_ops param_ops_##name = { \ + .set = param_set_##name, \ + .get = param_get_##name, \ + }; \ + EXPORT_SYMBOL(param_set_##name); \ + EXPORT_SYMBOL(param_get_##name); \ + EXPORT_SYMBOL(param_ops_##name) + +#endif + +STANDARD_PARAM_DEF(u64, u64, "%llu", u64, strict_strtoull); + +// From include/linux/moduleparam.h +#define param_check_u64(name, p) __param_check(name, p, u64) + MODULE_PARM_DESC(ccn504_addr, "CCN-504 physical base address"); -static unsigned long ccn504_addr = 0; -module_param(ccn504_addr, ulong, 0444); +static u64 ccn504_addr = 0; +module_param(ccn504_addr, u64, 0444); static void __iomem *gator_events_ccn504_base; +static bool gator_events_ccn504_global_enabled; static unsigned long gator_events_ccn504_enabled[CNTMAX]; static unsigned long gator_events_ccn504_event[CNTMAX]; static unsigned long gator_events_ccn504_key[CNTMAX]; static int gator_events_ccn504_buffer[2*CNTMAX]; +static int gator_events_ccn504_prev[CNTMAX]; static void gator_events_ccn504_create_shutdown(void) { @@ -96,7 +148,6 @@ static void gator_events_ccn504_set_dt_config(int xp_node_id, int event_num, int dt_config = readl(gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG); dt_config |= (value + event_num) << (4*event_num); - //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, dt_config, (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG); writel(dt_config, gator_events_ccn504_base + (REGION_XP + xp_node_id)*REGION_SIZE + DT_CONFIG); } @@ -104,6 +155,20 @@ static int gator_events_ccn504_start(void) { int i; + gator_events_ccn504_global_enabled = 0; + for (i = 0; i < CNTMAX; ++i) { + if (gator_events_ccn504_enabled[i]) { + gator_events_ccn504_global_enabled = 1; + break; + } + } + + if (!gator_events_ccn504_global_enabled) { + return 0; + } + + memset(&gator_events_ccn504_prev, 0x80, sizeof(gator_events_ccn504_prev)); + // Disable INTREQ on overflow // [6] ovfl_intr_en = 0 // perhaps set to 1? @@ -112,9 +177,22 @@ static int gator_events_ccn504_start(void) // [4:1] cntcfg = 0 // Enable PMU features // [0] pmu_en = 1 - //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0x1, REGION_DEBUG*REGION_SIZE + PMCR); writel(0x1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMCR); + // Configure the XPs + for (i = 0; i < NUM_XPS; ++i) { + int dt_control; + + // Pass on all events + writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG); + + // Enable PMU capability + // [0] dt_enable = 1 + dt_control = readl(gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL); + dt_control |= 0x1; + writel(dt_control, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONTROL); + } + // Assume no other pmu_event_sel registers are set // cycle counter does not need to be enabled @@ -134,15 +212,14 @@ static int gator_events_ccn504_start(void) pmu_event_id = get_pmu_event_id(gator_events_ccn504_event[i]); node_type = get_node_type(gator_events_ccn504_event[i]); region = get_region(gator_events_ccn504_event[i]); - //printk(KERN_ERR "%s(%s:%i) pmu_event_id: %x node_type: %x region: %x\n", __FUNCTION__, __FILE__, __LINE__, pmu_event_id, node_type, region); // Verify the node_type oly_id_whole = readl(gator_events_ccn504_base + region*REGION_SIZE + OLY_ID); oly_id = oly_id_whole & 0x1F; node_id = (oly_id_whole >> 8) & 0x7F; if ((oly_id != node_type) || - ((node_type == 0x16) && ((oly_id == 0x14) || (oly_id == 0x15) || (oly_id == 0x16) || (oly_id == 0x18) || (oly_id == 0x19) || (oly_id == 0x1A)))) { - printk(KERN_ERR "%s(%s:%i) oly_id is %x expected %x\n", __FUNCTION__, __FILE__, __LINE__, oly_id, node_type); + ((node_type == 0x16) && ((oly_id != 0x14) && (oly_id != 0x15) && (oly_id != 0x16) && (oly_id != 0x18) && (oly_id != 0x19) && (oly_id != 0x1A)))) { + printk(KERN_ERR "gator: oly_id is 0x%x expected 0x%x\n", oly_id, node_type); return -1; } @@ -160,7 +237,6 @@ static int gator_events_ccn504_start(void) gator_events_ccn504_set_dt_config(node_id/2, i, (node_id & 1) == 0 ? 0x8 : 0xC); break; } - //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, pmu_event_sel, region*REGION_SIZE + PMU_EVENT_SEL); writel(pmu_event_sel, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL); } @@ -171,21 +247,25 @@ static void gator_events_ccn504_stop(void) { int i; + if (!gator_events_ccn504_global_enabled) { + return; + } + // cycle counter does not need to be disabled for (i = 0; i < CCNT; ++i) { - int node_type; int region; - node_type = get_node_type(gator_events_ccn504_event[i]); + if (!gator_events_ccn504_enabled[i]) { + continue; + } + region = get_region(gator_events_ccn504_event[i]); - //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0, region*REGION_SIZE + PMU_EVENT_SEL); writel(0, gator_events_ccn504_base + region*REGION_SIZE + PMU_EVENT_SEL); } // Clear dt_config - for (i = 0; i < 11; ++i) { - //printk(KERN_ERR "%s(%s:%i) writel %x %x\n", __FUNCTION__, __FILE__, __LINE__, 0, (REGION_XP + i)*REGION_SIZE + DT_CONFIG); + for (i = 0; i < NUM_XPS; ++i) { writel(0, gator_events_ccn504_base + (REGION_XP + i)*REGION_SIZE + DT_CONFIG); } } @@ -194,27 +274,20 @@ static int gator_events_ccn504_read(int **buffer) { int i; int len = 0; + int value; - if (!on_primary_core()) { + if (!on_primary_core() || !gator_events_ccn504_global_enabled) { return 0; } // Verify the pmsr register is zero - //i = 0; - while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0) { - //++i; - } - //printk(KERN_ERR "%s(%s:%i) %i\n", __FUNCTION__, __FILE__, __LINE__, i); + while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) != 0); // Request a PMU snapshot writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_REQ); // Wait for the snapshot - //i = 0; - while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0) { - //++i; - } - //printk(KERN_ERR "%s(%s:%i) %i\n", __FUNCTION__, __FILE__, __LINE__, i); + while (readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR) == 0); // Read the shadow registers for (i = 0; i < CNTMAX; ++i) { @@ -222,8 +295,12 @@ static int gator_events_ccn504_read(int **buffer) continue; } - gator_events_ccn504_buffer[len++] = gator_events_ccn504_key[i]; - gator_events_ccn504_buffer[len++] = readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + (i == CCNT ? PMCCNTRSR : PMEVCNTSR0 + 8*i)); + value = readl(gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + (i == CCNT ? PMCCNTRSR : PMEVCNTSR0 + 8*i)); + if (gator_events_ccn504_prev[i] != 0x80808080) { + gator_events_ccn504_buffer[len++] = gator_events_ccn504_key[i]; + gator_events_ccn504_buffer[len++] = value - gator_events_ccn504_prev[i]; + } + gator_events_ccn504_prev[i] = value; // Are the counters registers cleared when read? Is that what the cntr_rst bit on the pmcr register does? } @@ -231,18 +308,10 @@ static int gator_events_ccn504_read(int **buffer) // Clear the PMU snapshot status writel(1, gator_events_ccn504_base + REGION_DEBUG*REGION_SIZE + PMSR_CLR); - return len; -} - -static void __maybe_unused gator_events_ccn504_enumerate(int pos, int size) -{ - int i; - u32 oly_id; + if (buffer) + *buffer = gator_events_ccn504_buffer; - for (i = pos; i < pos + size; ++i) { - oly_id = readl(gator_events_ccn504_base + i*REGION_SIZE + OLY_ID); - printk(KERN_ERR "%s(%s:%i) %i %08x\n", __FUNCTION__, __FILE__, __LINE__, i, oly_id); - } + return len; } static struct gator_interface gator_events_ccn504_interface = { @@ -263,36 +332,9 @@ int gator_events_ccn504_init(void) gator_events_ccn504_base = ioremap(ccn504_addr, NUM_REGIONS*REGION_SIZE); if (gator_events_ccn504_base == NULL) { - printk(KERN_ERR "%s(%s:%i) ioremap returned NULL\n", __FUNCTION__, __FILE__, __LINE__); + printk(KERN_ERR "gator: ioremap returned NULL\n"); return -1; } - //printk(KERN_ERR "%s(%s:%i)\n", __FUNCTION__, __FILE__, __LINE__); - - // Test - can memory be read - { - //gator_events_ccn504_enumerate(0, NUM_REGIONS); - -#if 0 - // DT - gator_events_ccn504_enumerate(1, 1); - // HN-F - gator_events_ccn504_enumerate(32, 8); - // XP - gator_events_ccn504_enumerate(64, 11); - // RN-I - gator_events_ccn504_enumerate(128, 1); - gator_events_ccn504_enumerate(130, 1); - gator_events_ccn504_enumerate(134, 1); - gator_events_ccn504_enumerate(140, 1); - gator_events_ccn504_enumerate(144, 1); - gator_events_ccn504_enumerate(148, 1); - // SBAS - gator_events_ccn504_enumerate(129, 1); - gator_events_ccn504_enumerate(137, 1); - gator_events_ccn504_enumerate(139, 1); - gator_events_ccn504_enumerate(147, 1); -#endif - } for (i = 0; i < CNTMAX; ++i) { gator_events_ccn504_enabled[i] = 0; @@ -302,5 +344,3 @@ int gator_events_ccn504_init(void) return gator_events_install(&gator_events_ccn504_interface); } - -gator_events_init(gator_events_ccn504_init); diff --git a/driver/gator_events_irq.c b/driver/gator_events_irq.c index b4df7fa..b11879a 100644 --- a/driver/gator_events_irq.c +++ b/driver/gator_events_irq.c @@ -163,5 +163,3 @@ int gator_events_irq_init(void) return gator_events_install(&gator_events_irq_interface); } - -gator_events_init(gator_events_irq_init); diff --git a/driver/gator_events_l2c-310.c b/driver/gator_events_l2c-310.c index 21aa4a2..ee521af 100644 --- a/driver/gator_events_l2c-310.c +++ b/driver/gator_events_l2c-310.c @@ -206,5 +206,3 @@ int gator_events_l2c310_init(void) return gator_events_install(&gator_events_l2c310_interface); } - -gator_events_init(gator_events_l2c310_init); diff --git a/driver/gator_events_mali_4xx.c b/driver/gator_events_mali_4xx.c index dd275f7..6719c1e 100644 --- a/driver/gator_events_mali_4xx.c +++ b/driver/gator_events_mali_4xx.c @@ -415,25 +415,12 @@ static void mali_counter_initialize(void) int i; int core_id; - mali_osk_fb_control_set_type *mali_set_fb_event; mali_profiling_control_type *mali_control; init_counters(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores) - 1); init_counters(COUNTER_VP_0_C0, COUNTER_VP_0_C0 + (2 * n_vp_cores) - 1); init_counters(COUNTER_FP_0_C0, COUNTER_FP_0_C0 + (2 * n_fp_cores) - 1); - mali_set_fb_event = symbol_get(_mali_osk_fb_control_set); - - if (mali_set_fb_event) { - pr_debug("gator: mali online _mali_osk_fb_control_set symbol @ %p\n", mali_set_fb_event); - - mali_set_fb_event(0, (counter_enabled[COUNTER_FILMSTRIP] ? 1 : 0)); - - symbol_put(_mali_osk_fb_control_set); - } else { - printk("gator: mali online _mali_osk_fb_control_set symbol not found\n"); - } - /* Generic control interface for Mali DDK. */ mali_control = symbol_get(_mali_profiling_control); if (mali_control) { @@ -491,7 +478,6 @@ static void mali_counter_initialize(void) static void mali_counter_deinitialize(void) { mali_profiling_set_event_type *mali_set_hw_event; - mali_osk_fb_control_set_type *mali_set_fb_event; mali_profiling_control_type *mali_control; mali_set_hw_event = symbol_get(_mali_profiling_set_event); @@ -509,23 +495,11 @@ static void mali_counter_deinitialize(void) printk("gator: mali offline _mali_profiling_set_event symbol not found\n"); } - mali_set_fb_event = symbol_get(_mali_osk_fb_control_set); - - if (mali_set_fb_event) { - pr_debug("gator: mali offline _mali_osk_fb_control_set symbol @ %p\n", mali_set_fb_event); - - mali_set_fb_event(0, 0); - - symbol_put(_mali_osk_fb_control_set); - } else { - printk("gator: mali offline _mali_osk_fb_control_set symbol not found\n"); - } - /* Generic control interface for Mali DDK. */ mali_control = symbol_get(_mali_profiling_control); if (mali_control) { - pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_set_fb_event); + pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_control); /* Reset the DDK state - disable counter collection */ mali_control(SW_COUNTER_ENABLE, 0); @@ -747,5 +721,3 @@ int gator_events_mali_init(void) return gator_events_install(&gator_events_mali_interface); } - -gator_events_init(gator_events_mali_init); diff --git a/driver/gator_events_mali_common.c b/driver/gator_events_mali_common.c index 5a98b37..466ca16 100644 --- a/driver/gator_events_mali_common.c +++ b/driver/gator_events_mali_common.c @@ -28,7 +28,7 @@ extern const char *gator_mali_get_mali_name(void) } } -extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter) +extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event) { int err; char buf[255]; @@ -56,6 +56,13 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ro_ulong for: %s (%s)", event_name, buf); return -1; } + if (event != NULL) { + err = gatorfs_create_ulong(sb, dir, "event", event); + if (err != 0) { + pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ro_ulong for: %s (%s)", event_name, buf); + return -1; + } + } } return 0; diff --git a/driver/gator_events_mali_common.h b/driver/gator_events_mali_common.h index d67ee2d..509f9b6 100644 --- a/driver/gator_events_mali_common.h +++ b/driver/gator_events_mali_common.h @@ -43,7 +43,6 @@ typedef struct { * Mali-4xx */ typedef int mali_profiling_set_event_type(unsigned int, int); -typedef void mali_osk_fb_control_set_type(unsigned int, unsigned int); typedef void mali_profiling_control_type(unsigned int, unsigned int); typedef void mali_profiling_get_counters_type(unsigned int *, unsigned int *, unsigned int *, unsigned int *); @@ -51,7 +50,6 @@ typedef void mali_profiling_get_counters_type(unsigned int *, unsigned int *, un * Driver entry points for functions called directly by gator. */ extern int _mali_profiling_set_event(unsigned int, int); -extern void _mali_osk_fb_control_set(unsigned int, unsigned int); extern void _mali_profiling_control(unsigned int, unsigned int); extern void _mali_profiling_get_counters(unsigned int *, unsigned int *, unsigned int *, unsigned int *); @@ -75,7 +73,7 @@ extern const char *gator_mali_get_mali_name(void); * * @return 0 if entry point was created, non-zero if not. */ -extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter); +extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event); /** * Initializes the counter array. diff --git a/driver/gator_events_mali_t6xx.c b/driver/gator_events_mali_t6xx.c index 2576a99..7bf7d6a 100644 --- a/driver/gator_events_mali_t6xx.c +++ b/driver/gator_events_mali_t6xx.c @@ -109,12 +109,14 @@ enum { #define NUMBER_OF_SOFTWARE_COUNTERS (sizeof(software_counter_names) / sizeof(software_counter_names[0])) #define FIRST_ACCUMULATOR (FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS) #define NUMBER_OF_ACCUMULATORS (sizeof(accumulators_names) / sizeof(accumulators_names[0])) -#define NUMBER_OF_EVENTS (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS) +#define FILMSTRIP (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS) +#define NUMBER_OF_EVENTS (NUMBER_OF_TIMELINE_EVENTS + NUMBER_OF_SOFTWARE_COUNTERS + NUMBER_OF_ACCUMULATORS + 1) /* * gatorfs variables for counter enable state */ static mali_counter counters[NUMBER_OF_EVENTS]; +static unsigned long filmstrip_event; /* An array used to return the data we recorded * as key,value pairs hence the *2 @@ -285,28 +287,37 @@ static int create_files(struct super_block *sb, struct dentry *root) */ int counter_index = 0; const char *mali_name = gator_mali_get_mali_name(); + mali_profiling_control_type *mali_control; for (event = FIRST_TIMELINE_EVENT; event < FIRST_TIMELINE_EVENT + NUMBER_OF_TIMELINE_EVENTS; event++) { - if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event]) != 0) { + if (gator_mali_create_file_system(mali_name, timeline_event_names[counter_index], sb, root, &counters[event], NULL) != 0) { return -1; } counter_index++; } counter_index = 0; for (event = FIRST_SOFTWARE_COUNTER; event < FIRST_SOFTWARE_COUNTER + NUMBER_OF_SOFTWARE_COUNTERS; event++) { - if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event]) != 0) { + if (gator_mali_create_file_system(mali_name, software_counter_names[counter_index], sb, root, &counters[event], NULL) != 0) { return -1; } counter_index++; } counter_index = 0; for (event = FIRST_ACCUMULATOR; event < FIRST_ACCUMULATOR + NUMBER_OF_ACCUMULATORS; event++) { - if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event]) != 0) { + if (gator_mali_create_file_system(mali_name, accumulators_names[counter_index], sb, root, &counters[event], NULL) != 0) { return -1; } counter_index++; } + mali_control = symbol_get(_mali_profiling_control); + if (mali_control) { + if (gator_mali_create_file_system(mali_name, "Filmstrip_cnt0", sb, root, &counters[FILMSTRIP], &filmstrip_event) != 0) { + return -1; + } + symbol_put(_mali_profiling_control); + } + return 0; } @@ -350,6 +361,7 @@ static int register_tracepoints(void) static int start(void) { unsigned int cnt; + mali_profiling_control_type *mali_control; /* Clean all data for the next capture */ for (cnt = 0; cnt < NUMBER_OF_TIMELINE_EVENTS; cnt++) { @@ -370,6 +382,30 @@ static int start(void) return -1; } + /* Generic control interface for Mali DDK. */ + mali_control = symbol_get(_mali_profiling_control); + if (mali_control) { + /* The event attribute in the XML file keeps the actual frame rate. */ + unsigned int enabled = counters[FILMSTRIP].enabled ? 1 : 0; + unsigned int rate = filmstrip_event & 0xff; + unsigned int resize_factor = (filmstrip_event >> 8) & 0xff; + + pr_debug("gator: mali online _mali_profiling_control symbol @ %p\n", mali_control); + +#define FBDUMP_CONTROL_ENABLE (1) +#define FBDUMP_CONTROL_RATE (2) +#define FBDUMP_CONTROL_RESIZE_FACTOR (4) + mali_control(FBDUMP_CONTROL_ENABLE, enabled); + mali_control(FBDUMP_CONTROL_RATE, rate); + mali_control(FBDUMP_CONTROL_RESIZE_FACTOR, resize_factor); + + pr_debug("gator: sent mali_control enabled=%d, rate=%d, resize_factor=%d\n", enabled, rate, resize_factor); + + symbol_put(_mali_profiling_control); + } else { + printk("gator: mali online _mali_profiling_control symbol not found\n"); + } + /* * Set the first timestamp for calculating the sample interval. The first interval could be quite long, * since it will be the time between 'start' and the first 'read'. @@ -382,6 +418,8 @@ static int start(void) static void stop(void) { + mali_profiling_control_type *mali_control; + pr_debug("gator: Mali-T6xx: stop\n"); /* @@ -402,6 +440,18 @@ static void stop(void) GATOR_UNREGISTER_TRACE(mali_total_alloc_pages_change); pr_debug("gator: Mali-T6xx: mali_total_alloc_pages_change tracepoint deactivated\n"); + + /* Generic control interface for Mali DDK. */ + mali_control = symbol_get(_mali_profiling_control); + if (mali_control) { + pr_debug("gator: mali offline _mali_profiling_control symbol @ %p\n", mali_control); + + mali_control(FBDUMP_CONTROL_ENABLE, 0); + + symbol_put(_mali_profiling_control); + } else { + printk("gator: mali offline _mali_profiling_control symbol not found\n"); + } } static int read(int **buffer) @@ -508,5 +558,3 @@ extern int gator_events_mali_t6xx_init(void) return gator_events_install(&gator_events_mali_t6xx_interface); } - -gator_events_init(gator_events_mali_t6xx_init); diff --git a/driver/gator_events_mali_t6xx_hw.c b/driver/gator_events_mali_t6xx_hw.c index f557350..e406991 100644 --- a/driver/gator_events_mali_t6xx_hw.c +++ b/driver/gator_events_mali_t6xx_hw.c @@ -63,6 +63,8 @@ static kbase_instr_hwcnt_disable_type *kbase_instr_hwcnt_disable_symbol; static kbase_va_free_type *kbase_va_free_symbol; static kbase_destroy_context_type *kbase_destroy_context_symbol; +static long shader_present_low = 0; + /** The interval between reads, in ns. * * Earlier we introduced @@ -496,6 +498,7 @@ static int start(void) mali_error err; int cnt; u16 bitmask[] = { 0, 0, 0, 0 }; + unsigned long long shadersPresent = 0; /* Setup HW counters */ num_hardware_counters_enabled = 0; @@ -539,6 +542,11 @@ static int start(void) goto out; } + + /* See if we can get the number of shader cores */ + shadersPresent = kbdevice->shader_present_bitmap; + shader_present_low = (unsigned long)shadersPresent; + /* * The amount of memory needed to store the dump (bytes) * DUMP_SIZE = number of core groups @@ -679,21 +687,41 @@ static int read(int **buffer) kbase_device_busy = false; if (success == MALI_TRUE) { + /* Cycle through hardware counters and accumulate totals */ for (cnt = 0; cnt < NUMBER_OF_HARDWARE_COUNTERS; cnt++) { const mali_counter *counter = &counters[cnt]; if (counter->enabled) { const int block = GET_HW_BLOCK(cnt); const int counter_offset = GET_COUNTER_OFFSET(cnt); - const u32 *counter_block = (u32 *) ((uintptr_t)kernel_dump_buffer + vithar_blocks[block]); - const u32 *counter_address = counter_block + counter_offset; - value = *counter_address; + const char* block_base_address = (char*)kernel_dump_buffer + vithar_blocks[block]; + /* If counter belongs to shader block need to take into account all cores */ if (block == SHADER_BLOCK) { - /* (counter_address + 0x000) has already been accounted-for above. */ - value += *(counter_address + 0x100); - value += *(counter_address + 0x200); - value += *(counter_address + 0x300); + int i = 0; + int shader_core_count = 0; + value = 0; + + for (i = 0; i < 4; i++) { + if ((shader_present_low >> i) & 1) { + value += *((u32*) (block_base_address + (0x100 * i)) + counter_offset); + shader_core_count++; + } + } + + for (i = 0; i < 4; i++) { + if((shader_present_low >> (i+4)) & 1) { + value += *((u32*)(block_base_address + (0x100 * i) + 0x800) + counter_offset); + shader_core_count++; + } + } + + /* Need to total by number of cores to produce an average */ + if (shader_core_count != 0) { + value /= shader_core_count; + } + } else { + value = *((u32*)block_base_address + counter_offset); } counter_dump[len++] = counter->key; @@ -727,7 +755,7 @@ static int create_files(struct super_block *sb, struct dentry *root) const char *mali_name = gator_mali_get_mali_name(); for (event = 0; event < NUMBER_OF_HARDWARE_COUNTERS; event++) { - if (gator_mali_create_file_system(mali_name, hardware_counter_names[counter_index], sb, root, &counters[event]) != 0) + if (gator_mali_create_file_system(mali_name, hardware_counter_names[counter_index], sb, root, &counters[event], NULL) != 0) return -1; counter_index++; } @@ -754,5 +782,3 @@ int gator_events_mali_t6xx_hw_init(void) return gator_events_install(&gator_events_mali_t6xx_interface); } - -gator_events_init(gator_events_mali_t6xx_hw_init); diff --git a/driver/gator_events_meminfo.c b/driver/gator_events_meminfo.c index c1e360d..451290d 100644 --- a/driver/gator_events_meminfo.c +++ b/driver/gator_events_meminfo.c @@ -8,27 +8,62 @@ */ #include "gator.h" + +#include +#include +#include +#include #include #include -#include -#define MEMINFO_MEMFREE 0 -#define MEMINFO_MEMUSED 1 -#define MEMINFO_BUFFERRAM 2 -#define MEMINFO_TOTAL 3 +enum { + MEMINFO_MEMFREE, + MEMINFO_MEMUSED, + MEMINFO_BUFFERRAM, + MEMINFO_TOTAL, +}; + +enum { + PROC_SIZE, + PROC_SHARE, + PROC_TEXT, + PROC_DATA, + PROC_COUNT, +}; + +static const char * const meminfo_names[] = { + "Linux_meminfo_memfree", + "Linux_meminfo_memused", + "Linux_meminfo_bufferram", +}; + +static const char * const proc_names[] = { + "Linux_proc_statm_size", + "Linux_proc_statm_share", + "Linux_proc_statm_text", + "Linux_proc_statm_data", +}; -static ulong meminfo_global_enabled; +static bool meminfo_global_enabled; static ulong meminfo_enabled[MEMINFO_TOTAL]; -static ulong meminfo_key[MEMINFO_TOTAL]; -static unsigned long long meminfo_buffer[MEMINFO_TOTAL * 2]; +static ulong meminfo_keys[MEMINFO_TOTAL]; +static long long meminfo_buffer[2 * (MEMINFO_TOTAL + 2)]; static int meminfo_length = 0; -static unsigned int mem_event = 0; static bool new_data_avail; -static void wq_sched_handler(struct work_struct *wsptr); -DECLARE_WORK(work, wq_sched_handler); -static struct timer_list meminfo_wake_up_timer; -static void meminfo_wake_up_handler(unsigned long unused_data); +static bool proc_global_enabled; +static ulong proc_enabled[PROC_COUNT]; +static ulong proc_keys[PROC_COUNT]; +static DEFINE_PER_CPU(long long, proc_buffer[2 * (PROC_COUNT + 3)]); + +static int gator_meminfo_func(void *data); +static bool gator_meminfo_run; +// Initialize semaphore unlocked to initialize memory values +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) +static DECLARE_MUTEX(gator_meminfo_sem); +#else +static DEFINE_SEMAPHORE(gator_meminfo_sem); +#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order)) @@ -36,7 +71,7 @@ GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order)) #endif { - mem_event++; + up(&gator_meminfo_sem); } #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) @@ -45,12 +80,12 @@ GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold)) GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold)) #endif { - mem_event++; + up(&gator_meminfo_sem); } GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype)) { - mem_event++; + up(&gator_meminfo_sem); } static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root) @@ -59,24 +94,21 @@ static int gator_events_meminfo_create_files(struct super_block *sb, struct dent int i; for (i = 0; i < MEMINFO_TOTAL; i++) { - switch (i) { - case MEMINFO_MEMFREE: - dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memfree"); - break; - case MEMINFO_MEMUSED: - dir = gatorfs_mkdir(sb, root, "Linux_meminfo_memused"); - break; - case MEMINFO_BUFFERRAM: - dir = gatorfs_mkdir(sb, root, "Linux_meminfo_bufferram"); - break; - default: + dir = gatorfs_mkdir(sb, root, meminfo_names[i]); + if (!dir) { return -1; } + gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]); + gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_keys[i]); + } + + for (i = 0; i < PROC_COUNT; ++i) { + dir = gatorfs_mkdir(sb, root, proc_names[i]); if (!dir) { return -1; } - gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]); - gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_key[i]); + gatorfs_create_ulong(sb, dir, "enabled", &proc_enabled[i]); + gatorfs_create_ro_ulong(sb, dir, "key", &proc_keys[i]); } return 0; @@ -86,13 +118,26 @@ static int gator_events_meminfo_start(void) { int i; - new_data_avail = true; + new_data_avail = false; + meminfo_global_enabled = 0; for (i = 0; i < MEMINFO_TOTAL; i++) { if (meminfo_enabled[i]) { meminfo_global_enabled = 1; + break; } } + proc_global_enabled = 0; + for (i = 0; i < PROC_COUNT; ++i) { + if (proc_enabled[i]) { + proc_global_enabled = 1; + break; + } + } + if (meminfo_enabled[MEMINFO_MEMUSED]) { + proc_global_enabled = 1; + } + if (meminfo_global_enabled == 0) return 0; @@ -111,9 +156,16 @@ static int gator_events_meminfo_start(void) if (GATOR_REGISTER_TRACE(mm_page_alloc)) goto mm_page_alloc_exit; - setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0); + // Start worker thread + gator_meminfo_run = true; + // Since the mutex starts unlocked, memory values will be initialized + if (IS_ERR(kthread_run(gator_meminfo_func, NULL, "gator_meminfo"))) + goto kthread_run_exit; + return 0; +kthread_run_exit: + GATOR_UNREGISTER_TRACE(mm_page_alloc); mm_page_alloc_exit: #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) GATOR_UNREGISTER_TRACE(mm_pagevec_free); @@ -132,8 +184,6 @@ mm_page_free_exit: static void gator_events_meminfo_stop(void) { - int i; - if (meminfo_global_enabled) { #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) GATOR_UNREGISTER_TRACE(mm_page_free_direct); @@ -144,68 +194,75 @@ static void gator_events_meminfo_stop(void) #endif GATOR_UNREGISTER_TRACE(mm_page_alloc); - del_timer_sync(&meminfo_wake_up_timer); - } - - meminfo_global_enabled = 0; - for (i = 0; i < MEMINFO_TOTAL; i++) { - meminfo_enabled[i] = 0; + // Stop worker thread + gator_meminfo_run = false; + up(&gator_meminfo_sem); } } // Must be run in process context as the kernel function si_meminfo() can sleep -static void wq_sched_handler(struct work_struct *wsptr) +static int gator_meminfo_func(void *data) { struct sysinfo info; int i, len; unsigned long long value; - meminfo_length = len = 0; + for (;;) { + if (down_killable(&gator_meminfo_sem)) { + break; + } - si_meminfo(&info); - for (i = 0; i < MEMINFO_TOTAL; i++) { - if (meminfo_enabled[i]) { - switch (i) { - case MEMINFO_MEMFREE: - value = info.freeram * PAGE_SIZE; - break; - case MEMINFO_MEMUSED: - value = (info.totalram - info.freeram) * PAGE_SIZE; - break; - case MEMINFO_BUFFERRAM: - value = info.bufferram * PAGE_SIZE; - break; - default: - value = 0; - break; + // Eat up any pending events + while (!down_trylock(&gator_meminfo_sem)); + + if (!gator_meminfo_run) { + break; + } + + meminfo_length = len = 0; + + si_meminfo(&info); + for (i = 0; i < MEMINFO_TOTAL; i++) { + if (meminfo_enabled[i]) { + switch (i) { + case MEMINFO_MEMFREE: + value = info.freeram * PAGE_SIZE; + break; + case MEMINFO_MEMUSED: + // pid -1 means system wide + meminfo_buffer[len++] = 1; + meminfo_buffer[len++] = -1; + // Emit value + meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED]; + meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE; + // Clear pid + meminfo_buffer[len++] = 1; + meminfo_buffer[len++] = 0; + continue; + case MEMINFO_BUFFERRAM: + value = info.bufferram * PAGE_SIZE; + break; + default: + value = 0; + break; + } + meminfo_buffer[len++] = meminfo_keys[i]; + meminfo_buffer[len++] = value; } - meminfo_buffer[len++] = (unsigned long long)meminfo_key[i]; - meminfo_buffer[len++] = value; } - } - meminfo_length = len; - new_data_avail = true; -} + meminfo_length = len; + new_data_avail = true; + } -static void meminfo_wake_up_handler(unsigned long unused_data) -{ - // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater - schedule_work(&work); + return 0; } static int gator_events_meminfo_read(long long **buffer) { - static unsigned int last_mem_event = 0; - if (!on_primary_core() || !meminfo_global_enabled) return 0; - if (last_mem_event != mem_event) { - last_mem_event = mem_event; - mod_timer(&meminfo_wake_up_timer, jiffies + 1); - } - if (!new_data_avail) return 0; @@ -217,11 +274,97 @@ static int gator_events_meminfo_read(long long **buffer) return meminfo_length; } +static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct *task) +{ + struct mm_struct *mm; + u64 share = 0; + int i; + long long value; + int len = 0; + int cpu = get_physical_cpu(); + long long *buf = per_cpu(proc_buffer, cpu); + + if (!proc_global_enabled) { + return 0; + } + + // Collect the memory stats of the process instead of the thread + if (task->group_leader != NULL) { + task = task->group_leader; + } + + // get_task_mm/mmput is not needed in this context because the task and it's mm are required as part of the sched_switch + mm = task->mm; + if (mm == NULL) { + return 0; + } + + // Derived from task_statm in fs/proc/task_mmu.c + if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) { + share = get_mm_counter(mm, +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) + file_rss +#else + MM_FILEPAGES +#endif + ); + } + + // key of 1 indicates a pid + buf[len++] = 1; + buf[len++] = task->pid; + + for (i = 0; i < PROC_COUNT; ++i) { + if (proc_enabled[i]) { + switch (i) { + case PROC_SIZE: + value = mm->total_vm; + break; + case PROC_SHARE: + value = share; + break; + case PROC_TEXT: + value = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> PAGE_SHIFT; + break; + case PROC_DATA: + value = mm->total_vm - mm->shared_vm; + break; + } + + buf[len++] = proc_keys[i]; + buf[len++] = value * PAGE_SIZE; + } + } + + if (meminfo_enabled[MEMINFO_MEMUSED]) { + value = share + get_mm_counter(mm, +#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 32) + anon_rss +#else + MM_ANONPAGES +#endif + ); + // Send resident for this pid + buf[len++] = meminfo_keys[MEMINFO_MEMUSED]; + buf[len++] = value * PAGE_SIZE; + } + + // Clear pid + buf[len++] = 1; + buf[len++] = 0; + + if (buffer) + *buffer = buf; + + return len; +} + static struct gator_interface gator_events_meminfo_interface = { .create_files = gator_events_meminfo_create_files, .start = gator_events_meminfo_start, .stop = gator_events_meminfo_stop, .read64 = gator_events_meminfo_read, + .read_proc = gator_events_meminfo_read_proc, }; int gator_events_meminfo_init(void) @@ -231,10 +374,14 @@ int gator_events_meminfo_init(void) meminfo_global_enabled = 0; for (i = 0; i < MEMINFO_TOTAL; i++) { meminfo_enabled[i] = 0; - meminfo_key[i] = gator_events_get_key(); + meminfo_keys[i] = gator_events_get_key(); + } + + proc_global_enabled = 0; + for (i = 0; i < PROC_COUNT; ++i) { + proc_enabled[i] = 0; + proc_keys[i] = gator_events_get_key(); } return gator_events_install(&gator_events_meminfo_interface); } - -gator_events_init(gator_events_meminfo_init); diff --git a/driver/gator_events_mmaped.c b/driver/gator_events_mmaped.c deleted file mode 100644 index f7670f6..0000000 --- a/driver/gator_events_mmaped.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Example events provider - * - * Copyright (C) ARM Limited 2010-2013. 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. - * - * Similar entries to those below must be present in the events.xml file. - * To add them to the events.xml, create an events-mmap.xml with the - * following contents and rebuild gatord: - * - * - * - * - * - * - * - */ - -#include -#include -#include - -#include "gator.h" - -#define MMAPED_COUNTERS_NUM 3 - -static struct { - unsigned long enabled; - unsigned long event; - unsigned long key; -} mmaped_counters[MMAPED_COUNTERS_NUM]; - -static int mmaped_buffer[MMAPED_COUNTERS_NUM * 2]; - -#ifdef TODO -static void __iomem *mmaped_base; -#endif - -#ifndef TODO -static s64 prev_time; -#endif - -/* Adds mmaped_cntX directories and enabled, event, and key files to /dev/gator/events */ -static int gator_events_mmaped_create_files(struct super_block *sb, - struct dentry *root) -{ - int i; - - for (i = 0; i < MMAPED_COUNTERS_NUM; i++) { - char buf[16]; - struct dentry *dir; - - snprintf(buf, sizeof(buf), "mmaped_cnt%d", i); - dir = gatorfs_mkdir(sb, root, buf); - if (WARN_ON(!dir)) - return -1; - gatorfs_create_ulong(sb, dir, "enabled", - &mmaped_counters[i].enabled); - gatorfs_create_ulong(sb, dir, "event", - &mmaped_counters[i].event); - gatorfs_create_ro_ulong(sb, dir, "key", - &mmaped_counters[i].key); - } - - return 0; -} - -static int gator_events_mmaped_start(void) -{ -#ifdef TODO - for (i = 0; i < MMAPED_COUNTERS_NUM; i++) - writel(mmaped_counters[i].event, - mmaped_base + COUNTERS_CONFIG_OFFSET[i]); - - writel(ENABLED, COUNTERS_CONTROL_OFFSET); -#endif - -#ifndef TODO - struct timespec ts; - getnstimeofday(&ts); - prev_time = timespec_to_ns(&ts); -#endif - - return 0; -} - -static void gator_events_mmaped_stop(void) -{ -#ifdef TODO - writel(DISABLED, COUNTERS_CONTROL_OFFSET); -#endif -} - -#ifndef TODO -/* This function "simulates" counters, generating values of fancy - * functions like sine or triangle... */ -static int mmaped_simulate(int counter, int delta_in_us) -{ - int result = 0; - - switch (counter) { - case 0: /* sort-of-sine */ - { - static int t = 0; - int x; - - t += delta_in_us; - if (t > 2048000) - t = 0; - - if (t % 1024000 < 512000) - x = 512000 - (t % 512000); - else - x = t % 512000; - - result = 32 * x / 512000; - result = result * result; - - if (t < 1024000) - result = 1922 - result; - } - break; - case 1: /* triangle */ - { - static int v, d = 1; - - v = v + d * delta_in_us; - if (v < 0) { - v = 0; - d = 1; - } else if (v > 1000000) { - v = 1000000; - d = -1; - } - - result = v; - } - break; - case 2: /* PWM signal */ - { - static int dc, x, t = 0; - - t += delta_in_us; - if (t > 1000000) - t = 0; - if (x / 1000000 != (x + delta_in_us) / 1000000) - dc = (dc + 100000) % 1000000; - x += delta_in_us; - - result = t < dc ? 0 : 10; - } - break; - } - - return result; -} -#endif - -static int gator_events_mmaped_read(int **buffer) -{ - int i; - int len = 0; -#ifndef TODO - int delta_in_us; - struct timespec ts; - s64 time; -#endif - - /* System wide counters - read from one core only */ - if (!on_primary_core()) - return 0; - -#ifndef TODO - getnstimeofday(&ts); - time = timespec_to_ns(&ts); - delta_in_us = (int)(time - prev_time) / 1000; - prev_time = time; -#endif - - for (i = 0; i < MMAPED_COUNTERS_NUM; i++) { - if (mmaped_counters[i].enabled) { - mmaped_buffer[len++] = mmaped_counters[i].key; -#ifdef TODO - mmaped_buffer[len++] = - readl(mmaped_base + COUNTERS_VALUE_OFFSET[i]); -#else - mmaped_buffer[len++] = - mmaped_simulate(mmaped_counters[i].event, - delta_in_us); -#endif - } - } - - if (buffer) - *buffer = mmaped_buffer; - - return len; -} - -static struct gator_interface gator_events_mmaped_interface = { - .create_files = gator_events_mmaped_create_files, - .start = gator_events_mmaped_start, - .stop = gator_events_mmaped_stop, - .read = gator_events_mmaped_read, -}; - -/* Must not be static! */ -int __init gator_events_mmaped_init(void) -{ - int i; - -#ifdef TODO - mmaped_base = ioremap(COUNTERS_PHYS_ADDR, SZ_4K); - if (!mmaped_base) - return -ENOMEM; -#endif - - for (i = 0; i < MMAPED_COUNTERS_NUM; i++) { - mmaped_counters[i].enabled = 0; - mmaped_counters[i].key = gator_events_get_key(); - } - - return gator_events_install(&gator_events_mmaped_interface); -} - -gator_events_init(gator_events_mmaped_init); diff --git a/driver/gator_events_mmapped.c b/driver/gator_events_mmapped.c new file mode 100644 index 0000000..f055e48 --- /dev/null +++ b/driver/gator_events_mmapped.c @@ -0,0 +1,209 @@ +/* + * Example events provider + * + * Copyright (C) ARM Limited 2010-2013. 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. + * + * Similar entries to those below must be present in the events.xml file. + * To add them to the events.xml, create an events-mmap.xml with the + * following contents and rebuild gatord: + * + * + * + * + * + * + * + * + * When adding custom events, be sure do the following + * - add any needed .c files to the gator driver Makefile + * - call gator_events_install in the events init function + * - add the init function to GATOR_EVENTS_LIST in gator_main.c + * - add a new events-*.xml file to the gator daemon and rebuild + */ + +#include +#include +#include + +#include "gator.h" + +#define MMAPPED_COUNTERS_NUM 3 + +static int mmapped_global_enabled; + +static struct { + unsigned long enabled; + unsigned long event; + unsigned long key; +} mmapped_counters[MMAPPED_COUNTERS_NUM]; + +static int mmapped_buffer[MMAPPED_COUNTERS_NUM * 2]; + +static s64 prev_time; + +/* Adds mmapped_cntX directories and enabled, event, and key files to /dev/gator/events */ +static int gator_events_mmapped_create_files(struct super_block *sb, + struct dentry *root) +{ + int i; + + for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { + char buf[16]; + struct dentry *dir; + + snprintf(buf, sizeof(buf), "mmapped_cnt%d", i); + dir = gatorfs_mkdir(sb, root, buf); + if (WARN_ON(!dir)) + return -1; + gatorfs_create_ulong(sb, dir, "enabled", + &mmapped_counters[i].enabled); + gatorfs_create_ulong(sb, dir, "event", + &mmapped_counters[i].event); + gatorfs_create_ro_ulong(sb, dir, "key", + &mmapped_counters[i].key); + } + + return 0; +} + +static int gator_events_mmapped_start(void) +{ + int i; + struct timespec ts; + + getnstimeofday(&ts); + prev_time = timespec_to_ns(&ts); + + mmapped_global_enabled = 0; + for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { + if (mmapped_counters[i].enabled) { + mmapped_global_enabled = 1; + break; + } + } + + return 0; +} + +static void gator_events_mmapped_stop(void) +{ +} + +/* This function "simulates" counters, generating values of fancy + * functions like sine or triangle... */ +static int mmapped_simulate(int counter, int delta_in_us) +{ + int result = 0; + + switch (counter) { + case 0: /* sort-of-sine */ + { + static int t = 0; + int x; + + t += delta_in_us; + if (t > 2048000) + t = 0; + + if (t % 1024000 < 512000) + x = 512000 - (t % 512000); + else + x = t % 512000; + + result = 32 * x / 512000; + result = result * result; + + if (t < 1024000) + result = 1922 - result; + } + break; + case 1: /* triangle */ + { + static int v, d = 1; + + v = v + d * delta_in_us; + if (v < 0) { + v = 0; + d = 1; + } else if (v > 1000000) { + v = 1000000; + d = -1; + } + + result = v; + } + break; + case 2: /* PWM signal */ + { + static int dc, x, t = 0; + + t += delta_in_us; + if (t > 1000000) + t = 0; + if (x / 1000000 != (x + delta_in_us) / 1000000) + dc = (dc + 100000) % 1000000; + x += delta_in_us; + + result = t < dc ? 0 : 10; + } + break; + } + + return result; +} + +static int gator_events_mmapped_read(int **buffer) +{ + int i; + int len = 0; + int delta_in_us; + struct timespec ts; + s64 time; + + /* System wide counters - read from one core only */ + if (!on_primary_core() || !mmapped_global_enabled) + return 0; + + getnstimeofday(&ts); + time = timespec_to_ns(&ts); + delta_in_us = (int)(time - prev_time) / 1000; + prev_time = time; + + for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { + if (mmapped_counters[i].enabled) { + mmapped_buffer[len++] = mmapped_counters[i].key; + mmapped_buffer[len++] = + mmapped_simulate(mmapped_counters[i].event, + delta_in_us); + } + } + + if (buffer) + *buffer = mmapped_buffer; + + return len; +} + +static struct gator_interface gator_events_mmapped_interface = { + .create_files = gator_events_mmapped_create_files, + .start = gator_events_mmapped_start, + .stop = gator_events_mmapped_stop, + .read = gator_events_mmapped_read, +}; + +/* Must not be static! */ +int __init gator_events_mmapped_init(void) +{ + int i; + + for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) { + mmapped_counters[i].enabled = 0; + mmapped_counters[i].key = gator_events_get_key(); + } + + return gator_events_install(&gator_events_mmapped_interface); +} diff --git a/driver/gator_events_net.c b/driver/gator_events_net.c index 80cdee4..9c8d3a4 100644 --- a/driver/gator_events_net.c +++ b/driver/gator_events_net.c @@ -73,6 +73,8 @@ static void calculate_delta(int *rx, int *tx) static int gator_events_net_create_files(struct super_block *sb, struct dentry *root) { + // Network counters are not currently supported in RT-Preempt full because mod_timer is used +#ifndef CONFIG_PREEMPT_RT_FULL struct dentry *dir; dir = gatorfs_mkdir(sb, root, "Linux_net_rx"); @@ -88,6 +90,7 @@ static int gator_events_net_create_files(struct super_block *sb, struct dentry * } gatorfs_create_ulong(sb, dir, "enabled", &nettx_enabled); gatorfs_create_ro_ulong(sb, dir, "key", &nettx_key); +#endif return 0; } @@ -167,5 +170,3 @@ int gator_events_net_init(void) return gator_events_install(&gator_events_net_interface); } - -gator_events_init(gator_events_net_init); diff --git a/driver/gator_events_perf_pmu.c b/driver/gator_events_perf_pmu.c index 53b2d0a..d472df9 100644 --- a/driver/gator_events_perf_pmu.c +++ b/driver/gator_events_perf_pmu.c @@ -6,13 +6,18 @@ * published by the Free Software Foundation. */ -#include -#include #include "gator.h" // gator_events_armvX.c is used for Linux 2.6.x #if GATOR_PERF_PMU_SUPPORT +#include +#ifdef CONFIG_OF +#include +#endif +#include +#include + extern bool event_based_sampling; // Maximum number of per-core counters - currently reserves enough space for two full hardware PMUs for big.LITTLE @@ -22,6 +27,9 @@ extern bool event_based_sampling; // + 1 for the cci-400 cycles counter #define UCCNT (CCI_400 + 1) +// Default to 0 if unable to probe the revision which was the previous behavior +#define DEFAULT_CCI_REVISION 0 + // A gator_attr is needed for every counter struct gator_attr { // Set once in gator_events_perf_pmu_*_init - the name of the event in the gatorfs @@ -404,17 +412,81 @@ static void __attr_init(struct gator_attr *const attr) attr->key = gator_events_get_key(); } +#ifdef CONFIG_OF + +static const struct of_device_id arm_cci_matches[] = { + {.compatible = "arm,cci-400" }, + {}, +}; + +static int probe_cci_revision(void) +{ + struct device_node *np; + struct resource res; + void __iomem *cci_ctrl_base; + int rev; + int ret = DEFAULT_CCI_REVISION; + + np = of_find_matching_node(NULL, arm_cci_matches); + if (!np) { + return ret; + } + + if (of_address_to_resource(np, 0, &res)) { + goto node_put; + } + + cci_ctrl_base = ioremap(res.start, resource_size(&res)); + + rev = (readl_relaxed(cci_ctrl_base + 0xfe8) >> 4) & 0xf; + + if (rev <= 4) { + ret = 0; + } else if (rev <= 6) { + ret = 1; + } + + iounmap(cci_ctrl_base); + + node_put: + of_node_put(np); + + return ret; +} + +#else + +static int probe_cci_revision(void) +{ + return DEFAULT_CCI_REVISION; +} + +#endif + static void gator_events_perf_pmu_cci_init(const int type) { int cnt; + const char *cci_name; + + switch (probe_cci_revision()) { + case 0: + cci_name = "cci-400"; + break; + case 1: + cci_name = "cci-400-r1"; + break; + default: + pr_debug("gator: unrecognized cci-400 revision\n"); + return; + } - strncpy(uc_attrs[uc_attr_count].name, "cci-400_ccnt", sizeof(uc_attrs[uc_attr_count].name)); + snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", cci_name); uc_attrs[uc_attr_count].type = type; ++uc_attr_count; for (cnt = 0; cnt < CCI_400; ++cnt, ++uc_attr_count) { struct gator_attr *const attr = &uc_attrs[uc_attr_count]; - snprintf(attr->name, sizeof(attr->name), "cci-400_cnt%d", cnt); + snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", cci_name, cnt); attr->type = type; } } @@ -477,7 +549,7 @@ int gator_events_perf_pmu_init(void) } if (pe->pmu != NULL && type == pe->pmu->type) { - if (strcmp("CCI", pe->pmu->name) == 0) { + if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0) { gator_events_perf_pmu_cci_init(type); } else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) { found_cpu = true; @@ -512,5 +584,4 @@ int gator_events_perf_pmu_init(void) return gator_events_install(&gator_events_perf_pmu_interface); } -gator_events_init(gator_events_perf_pmu_init); #endif diff --git a/driver/gator_events_sched.c b/driver/gator_events_sched.c index 461a051..29f4e39 100644 --- a/driver/gator_events_sched.c +++ b/driver/gator_events_sched.c @@ -111,5 +111,3 @@ int gator_events_sched_init(void) return gator_events_install(&gator_events_sched_interface); } - -gator_events_init(gator_events_sched_init); diff --git a/driver/gator_events_scorpion.c b/driver/gator_events_scorpion.c index aaf306a..c91db12 100644 --- a/driver/gator_events_scorpion.c +++ b/driver/gator_events_scorpion.c @@ -666,11 +666,4 @@ int gator_events_scorpion_init(void) return gator_events_install(&gator_events_scorpion_interface); } -gator_events_init(gator_events_scorpion_init); - -#else -int gator_events_scorpion_init(void) -{ - return -1; -} #endif diff --git a/driver/gator_main.c b/driver/gator_main.c index 7dd70d9..9773ae2 100644 --- a/driver/gator_main.c +++ b/driver/gator_main.c @@ -8,7 +8,8 @@ */ // This version must match the gator daemon version -static unsigned long gator_protocol_version = 16; +#define PROTOCOL_VERSION 17 +static unsigned long gator_protocol_version = PROTOCOL_VERSION; #include #include @@ -22,16 +23,20 @@ static unsigned long gator_protocol_version = 16; #include #include #include +#include #include #include #include "gator.h" -#include "gator_events.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) #error kernels prior to 2.6.32 are not supported #endif +#if defined(MODULE) && !defined(CONFIG_MODULES) +#error Cannot build a module against a kernel that does not support modules. To resolve, either rebuild the kernel to support modules or build gator as part of the kernel. +#endif + #if !defined(CONFIG_GENERIC_TRACER) && !defined(CONFIG_TRACING) #error gator requires the kernel to have CONFIG_GENERIC_TRACER or CONFIG_TRACING defined #endif @@ -44,7 +49,7 @@ static unsigned long gator_protocol_version = 16; #error gator requires the kernel to have CONFIG_HIGH_RES_TIMERS defined to support PC sampling #endif -#if defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) && defined(__arm__) && defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) #error gator requires the kernel to have CONFIG_LOCAL_TIMERS defined on SMP systems #endif @@ -87,6 +92,7 @@ static unsigned long gator_protocol_version = 16; #define MESSAGE_COOKIE 1 #define MESSAGE_THREAD_NAME 2 #define HRTIMER_CORE_NAME 3 +#define MESSAGE_LINK 4 #define MESSAGE_GPU_START 1 #define MESSAGE_GPU_STOP 2 @@ -136,6 +142,7 @@ static u64 gator_live_rate; static unsigned long gator_started; static u64 gator_monotonic_started; +static u64 gator_hibernate_time; static unsigned long gator_buffer_opened; static unsigned long gator_timer_count; static unsigned long gator_response_type; @@ -147,6 +154,8 @@ bool event_based_sampling; static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait); static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait); static struct timer_list gator_buffer_wake_up_timer; +static bool gator_buffer_wake_stop; +static struct task_struct *gator_buffer_wake_thread; static LIST_HEAD(gator_events); static DEFINE_PER_CPU(u64, last_timestamp); @@ -189,6 +198,34 @@ static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer); // The time after which the buffer should be committed for live display static DEFINE_PER_CPU(u64, gator_buffer_commit_time); +// List of all gator events - new events must be added to this list +#define GATOR_EVENTS_LIST \ + GATOR_EVENT(gator_events_armv6_init) \ + GATOR_EVENT(gator_events_armv7_init) \ + GATOR_EVENT(gator_events_block_init) \ + GATOR_EVENT(gator_events_ccn504_init) \ + GATOR_EVENT(gator_events_irq_init) \ + GATOR_EVENT(gator_events_l2c310_init) \ + GATOR_EVENT(gator_events_mali_init) \ + GATOR_EVENT(gator_events_mali_t6xx_hw_init) \ + GATOR_EVENT(gator_events_mali_t6xx_init) \ + GATOR_EVENT(gator_events_meminfo_init) \ + GATOR_EVENT(gator_events_mmapped_init) \ + GATOR_EVENT(gator_events_net_init) \ + GATOR_EVENT(gator_events_perf_pmu_init) \ + GATOR_EVENT(gator_events_sched_init) \ + GATOR_EVENT(gator_events_scorpion_init) \ + +#define GATOR_EVENT(EVENT_INIT) __weak int EVENT_INIT(void); +GATOR_EVENTS_LIST +#undef GATOR_EVENT + +static int (*gator_events_list[])(void) = { +#define GATOR_EVENT(EVENT_INIT) EVENT_INIT, +GATOR_EVENTS_LIST +#undef GATOR_EVENT +}; + /****************************************************************************** * Application Includes ******************************************************************************/ @@ -392,6 +429,21 @@ static void gator_buffer_wake_up(unsigned long data) wake_up(&gator_buffer_wait); } +static int gator_buffer_wake_func(void *data) +{ + while (!gator_buffer_wake_stop) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + if (gator_buffer_wake_stop) { + break; + } + + gator_buffer_wake_up(0); + } + + return 0; +} + /****************************************************************************** * Commit interface ******************************************************************************/ @@ -517,7 +569,14 @@ static void gator_commit_buffer(int cpu, int buftype, u64 time) marshal_frame(cpu, buftype); // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater - mod_timer(&gator_buffer_wake_up_timer, jiffies + 1); + if (per_cpu(in_scheduler_context, cpu)) { +#ifndef CONFIG_PREEMPT_RT_FULL + // mod_timer can not be used in interrupt context in RT-Preempt full + mod_timer(&gator_buffer_wake_up_timer, jiffies + 1); +#endif + } else { + wake_up_process(gator_buffer_wake_thread); + } } static void buffer_check(int cpu, int buftype, u64 time) @@ -590,8 +649,13 @@ void gator_backtrace_handler(struct pt_regs *const regs) // Collect counters if (!per_cpu(collecting, cpu)) { - collect_counters(time); + collect_counters(time, NULL); } + + // No buffer flushing occurs during sched switch for RT-Preempt full. The block counter frame will be flushed by collect_counters, but the sched buffer needs to be explicitly flushed +#ifdef CONFIG_PREEMPT_RT_FULL + buffer_check(cpu, SCHED_TRACE_BUF, time); +#endif } static int gator_running; @@ -815,6 +879,7 @@ static struct notifier_block __refdata gator_hotcpu_notifier = { static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy) { int cpu; + struct timespec ts; switch (event) { case PM_HIBERNATION_PREPARE: @@ -825,9 +890,20 @@ static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void for_each_online_cpu(cpu) { gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false); } + + // Record the wallclock hibernate time + getnstimeofday(&ts); + gator_hibernate_time = timespec_to_ns(&ts) - gator_get_time(); break; case PM_POST_HIBERNATION: case PM_POST_SUSPEND: + // Adjust gator_monotonic_started for the time spent sleeping, as gator_get_time does not account for it + if (gator_hibernate_time > 0) { + getnstimeofday(&ts); + gator_monotonic_started += gator_hibernate_time + gator_get_time() - timespec_to_ns(&ts); + gator_hibernate_time = 0; + } + for_each_online_cpu(cpu) { gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false); } @@ -902,8 +978,10 @@ int gator_events_install(struct gator_interface *interface) int gator_events_get_key(void) { - // key of zero is reserved as a timestamp - static int key = 1; + // key 0 is reserved as a timestamp + // key 1 is reserved as the marker for thread specific counters + // Odd keys are assigned by the driver, even keys by the daemon + static int key = 3; const int ret = key; key += 2; @@ -916,7 +994,7 @@ static int gator_init(void) calc_first_cluster_size(); - // events sources (gator_events.h, generated by gator_events.sh) + // events sources for (i = 0; i < ARRAY_SIZE(gator_events_list); i++) if (gator_events_list[i]) gator_events_list[i](); @@ -941,6 +1019,11 @@ static int gator_start(void) unsigned long cpu, i; struct gator_interface *gi; + gator_buffer_wake_stop = false; + if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) { + goto bwake_failure; + } + if (gator_migrate_start()) goto migrate_failure; @@ -1011,6 +1094,9 @@ cookies_failure: events_failure: gator_migrate_stop(); migrate_failure: + gator_buffer_wake_stop = true; + wake_up_process(gator_buffer_wake_thread); +bwake_failure: return -1; } @@ -1034,6 +1120,9 @@ static void gator_stop(void) gi->stop(); gator_migrate_stop(); + + gator_buffer_wake_stop = true; + wake_up_process(gator_buffer_wake_thread); } /****************************************************************************** @@ -1438,3 +1527,6 @@ module_exit(gator_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("ARM Ltd"); MODULE_DESCRIPTION("Gator system profiler"); +#define STRIFY2(ARG) #ARG +#define STRIFY(ARG) STRIFY2(ARG) +MODULE_VERSION(STRIFY(PROTOCOL_VERSION)); diff --git a/driver/gator_marshaling.c b/driver/gator_marshaling.c index 3282de8..af80ff6 100644 --- a/driver/gator_marshaling.c +++ b/driver/gator_marshaling.c @@ -89,6 +89,25 @@ static void marshal_thread_name(int pid, char *name) local_irq_restore(flags); } +static void marshal_link(int cookie, int tgid, int pid) +{ + unsigned long cpu = get_physical_cpu(), flags; + u64 time; + + local_irq_save(flags); + time = gator_get_time(); + if (buffer_check_space(cpu, NAME_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { + gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_LINK); + gator_buffer_write_packed_int64(cpu, NAME_BUF, time); + gator_buffer_write_packed_int(cpu, NAME_BUF, cookie); + gator_buffer_write_packed_int(cpu, NAME_BUF, tgid); + gator_buffer_write_packed_int(cpu, NAME_BUF, pid); + } + // Check and commit; commit is set to occur once buffer is 3/4 full + buffer_check(cpu, NAME_BUF, time); + local_irq_restore(flags); +} + static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, int inKernel, u64 time) { int cpu = get_physical_cpu(); diff --git a/driver/gator_trace_gpu.c b/driver/gator_trace_gpu.c index 12623c4..be135b4 100644 --- a/driver/gator_trace_gpu.c +++ b/driver/gator_trace_gpu.c @@ -85,7 +85,7 @@ static void mali_gpu_stop(int unit, int core) int count; int last_tgid = 0; int last_pid = 0; - int last_job_id = 0; + //int last_job_id = 0; spin_lock(&mali_gpu_jobs_lock); if (mali_gpu_jobs[unit][core].count == 0) { @@ -97,7 +97,7 @@ static void mali_gpu_stop(int unit, int core) if (count) { last_tgid = mali_gpu_jobs[unit][core].last_tgid; last_pid = mali_gpu_jobs[unit][core].last_pid; - last_job_id = mali_gpu_jobs[unit][core].last_job_id; + //last_job_id = mali_gpu_jobs[unit][core].last_job_id; } spin_unlock(&mali_gpu_jobs_lock); @@ -242,7 +242,7 @@ int gator_trace_gpu_start(void) * Absence of gpu trace points is not an error */ - memset(&mali_gpu_jobs, sizeof(mali_gpu_jobs), 0); + memset(&mali_gpu_jobs, 0, sizeof(mali_gpu_jobs)); gpu_trace_registered = mali_timeline_trace_registered = mali_job_slots_trace_registered = 0; #if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx) diff --git a/driver/gator_trace_sched.c b/driver/gator_trace_sched.c index e98815e..332b3f6 100644 --- a/driver/gator_trace_sched.c +++ b/driver/gator_trace_sched.c @@ -22,6 +22,7 @@ enum { static DEFINE_PER_CPU(uint64_t *, taskname_keys); static DEFINE_PER_CPU(int, collecting); +static DEFINE_PER_CPU(bool, in_scheduler_context); // this array is never read as the cpu wait charts are derived counters // the files are needed, nonetheless, to show that these counters are available @@ -89,7 +90,7 @@ void emit_pid_name(struct task_struct *task) } } -static void collect_counters(u64 time) +static void collect_counters(u64 time, struct task_struct *task) { int *buffer, len, cpu = get_physical_cpu(); long long *buffer64; @@ -104,17 +105,26 @@ static void collect_counters(u64 time) len = gi->read64(&buffer64); marshal_event64(len, buffer64); } + if (gi->read_proc && task != NULL) { + len = gi->read_proc(&buffer64, task); + marshal_event64(len, buffer64); + } } // Only check after writing all counters so that time and corresponding counters appear in the same frame buffer_check(cpu, BLOCK_COUNTER_BUF, time); // Commit buffers on timeout if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) { - static const int buftypes[] = { COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF }; + static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF }; + unsigned long flags; int i; + + local_irq_save(flags); for (i = 0; i < ARRAY_SIZE(buftypes); ++i) { gator_commit_buffer(cpu, buftypes[i], time); } + local_irq_restore(flags); + // Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full if (on_primary_core() && spin_trylock(&annotate_lock)) { gator_commit_buffer(0, ANNOTATE_BUF, time); @@ -151,6 +161,8 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_ int state; int cpu = get_physical_cpu(); + per_cpu(in_scheduler_context, cpu) = true; + // do as much work as possible before disabling interrupts cookie = get_exec_cookie(cpu, next); emit_pid_name(next); @@ -163,10 +175,12 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_ } per_cpu(collecting, cpu) = 1; - collect_counters(gator_get_time()); + collect_counters(gator_get_time(), prev); per_cpu(collecting, cpu) = 0; marshal_sched_trace_switch(next->tgid, next->pid, cookie, state); + + per_cpu(in_scheduler_context, cpu) = false; } GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p)) diff --git a/driver/mali/mali_mjollnir_profiling_gator_api.h b/driver/mali/mali_mjollnir_profiling_gator_api.h index 3db4543..347a4fe 100644 --- a/driver/mali/mali_mjollnir_profiling_gator_api.h +++ b/driver/mali/mali_mjollnir_profiling_gator_api.h @@ -1,11 +1,10 @@ -/* - * This confidential and proprietary software may be used only as - * authorised by a licensing agreement from ARM Limited - * (C) COPYRIGHT 2013 ARM Limited - * ALL RIGHTS RESERVED - * The entire notice above must be reproduced on all authorised - * copies and copies may only be made to the extent permitted - * by a licensing agreement from ARM Limited. +/** + * Copyright (C) ARM Limited 2013. 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 __MALI_MJOLLNIR_PROFILING_GATOR_API_H__ diff --git a/driver/mali/mali_utgard_profiling_gator_api.h b/driver/mali/mali_utgard_profiling_gator_api.h index c02a1a4..559647a 100644 --- a/driver/mali/mali_utgard_profiling_gator_api.h +++ b/driver/mali/mali_utgard_profiling_gator_api.h @@ -1,11 +1,10 @@ -/* - * This confidential and proprietary software may be used only as - * authorised by a licensing agreement from ARM Limited - * (C) COPYRIGHT 2013 ARM Limited - * ALL RIGHTS RESERVED - * The entire notice above must be reproduced on all authorised - * copies and copies may only be made to the extent permitted - * by a licensing agreement from ARM Limited. +/** + * Copyright (C) ARM Limited 2013. 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 __MALI_UTGARD_PROFILING_GATOR_API_H__ diff --git a/driver/mali_t6xx.mk b/driver/mali_t6xx.mk index 2cc6411..1a98c1c 100644 --- a/driver/mali_t6xx.mk +++ b/driver/mali_t6xx.mk @@ -9,16 +9,17 @@ EXTRA_CFLAGS += -DMALI_USE_UMP=1 \ -DMALI_BACKEND_KERNEL=1 \ -DMALI_NO_MALI=0 -KBASE_DIR = $(DDK_DIR)/kernel/drivers/gpu/arm/t6xx/kbase -OSK_DIR = $(DDK_DIR)/kernel/drivers/gpu/arm/t6xx/kbase/osk -UMP_DIR = $(DDK_DIR)/kernel/include/linux +DDK_DIR ?= . +KBASE_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase +OSK_DIR = $(DDK_DIR)/drivers/gpu/arm/t6xx/kbase/osk +UMP_DIR = $(DDK_DIR)/include/linux # Include directories in the DDK -EXTRA_CFLAGS += -I$(DDK_DIR) \ +EXTRA_CFLAGS += -I$(KBASE_DIR)/ \ -I$(KBASE_DIR)/.. \ -I$(OSK_DIR)/.. \ -I$(UMP_DIR)/.. \ - -I$(DDK_DIR)/kernel/include \ + -I$(DDK_DIR)/include \ -I$(KBASE_DIR)/osk/src/linux/include \ -I$(KBASE_DIR)/platform_dummy \ -I$(KBASE_DIR)/src -- cgit v1.2.3