aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrew Richardson <drew.richardson@arm.com>2013-12-16 12:00:00 -0800
committerDrew Richardson <drew.richardson@arm.com>2014-12-19 15:48:40 -0800
commit9b0375410d73fb0de515ee33e0dd7f054cd45a6f (patch)
tree6a2a9dfa45fe1a25b0959f10401e200687fd1a03
parentdf48c99f8da89ef9a91fac638b8e0528507bd088 (diff)
gator: Version 5.175.17
Signed-off-by: Drew Richardson <drew.richardson@arm.com>
-rw-r--r--README_Streamline.txt23
-rw-r--r--daemon/Buffer.cpp11
-rw-r--r--daemon/Buffer.h5
-rw-r--r--daemon/Child.cpp13
-rw-r--r--daemon/Child.h4
-rw-r--r--daemon/ConfigurationXML.h4
-rw-r--r--daemon/Driver.h6
-rw-r--r--daemon/Fifo.h4
-rw-r--r--daemon/Hwmon.cpp4
-rw-r--r--daemon/Hwmon.h4
-rw-r--r--daemon/OlySocket.cpp23
-rw-r--r--daemon/Sender.h4
-rw-r--r--daemon/SessionData.cpp12
-rw-r--r--daemon/SessionData.h6
-rw-r--r--daemon/SessionXML.h4
-rw-r--r--daemon/StreamlineSetup.h4
-rw-r--r--daemon/common.mk2
-rw-r--r--daemon/events-CCI-400.xml62
-rw-r--r--daemon/events-Linux.xml10
-rw-r--r--daemon/events-Mali-T6xx.xml10
-rw-r--r--daemon/events-Mali-T6xx_hw.xml5
-rw-r--r--daemon/main.cpp25
-rw-r--r--driver/Makefile61
-rw-r--r--driver/gator.h6
-rw-r--r--driver/gator_annotate_kernel.c107
-rw-r--r--driver/gator_backtrace.c10
-rw-r--r--driver/gator_cookies.c36
-rw-r--r--driver/gator_events.sh19
-rw-r--r--driver/gator_events_armv6.c7
-rw-r--r--driver/gator_events_armv7.c7
-rw-r--r--driver/gator_events_block.c2
-rw-r--r--driver/gator_events_ccn-504.c192
-rw-r--r--driver/gator_events_irq.c2
-rw-r--r--driver/gator_events_l2c-310.c2
-rw-r--r--driver/gator_events_mali_4xx.c30
-rw-r--r--driver/gator_events_mali_common.c9
-rw-r--r--driver/gator_events_mali_common.h4
-rw-r--r--driver/gator_events_mali_t6xx.c60
-rw-r--r--driver/gator_events_mali_t6xx_hw.c46
-rw-r--r--driver/gator_events_meminfo.c301
-rw-r--r--driver/gator_events_mmapped.c (renamed from driver/gator_events_mmaped.c)124
-rw-r--r--driver/gator_events_net.c5
-rw-r--r--driver/gator_events_perf_pmu.c83
-rw-r--r--driver/gator_events_sched.c2
-rw-r--r--driver/gator_events_scorpion.c7
-rw-r--r--driver/gator_main.c108
-rw-r--r--driver/gator_marshaling.c19
-rw-r--r--driver/gator_trace_gpu.c6
-rw-r--r--driver/gator_trace_sched.c20
-rw-r--r--driver/mali/mali_mjollnir_profiling_gator_api.h15
-rw-r--r--driver/mali/mali_utgard_profiling_gator_api.h15
-rw-r--r--driver/mali_t6xx.mk11
52 files changed, 1076 insertions, 485 deletions
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=<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 <stdio.h>
#ifdef WIN32
#include <Winsock2.h>
+#include <ws2tcpip.h>
#else
#include <netinet/in.h>
#include <sys/socket.h>
@@ -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 @@
<event event="0x04" option_set="Slave" title="CCI-400" name="Read: cache" description="Read request handshake: cache maintenance operation, CleanInvalid, CleanShared, MakeInvalid"/>
<event event="0x05" option_set="Slave" title="CCI-400" name="Read: memory barrier" description="Read request handshake: memory barrier"/>
<event event="0x06" option_set="Slave" title="CCI-400" name="Read: sync barrier" description="Read request handshake: synchronization barrier"/>
- <event event="0x07" option_set="Slave" title="CCI-400" name="Read: DVM message, no sync" description="Read request handshake: DVM message, no synchronization"/>
+ <event event="0x07" option_set="Slave" title="CCI-400" name="Read: DVM message, no sync" description="Read request handshake: DVM message, not synchronization"/>
<event event="0x08" option_set="Slave" title="CCI-400" name="Read: DVM message, sync" description="Read request handshake: DVM message, synchronization"/>
<event event="0x09" option_set="Slave" title="CCI-400" name="Read: stall" description="Read request stall cycle because the transaction tracker is full. Increase SIx_R_MAX to avoid this stall"/>
<event event="0x0a" option_set="Slave" title="CCI-400" name="Read data last handshake" description="Read data last handshake: data returned from the snoop instead of from downstream"/>
@@ -45,3 +45,63 @@
<event event="0x19" option_set="Master" title="CCI-400" name="Write stall: barrier hazard" description="Write request stall cycle because of a barrier hazard"/>
<event event="0x1a" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase MIx_W_MAX to avoid this stall. See the CoreLink CCI-400 Cache Coherent Interconnect Integration Manual"/>
</category>
+
+ <counter_set name="cci-400-r1_cnt" count="4"/>
+ <category name="CCI-400" counter_set="cci-400-r1_cnt" per_cpu="no" supports_event_based_sampling="yes">
+ <event counter="cci-400-r1_ccnt" event="0xff" title="CCI-400 Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" description="The number of core clock cycles"/>
+
+ <option_set name="Slave">
+ <option event_delta="0x00" name="S0" description="Slave interface 0"/>
+ <option event_delta="0x20" name="S1" description="Slave interface 1"/>
+ <option event_delta="0x40" name="S2" description="Slave interface 2"/>
+ <option event_delta="0x60" name="S3" description="Slave interface 3"/>
+ <option event_delta="0x80" name="S4" description="Slave interface 4"/>
+ </option_set>
+
+ <event event="0x00" option_set="Slave" title="CCI-400" name="Read: any" description="Read request handshake: any"/>
+ <event event="0x01" option_set="Slave" title="CCI-400" name="Read: transaction" description="Read request handshake: device transaction"/>
+ <event event="0x02" option_set="Slave" title="CCI-400" name="Read: normal" description="Read request handshake: normal, non-shareable or system-shareable, but not barrier or cache maintenance operation"/>
+ <event event="0x03" option_set="Slave" title="CCI-400" name="Read: shareable" description="Read request handshake: inner- or outer-shareable, but not barrier, DVM message or cache maintenance operation"/>
+ <event event="0x04" option_set="Slave" title="CCI-400" name="Read: cache" description="Read request handshake: cache maintenance operation"/>
+ <event event="0x05" option_set="Slave" title="CCI-400" name="Read: memory barrier" description="Read request handshake: memory barrier"/>
+ <event event="0x06" option_set="Slave" title="CCI-400" name="Read: sync barrier" description="Read request handshake: synchronization barrier"/>
+ <event event="0x07" option_set="Slave" title="CCI-400" name="Read: DVM message, no sync" description="Read request handshake: DVM message, not synchronization"/>
+ <event event="0x08" option_set="Slave" title="CCI-400" name="Read: DVM message, sync" description="Read request handshake: DVM message, synchronization"/>
+ <event event="0x09" option_set="Slave" title="CCI-400" name="Read: stall" description="Read request stall cycle because the transaction tracker is full. Increase SIx_R_MAX to avoid this stall"/>
+ <event event="0x0a" option_set="Slave" title="CCI-400" name="Read data last handshake" description="Read data last handshake: data returned from the snoop instead of from downstream"/>
+ <event event="0x0b" option_set="Slave" title="CCI-400" name="Read data stall cycle" description="Read data stall cycle: RVALIDS is HIGH, RREADYS is LOW"/>
+ <event event="0x0c" option_set="Slave" title="CCI-400" name="Write: any" description="Write request handshake: any"/>
+ <event event="0x0d" option_set="Slave" title="CCI-400" name="Write: transaction" description="Write request handshake: device transaction"/>
+ <event event="0x0e" option_set="Slave" title="CCI-400" name="Write: normal" description="Write request handshake: normal, non-shareable, or system-shareable, but not barrier"/>
+ <event event="0x0f" option_set="Slave" title="CCI-400" name="Write: shareable" description="Write request handshake: inner- or outer-shareable, WriteBack or WriteClean"/>
+ <event event="0x10" option_set="Slave" title="CCI-400" name="Write: WriteUnique" description="Write request handshake: WriteUnique"/>
+ <event event="0x11" option_set="Slave" title="CCI-400" name="Write: WriteLineUnique" description="Write request handshake: WriteLineUnique"/>
+ <event event="0x12" option_set="Slave" title="CCI-400" name="Write: Evict" description="Write request handshake: Evict"/>
+ <event event="0x13" option_set="Slave" title="CCI-400" name="Write stall: tracker full" description="Write request stall cycle because the transaction tracker is full. Increase SIx_W_MAX to avoid this stall"/>
+ <event event="0x14" option_set="Slave" title="CCI-400" name="Read stall: slave hazard" description="Read request stall cycle because of a slave interface ID hazard"/>
+
+ <option_set name="Master">
+ <option event_delta="0xa0" name="M0" description="Master interface 0"/>
+ <option event_delta="0xc0" name="M1" description="Master interface 1"/>
+ <option event_delta="0xe0" name="M2" description="Master interface 2"/>
+ </option_set>
+
+ <event event="0x00" option_set="Master" title="CCI-400" name="Retry fetch" description="RETRY of speculative fetch transaction"/>
+ <event event="0x01" option_set="Master" title="CCI-400" name="Read stall: address hazard" description="Stall cycle because of an address hazard. A read or write invalidation is stalled because of an outstanding transaction to an overlapping address"/>
+ <event event="0x02" option_set="Master" title="CCI-400" name="Read stall: ID hazard" description="Read request stall cycle because of a master interface ID hazard"/>
+ <event event="0x03" option_set="Master" title="CCI-400" name="Read stall: tracker full" description="A read request with a QoS value in the high priority group is stalled for a cycle because the read transaction queue is full. Increase MIx_R_MAX to avoid this stall"/>
+ <event event="0x04" option_set="Master" title="CCI-400" name="Read stall: barrier hazard" description="Read request stall cycle because of a barrier hazard"/>
+ <event event="0x05" option_set="Master" title="CCI-400" name="Write stall: barrier hazard" description="Write request stall cycle because of a barrier hazard"/>
+ <event event="0x06" option_set="Master" title="CCI-400" name="Write stall: tracker full" description="A write request is stalled for a cycle because the write transaction tracker is full. Increase MIx_W_MAX to avoid this stall"/>
+ <event event="0x07" option_set="Master" title="CCI-400" name="Read Stall: Low Priority" description="A read request with a QoS value in the low priority group is stalled for a cycle because there are no slots available in the read queue for the low priority group"/>
+ <event event="0x08" option_set="Master" title="CCI-400" name="Read Stall: Medium Priority" description="A read request with a QoS value in the medium priority group is stalled for a cycle because there are no slots available in the read queue for the medium priority group"/>
+ <event event="0x09" option_set="Master" title="CCI-400" name="Read Stall: VN0" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN0"/>
+ <event event="0x0a" option_set="Master" title="CCI-400" name="Read Stall: VN1" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN1"/>
+ <event event="0x0b" option_set="Master" title="CCI-400" name="Read Stall: VN2" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN2"/>
+ <event event="0x0c" option_set="Master" title="CCI-400" name="Read Stall: VN3" description="A read request is stalled for a cycle while it was waiting for a QVN token on VN3"/>
+ <event event="0x0d" option_set="Master" title="CCI-400" name="Write Stall: VN0" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN0"/>
+ <event event="0x0e" option_set="Master" title="CCI-400" name="Write Stall: VN1" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN1"/>
+ <event event="0x0f" option_set="Master" title="CCI-400" name="Write Stall: VN2" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN2"/>
+ <event event="0x10" option_set="Master" title="CCI-400" name="Write Stall: VN" description="A write request is stalled for a cycle while it was waiting for a QVN token on VN"/>
+ <event event="0x11" option_set="Master" title="CCI-400" name="WriteUnique or WriteLineUnique Stall" description="A WriteUnique or WriteLineUnique request is stalled for a cycle because of an address hazard"/>
+ </category>
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 @@
<event counter="Linux_net_rx" title="Network" name="Receive" units="B" description="Receive network traffic, including effect from Streamline"/>
<event counter="Linux_net_tx" title="Network" name="Transmit" units="B" description="Transmit network traffic, including effect from Streamline"/>
<event counter="Linux_sched_switch" title="Scheduler" name="Switch" per_cpu="yes" description="Context switch events"/>
- <event counter="Linux_meminfo_memused" title="Memory" name="Used" display="maximum" units="B" average_selection="yes" description="Total used memory size"/>
- <event counter="Linux_meminfo_memfree" title="Memory" name="Free" display="minimum" units="B" average_selection="yes" description="Available memory size"/>
- <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" display="maximum" units="B" average_selection="yes" description="Memory used by OS disk buffers"/>
- <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" display="maximum" units="Hz" series_composition="overlay" average_selection="yes" average_cores="yes" description="Frequency setting of the CPU"/>
- <event counter="Linux_power_cpu_idle" title="Idle" name="State" per_cpu="yes" display="maximum" average_selection="yes" description="CPU Idle State + 1, set the Sample Rate to None to prevent the hrtimer from interrupting the system"/>
+ <event counter="Linux_meminfo_memused" title="Memory" name="Used" display="maximum" units="B" proc="yes" description="Total used memory size. Note: a process' used memory includes shared memory that may be counted more than once (equivalent to RES from top). Kernel threads are not filterable."/>
+ <event counter="Linux_meminfo_memfree" title="Memory" name="Free" display="minimum" units="B" description="Available memory size"/>
+ <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" display="maximum" units="B" description="Memory used by OS disk buffers"/>
+ <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" display="maximum" units="Hz" series_composition="overlay" average_cores="yes" description="Frequency setting of the CPU"/>
+ <event counter="Linux_power_cpu_idle" title="Idle" name="State" per_cpu="yes" display="maximum" description="CPU Idle State + 1, set the Sample Rate to None to prevent the hrtimer from interrupting the system"/>
<event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" display="average" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on contended resource"/>
<event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" display="average" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on I/O resource"/>
</category>
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 @@
<event counter="ARM_Mali-T6xx_MMU_PAGE_FAULT_2" title="Mali MMU Page Fault Add. Space" name="Mali MMU Page Fault Add. Space 2" description="Reports the number of newly allocated pages after a MMU page fault in address space 2."/>
<event counter="ARM_Mali-T6xx_MMU_PAGE_FAULT_3" title="Mali MMU Page Fault Add. Space" name="Mali MMU Page Fault Add. Space 3" description="Reports the number of newly allocated pages after a MMU page fault in address space 3."/>
</category>
+
+ <counter_set name="ARM_Mali-T6xx_Filmstrip_cnt" count="1"/>
+ <category name="ARM Mali-T6xx Filmstrip" counter_set="ARM_Mali-T6xx_Filmstrip_cnt" per_cpu="no">
+ <option_set name="fs">
+ <option event_delta="0x3c" name="1:60" description="captures every 60th frame"/>
+ <option event_delta="0x1e" name="1:30" description="captures every 30th frame"/>
+ <option event_delta="0xa" name="1:10" description="captures every 10th frame"/>
+ </option_set>
+ <event event="0x0400" option_set="fs" title="ARM Mali-T6xx" name="Filmstrip" description="Scaled framebuffer"/>
+ </category>
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 @@
<event counter="ARM_Mali-T6xx_FRAG_THREADS" title="Mali Core Threads" name="Fragment threads" description="Number of fragment threads started"/>
<event counter="ARM_Mali-T6xx_FRAG_DUMMY_THREADS" title="Mali Core Threads" name="Dummy fragment threads" description="Number of dummy fragment threads started"/>
- <event counter="ARM_Mali-T6xx_COMPUTE_THREADS" title="Mali Core Threads" name="Compute threads" description="Number of vertex\compute threads started"/>
<event counter="ARM_Mali-T6xx_FRAG_QUADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
<event counter="ARM_Mali-T6xx_FRAG_QUADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
<event counter="ARM_Mali-T6xx_FRAG_THREADS_LZS_TEST" title="Mali Core Threads" name="Frag threads doing late ZS" description="Number of threads doing late ZS test"/>
<event counter="ARM_Mali-T6xx_FRAG_THREADS_LZS_KILLED" title="Mali Core Threads" name="Frag threads killed late ZS" description="Number of threads killed by late ZS test"/>
+ <event counter="ARM_Mali-T6xx_COMPUTE_TASKS" title="Mali Compute Threads" name="Compute tasks" description="Number of compute tasks"/>
+ <event counter="ARM_Mali-T6xx_COMPUTE_THREADS" title="Mali Compute Threads" name="Compute threads started" description="Number of compute threads started"/>
+ <event counter="ARM_Mali-T6xx_COMPUTE_CYCLES_DESC" title="Mali Compute Threads" name="Compute cycles awaiting descriptors" description="Number of compute cycles spent waiting for descriptors"/>
+
<event counter="ARM_Mali-T6xx_FRAG_PRIMATIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
<event counter="ARM_Mali-T6xx_FRAG_PRIMATIVES_DROPPED" title="Mali Fragment Primitives" name="Primitives dropped" description="Number of primitives dropped because out of tile"/>
<event counter="ARM_Mali-T6xx_FRAG_PRIMITIVES" title="Mali Fragment Primitives" name="Primitives loaded" description="Number of primitives loaded from tiler"/>
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 <linux/io.h>
#include <linux/module.h>
#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 <linux/hardirq.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
#include <linux/workqueue.h>
#include <trace/events/kmem.h>
-#include <linux/hardirq.h>
-#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_mmapped.c
index f7670f6..f055e48 100644
--- a/driver/gator_events_mmaped.c
+++ b/driver/gator_events_mmapped.c
@@ -11,12 +11,18 @@
* To add them to the events.xml, create an events-mmap.xml with the
* following contents and rebuild gatord:
*
- * <counter_set name="mmaped_cnt" count="3"/>
- * <category name="mmaped" counter_set="mmaped_cnt" per_cpu="no">
+ * <counter_set name="mmapped_cnt" count="3"/>
+ * <category name="mmapped" counter_set="mmapped_cnt" per_cpu="no">
* <event event="0x0" title="Simulated1" name="Sine" display="maximum" average_selection="yes" description="Sort-of-sine"/>
* <event event="0x1" title="Simulated2" name="Triangle" display="maximum" average_selection="yes" description="Triangular wave"/>
* <event event="0x2" title="Simulated3" name="PWM" display="maximum" average_selection="yes" description="PWM Signal"/>
* </category>
+ *
+ * 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 <linux/init.h>
@@ -25,79 +31,71 @@
#include "gator.h"
-#define MMAPED_COUNTERS_NUM 3
+#define MMAPPED_COUNTERS_NUM 3
+
+static int mmapped_global_enabled;
static struct {
unsigned long enabled;
unsigned long event;
unsigned long key;
-} mmaped_counters[MMAPED_COUNTERS_NUM];
+} mmapped_counters[MMAPPED_COUNTERS_NUM];
-static int mmaped_buffer[MMAPED_COUNTERS_NUM * 2];
+static int mmapped_buffer[MMAPPED_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,
+/* 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 < MMAPED_COUNTERS_NUM; i++) {
+ for (i = 0; i < MMAPPED_COUNTERS_NUM; i++) {
char buf[16];
struct dentry *dir;
- snprintf(buf, sizeof(buf), "mmaped_cnt%d", i);
+ 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",
- &mmaped_counters[i].enabled);
+ &mmapped_counters[i].enabled);
gatorfs_create_ulong(sb, dir, "event",
- &mmaped_counters[i].event);
+ &mmapped_counters[i].event);
gatorfs_create_ro_ulong(sb, dir, "key",
- &mmaped_counters[i].key);
+ &mmapped_counters[i].key);
}
return 0;
}
-static int gator_events_mmaped_start(void)
+static int gator_events_mmapped_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
+ int i;
struct timespec ts;
+
getnstimeofday(&ts);
prev_time = timespec_to_ns(&ts);
-#endif
+
+ 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_mmaped_stop(void)
+static void gator_events_mmapped_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)
+static int mmapped_simulate(int counter, int delta_in_us)
{
int result = 0;
@@ -157,73 +155,55 @@ static int mmaped_simulate(int counter, int delta_in_us)
return result;
}
-#endif
-static int gator_events_mmaped_read(int **buffer)
+static int gator_events_mmapped_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())
+ if (!on_primary_core() || !mmapped_global_enabled)
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,
+
+ 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);
-#endif
}
}
if (buffer)
- *buffer = mmaped_buffer;
+ *buffer = mmapped_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,
+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_mmaped_init(void)
+int __init gator_events_mmapped_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();
+ 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_mmaped_interface);
+ return gator_events_install(&gator_events_mmapped_interface);
}
-
-gator_events_init(gator_events_mmaped_init);
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 <linux/slab.h>
-#include <linux/perf_event.h>
#include "gator.h"
// gator_events_armvX.c is used for Linux 2.6.x
#if GATOR_PERF_PMU_SUPPORT
+#include <linux/io.h>
+#ifdef CONFIG_OF
+#include <linux/of_address.h>
+#endif
+#include <linux/perf_event.h>
+#include <linux/slab.h>
+
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 <linux/slab.h>
#include <linux/cpu.h>
@@ -22,16 +23,20 @@ static unsigned long gator_protocol_version = 16;
#include <linux/module.h>
#include <linux/perf_event.h>
#include <linux/utsname.h>
+#include <linux/kthread.h>
#include <asm/stacktrace.h>
#include <asm/uaccess.h>
#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