aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rwxr-xr-xdriver/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.c114
-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
51 files changed, 1058 insertions, 486 deletions
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 100755
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 ead7eae..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,17 +49,15 @@ 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 LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0) /* Because CONFIG_LOCAL_TIMERS was removed in 3.12 */
-#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
-#endif
#if (GATOR_PERF_SUPPORT) && (!(GATOR_PERF_PMU_SUPPORT))
#ifndef CONFIG_PERF_EVENTS
-#warning gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
+#error gator requires the kernel to have CONFIG_PERF_EVENTS defined to support pmu hardware counters
#elif !defined CONFIG_HW_PERF_EVENTS
-#warning gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
+#error gator requires the kernel to have CONFIG_HW_PERF_EVENTS defined to support pmu hardware counters
#endif
#endif
@@ -89,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
@@ -138,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;
@@ -149,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);
@@ -191,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
******************************************************************************/
@@ -394,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
******************************************************************************/
@@ -519,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)
@@ -592,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;
@@ -817,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:
@@ -827,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);
}
@@ -904,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;
@@ -918,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]();
@@ -943,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;
@@ -1013,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;
}
@@ -1036,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);
}
/******************************************************************************
@@ -1440,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