summaryrefslogtreecommitdiffstats
path: root/daemon
diff options
context:
space:
mode:
authorJon Medhurst2014-04-09 06:39:14 -0500
committerJon Medhurst2014-04-09 06:40:23 -0500
commit0f66ada81c8f90a7b2e4f7570032e33aaedfb32f (patch)
treec686b9fe25f272834766eba38b51cc7a97c69786 /daemon
parent33bef9ed7feca41e7cd6de8bf5d80052669278d3 (diff)
downloadarm-ds5-gator-0f66ada81c8f90a7b2e4f7570032e33aaedfb32f.tar.gz
arm-ds5-gator-0f66ada81c8f90a7b2e4f7570032e33aaedfb32f.tar.xz
arm-ds5-gator-0f66ada81c8f90a7b2e4f7570032e33aaedfb32f.zip
gator: Version 5.18DS-5.18
Signed-off-by: Jon Medhurst <tixy@linaro.org>
Diffstat (limited to 'daemon')
-rw-r--r--daemon/Android.mk15
-rw-r--r--daemon/Buffer.cpp259
-rw-r--r--daemon/Buffer.h99
-rw-r--r--daemon/CapturedXML.cpp11
-rw-r--r--daemon/CapturedXML.h2
-rw-r--r--daemon/Child.cpp174
-rw-r--r--daemon/Child.h4
-rw-r--r--daemon/Collector.h38
-rw-r--r--daemon/Config.h17
-rw-r--r--daemon/ConfigurationXML.cpp16
-rw-r--r--daemon/ConfigurationXML.h2
-rw-r--r--daemon/Counter.h4
-rw-r--r--daemon/Driver.cpp2
-rw-r--r--daemon/Driver.h4
-rw-r--r--daemon/DriverSource.cpp (renamed from daemon/Collector.cpp)225
-rw-r--r--daemon/DriverSource.h52
-rw-r--r--daemon/DynBuf.cpp139
-rw-r--r--daemon/DynBuf.h52
-rw-r--r--daemon/EventsXML.cpp4
-rw-r--r--daemon/EventsXML.h2
-rw-r--r--daemon/ExternalSource.cpp56
-rw-r--r--daemon/ExternalSource.h40
-rw-r--r--daemon/Fifo.cpp2
-rw-r--r--daemon/Fifo.h4
-rw-r--r--daemon/Hwmon.cpp40
-rw-r--r--daemon/Hwmon.h6
-rw-r--r--daemon/KMod.cpp25
-rw-r--r--daemon/KMod.h4
-rw-r--r--daemon/LocalCapture.cpp6
-rw-r--r--daemon/LocalCapture.h2
-rw-r--r--daemon/Logging.cpp6
-rw-r--r--daemon/Logging.h13
-rw-r--r--daemon/Monitor.cpp61
-rw-r--r--daemon/Monitor.h32
-rw-r--r--daemon/OlySocket.cpp101
-rw-r--r--daemon/OlySocket.h43
-rw-r--r--daemon/OlyUtility.cpp2
-rw-r--r--daemon/OlyUtility.h2
-rw-r--r--daemon/PerfBuffer.cpp139
-rw-r--r--daemon/PerfBuffer.h39
-rw-r--r--daemon/PerfDriver.cpp355
-rw-r--r--daemon/PerfDriver.h56
-rw-r--r--daemon/PerfGroup.cpp206
-rw-r--r--daemon/PerfGroup.h55
-rw-r--r--daemon/PerfSource.cpp271
-rw-r--r--daemon/PerfSource.h54
-rw-r--r--daemon/Proc.cpp179
-rw-r--r--daemon/Proc.h17
-rw-r--r--daemon/Sender.cpp29
-rw-r--r--daemon/Sender.h2
-rw-r--r--daemon/SessionData.cpp29
-rw-r--r--daemon/SessionData.h14
-rw-r--r--daemon/SessionXML.cpp12
-rw-r--r--daemon/SessionXML.h8
-rw-r--r--daemon/Source.cpp33
-rw-r--r--daemon/Source.h40
-rw-r--r--daemon/StreamlineSetup.cpp36
-rw-r--r--daemon/StreamlineSetup.h7
-rw-r--r--daemon/UEvent.cpp75
-rw-r--r--daemon/UEvent.h36
-rw-r--r--daemon/UserSpaceSource.cpp97
-rw-r--r--daemon/UserSpaceSource.h38
-rw-r--r--daemon/common.mk4
-rw-r--r--daemon/defaults.xml (renamed from daemon/configuration.xml)51
-rw-r--r--daemon/escape.c2
-rw-r--r--daemon/events-Cortex-A12.xml6
-rw-r--r--daemon/events-Cortex-A15.xml6
-rw-r--r--daemon/events-Cortex-A5.xml6
-rw-r--r--daemon/events-Cortex-A7.xml6
-rw-r--r--daemon/events-Cortex-A8.xml6
-rw-r--r--daemon/events-Cortex-A9.xml6
-rw-r--r--daemon/events-Linux.xml14
-rw-r--r--daemon/events-Mali-4xx.xml2
-rw-r--r--daemon/events-Mali-T6xx.xml16
-rw-r--r--daemon/events-Perf-Hardware.xml12
-rw-r--r--daemon/k/perf_event.3.12.h792
l---------daemon/k/perf_event.h1
-rw-r--r--daemon/main.cpp80
78 files changed, 3804 insertions, 599 deletions
diff --git a/daemon/Android.mk b/daemon/Android.mk
index a042971..045d028 100644
--- a/daemon/Android.mk
+++ b/daemon/Android.mk
@@ -1,7 +1,7 @@
1LOCAL_PATH := $(call my-dir) 1LOCAL_PATH := $(call my-dir)
2include $(CLEAR_VARS) 2include $(CLEAR_VARS)
3 3
4XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h configuration_xml.h) 4XML_H := $(shell cd $(LOCAL_PATH) && make events_xml.h defaults_xml.h)
5 5
6LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -DETCDIR=\"/etc\" -Ilibsensors 6LOCAL_CFLAGS += -Wall -O3 -mthumb-interwork -fno-exceptions -DETCDIR=\"/etc\" -Ilibsensors
7 7
@@ -9,22 +9,33 @@ LOCAL_SRC_FILES := \
9 Buffer.cpp \ 9 Buffer.cpp \
10 CapturedXML.cpp \ 10 CapturedXML.cpp \
11 Child.cpp \ 11 Child.cpp \
12 Collector.cpp \
13 ConfigurationXML.cpp \ 12 ConfigurationXML.cpp \
14 Driver.cpp \ 13 Driver.cpp \
14 DriverSource.cpp \
15 DynBuf.cpp \
15 EventsXML.cpp \ 16 EventsXML.cpp \
17 ExternalSource.cpp \
16 Fifo.cpp \ 18 Fifo.cpp \
17 Hwmon.cpp \ 19 Hwmon.cpp \
18 KMod.cpp \ 20 KMod.cpp \
19 LocalCapture.cpp \ 21 LocalCapture.cpp \
20 Logging.cpp \ 22 Logging.cpp \
21 main.cpp \ 23 main.cpp \
24 Monitor.cpp \
22 OlySocket.cpp \ 25 OlySocket.cpp \
23 OlyUtility.cpp \ 26 OlyUtility.cpp \
27 PerfBuffer.cpp \
28 PerfDriver.cpp \
29 PerfGroup.cpp \
30 PerfSource.cpp \
31 Proc.cpp \
24 Sender.cpp \ 32 Sender.cpp \
25 SessionData.cpp \ 33 SessionData.cpp \
26 SessionXML.cpp \ 34 SessionXML.cpp \
35 Source.cpp \
27 StreamlineSetup.cpp \ 36 StreamlineSetup.cpp \
37 UEvent.cpp \
38 UserSpaceSource.cpp \
28 libsensors/access.c \ 39 libsensors/access.c \
29 libsensors/conf-lex.c \ 40 libsensors/conf-lex.c \
30 libsensors/conf-parse.c \ 41 libsensors/conf-parse.c \
diff --git a/daemon/Buffer.cpp b/daemon/Buffer.cpp
index 090a715..93557da 100644
--- a/daemon/Buffer.cpp
+++ b/daemon/Buffer.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -12,33 +12,60 @@
12#include "Sender.h" 12#include "Sender.h"
13#include "SessionData.h" 13#include "SessionData.h"
14 14
15#define mask (size - 1) 15#define mask (mSize - 1)
16 16
17Buffer::Buffer (const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : core(core), buftype(buftype), size(size), readPos(0), writePos(0), commitPos(0), available(true), done(false), buf(new char[size]), commitTime(gSessionData->mLiveRate), readerSem(readerSem) { 17enum {
18 if ((size & mask) != 0) { 18 CODE_PEA = 1,
19 CODE_KEYS = 2,
20 CODE_FORMAT = 3,
21 CODE_MAPS = 4,
22 CODE_COMM = 5,
23};
24
25// Summary Frame Messages
26enum {
27 MESSAGE_SUMMARY = 1,
28 MESSAGE_CORE_NAME = 3,
29};
30
31// From gator_marshaling.c
32#define NEWLINE_CANARY \
33 /* Unix */ \
34 "1\n" \
35 /* Windows */ \
36 "2\r\n" \
37 /* Mac OS */ \
38 "3\r" \
39 /* RISC OS */ \
40 "4\n\r" \
41 /* Add another character so the length isn't 0x0a bytes */ \
42 "5"
43
44Buffer::Buffer(const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : mCore(core), mBufType(buftype), mSize(size), mReadPos(0), mWritePos(0), mCommitPos(0), mAvailable(true), mIsDone(false), mBuf(new char[mSize]), mCommitTime(gSessionData->mLiveRate), mReaderSem(readerSem) {
45 if ((mSize & mask) != 0) {
19 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2"); 46 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
20 handleException(); 47 handleException();
21 } 48 }
22 frame(); 49 frame();
23} 50}
24 51
25Buffer::~Buffer () { 52Buffer::~Buffer() {
26 delete [] buf; 53 delete [] mBuf;
27} 54}
28 55
29void Buffer::write (Sender * const sender) { 56void Buffer::write(Sender *const sender) {
30 if (!commitReady()) { 57 if (!commitReady()) {
31 return; 58 return;
32 } 59 }
33 60
34 // determine the size of two halves 61 // determine the size of two halves
35 int length1 = commitPos - readPos; 62 int length1 = mCommitPos - mReadPos;
36 char * buffer1 = buf + readPos; 63 char *buffer1 = mBuf + mReadPos;
37 int length2 = 0; 64 int length2 = 0;
38 char * buffer2 = buf; 65 char *buffer2 = mBuf;
39 if (length1 < 0) { 66 if (length1 < 0) {
40 length1 = size - readPos; 67 length1 = mSize - mReadPos;
41 length2 = commitPos; 68 length2 = mCommitPos;
42 } 69 }
43 70
44 logg->logMessage("Sending data length1: %i length2: %i", length1, length2); 71 logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
@@ -53,22 +80,22 @@ void Buffer::write (Sender * const sender) {
53 sender->writeData(buffer2, length2, RESPONSE_APC_DATA); 80 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
54 } 81 }
55 82
56 readPos = commitPos; 83 mReadPos = mCommitPos;
57} 84}
58 85
59bool Buffer::commitReady () const { 86bool Buffer::commitReady() const {
60 return commitPos != readPos; 87 return mCommitPos != mReadPos;
61} 88}
62 89
63int Buffer::bytesAvailable () const { 90int Buffer::bytesAvailable() const {
64 int filled = writePos - readPos; 91 int filled = mWritePos - mReadPos;
65 if (filled < 0) { 92 if (filled < 0) {
66 filled += size; 93 filled += mSize;
67 } 94 }
68 95
69 int remaining = size - filled; 96 int remaining = mSize - filled;
70 97
71 if (available) { 98 if (mAvailable) {
72 // Give some extra room; also allows space to insert the overflow error packet 99 // Give some extra room; also allows space to insert the overflow error packet
73 remaining -= 200; 100 remaining -= 200;
74 } else { 101 } else {
@@ -79,58 +106,68 @@ int Buffer::bytesAvailable () const {
79 return remaining; 106 return remaining;
80} 107}
81 108
82bool Buffer::checkSpace (const int bytes) { 109bool Buffer::checkSpace(const int bytes) {
83 const int remaining = bytesAvailable(); 110 const int remaining = bytesAvailable();
84 111
85 if (remaining < bytes) { 112 if (remaining < bytes) {
86 available = false; 113 mAvailable = false;
87 } else { 114 } else {
88 available = true; 115 mAvailable = true;
89 } 116 }
90 117
91 return available; 118 return mAvailable;
119}
120
121int Buffer::contiguousSpaceAvailable() const {
122 int remaining = bytesAvailable();
123 int contiguous = mSize - mWritePos;
124 if (remaining < contiguous) {
125 return remaining;
126 } else {
127 return contiguous;
128 }
92} 129}
93 130
94void Buffer::commit (const uint64_t time) { 131void Buffer::commit(const uint64_t time) {
95 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload 132 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
96 const int typeLength = gSessionData->mLocalCapture ? 0 : 1; 133 const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
97 int length = writePos - commitPos; 134 int length = mWritePos - mCommitPos;
98 if (length < 0) { 135 if (length < 0) {
99 length += size; 136 length += mSize;
100 } 137 }
101 length = length - typeLength - sizeof(int32_t); 138 length = length - typeLength - sizeof(int32_t);
102 for (size_t byte = 0; byte < sizeof(int32_t); byte++) { 139 for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
103 buf[(commitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF; 140 mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
104 } 141 }
105 142
106 logg->logMessage("Committing data readPos: %i writePos: %i commitPos: %i", readPos, writePos, commitPos); 143 logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
107 commitPos = writePos; 144 mCommitPos = mWritePos;
108 145
109 if (gSessionData->mLiveRate > 0) { 146 if (gSessionData->mLiveRate > 0) {
110 while (time > commitTime) { 147 while (time > mCommitTime) {
111 commitTime += gSessionData->mLiveRate; 148 mCommitTime += gSessionData->mLiveRate;
112 } 149 }
113 } 150 }
114 151
115 if (!done) { 152 if (!mIsDone) {
116 frame(); 153 frame();
117 } 154 }
118 155
119 // send a notification that data is ready 156 // send a notification that data is ready
120 sem_post(readerSem); 157 sem_post(mReaderSem);
121} 158}
122 159
123void Buffer::check (const uint64_t time) { 160void Buffer::check(const uint64_t time) {
124 int filled = writePos - commitPos; 161 int filled = mWritePos - mCommitPos;
125 if (filled < 0) { 162 if (filled < 0) {
126 filled += size; 163 filled += mSize;
127 } 164 }
128 if (filled >= ((size * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= commitTime)) { 165 if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
129 commit(time); 166 commit(time);
130 } 167 }
131} 168}
132 169
133void Buffer::packInt (int32_t x) { 170void Buffer::packInt(int32_t x) {
134 int packedBytes = 0; 171 int packedBytes = 0;
135 int more = true; 172 int more = true;
136 while (more) { 173 while (more) {
@@ -144,14 +181,14 @@ void Buffer::packInt (int32_t x) {
144 b |= 0x80; 181 b |= 0x80;
145 } 182 }
146 183
147 buf[(writePos + packedBytes) & mask] = b; 184 mBuf[(mWritePos + packedBytes) & mask] = b;
148 packedBytes++; 185 packedBytes++;
149 } 186 }
150 187
151 writePos = (writePos + packedBytes) & mask; 188 mWritePos = (mWritePos + packedBytes) & mask;
152} 189}
153 190
154void Buffer::packInt64 (int64_t x) { 191void Buffer::packInt64(int64_t x) {
155 int packedBytes = 0; 192 int packedBytes = 0;
156 int more = true; 193 int more = true;
157 while (more) { 194 while (more) {
@@ -165,24 +202,61 @@ void Buffer::packInt64 (int64_t x) {
165 b |= 0x80; 202 b |= 0x80;
166 } 203 }
167 204
168 buf[(writePos + packedBytes) & mask] = b; 205 mBuf[(mWritePos + packedBytes) & mask] = b;
169 packedBytes++; 206 packedBytes++;
170 } 207 }
171 208
172 writePos = (writePos + packedBytes) & mask; 209 mWritePos = (mWritePos + packedBytes) & mask;
210}
211
212void Buffer::writeBytes(const void *const data, size_t count) {
213 size_t i;
214 for (i = 0; i < count; ++i) {
215 mBuf[(mWritePos + i) & mask] = static_cast<const char *>(data)[i];
216 }
217
218 mWritePos = (mWritePos + i) & mask;
173} 219}
174 220
175void Buffer::frame () { 221void Buffer::writeString(const char *const str) {
222 const int len = strlen(str);
223 packInt(len);
224 writeBytes(str, len);
225}
226
227void Buffer::frame() {
176 if (!gSessionData->mLocalCapture) { 228 if (!gSessionData->mLocalCapture) {
177 packInt(RESPONSE_APC_DATA); 229 packInt(RESPONSE_APC_DATA);
178 } 230 }
179 // Reserve space for the length 231 // Reserve space for the length
180 writePos += sizeof(int32_t); 232 mWritePos += sizeof(int32_t);
181 packInt(buftype); 233 packInt(mBufType);
182 packInt(core); 234 packInt(mCore);
183} 235}
184 236
185bool Buffer::eventHeader (const uint64_t curr_time) { 237void Buffer::summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
238 packInt(MESSAGE_SUMMARY);
239 writeString(NEWLINE_CANARY);
240 packInt64(timestamp);
241 packInt64(uptime);
242 packInt64(monotonicDelta);
243 writeString("uname");
244 writeString(uname);
245 writeString("");
246 check(1);
247}
248
249void Buffer::coreName(const int core, const int cpuid, const char *const name) {
250 if (checkSpace(3 * MAXSIZE_PACK32 + 0x100)) {
251 packInt(MESSAGE_CORE_NAME);
252 packInt(core);
253 packInt(cpuid);
254 writeString(name);
255 }
256 check(1);
257}
258
259bool Buffer::eventHeader(const uint64_t curr_time) {
186 bool retval = false; 260 bool retval = false;
187 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) { 261 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
188 packInt(0); // key of zero indicates a timestamp 262 packInt(0); // key of zero indicates a timestamp
@@ -193,9 +267,9 @@ bool Buffer::eventHeader (const uint64_t curr_time) {
193 return retval; 267 return retval;
194} 268}
195 269
196bool Buffer::eventTid (const int tid) { 270bool Buffer::eventTid(const int tid) {
197 bool retval = false; 271 bool retval = false;
198 if (checkSpace(2*MAXSIZE_PACK32)) { 272 if (checkSpace(2 * MAXSIZE_PACK32)) {
199 packInt(1); // key of 1 indicates a tid 273 packInt(1); // key of 1 indicates a tid
200 packInt(tid); 274 packInt(tid);
201 retval = true; 275 retval = true;
@@ -204,25 +278,94 @@ bool Buffer::eventTid (const int tid) {
204 return retval; 278 return retval;
205} 279}
206 280
207void Buffer::event (const int32_t key, const int32_t value) { 281void Buffer::event(const int32_t key, const int32_t value) {
208 if (checkSpace(2 * MAXSIZE_PACK32)) { 282 if (checkSpace(2 * MAXSIZE_PACK32)) {
209 packInt(key); 283 packInt(key);
210 packInt(value); 284 packInt(value);
211 } 285 }
212} 286}
213 287
214void Buffer::event64 (const int64_t key, const int64_t value) { 288void Buffer::event64(const int64_t key, const int64_t value) {
215 if (checkSpace(2 * MAXSIZE_PACK64)) { 289 if (checkSpace(2 * MAXSIZE_PACK64)) {
216 packInt64(key); 290 packInt64(key);
217 packInt64(value); 291 packInt64(value);
218 } 292 }
219} 293}
220 294
221void Buffer::setDone () { 295void Buffer::pea(const struct perf_event_attr *const pea, int key) {
222 done = true; 296 if (checkSpace(2 * MAXSIZE_PACK32 + pea->size)) {
297 packInt(CODE_PEA);
298 writeBytes(pea, pea->size);
299 packInt(key);
300 } else {
301 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
302 handleException();
303 }
304 // Don't know the real perf time so use 1 as it will work for now
305 check(1);
306}
307
308void Buffer::keys(const int count, const __u64 *const ids, const int *const keys) {
309 if (checkSpace(2 * MAXSIZE_PACK32 + count * (MAXSIZE_PACK32 + MAXSIZE_PACK64))) {
310 packInt(CODE_KEYS);
311 packInt(count);
312 for (int i = 0; i < count; ++i) {
313 packInt64(ids[i]);
314 packInt(keys[i]);
315 }
316 } else {
317 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
318 handleException();
319 }
320 check(1);
321}
322
323void Buffer::format(const int length, const char *const format) {
324 if (checkSpace(MAXSIZE_PACK32 + length + 1)) {
325 packInt(CODE_FORMAT);
326 writeBytes(format, length + 1);
327 } else {
328 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
329 handleException();
330 }
331 check(1);
332}
333
334void Buffer::maps(const int pid, const int tid, const char *const maps) {
335 const int mapsLen = strlen(maps) + 1;
336 if (checkSpace(3 * MAXSIZE_PACK32 + mapsLen)) {
337 packInt(CODE_MAPS);
338 packInt(pid);
339 packInt(tid);
340 writeBytes(maps, mapsLen);
341 } else {
342 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
343 handleException();
344 }
345 check(1);
346}
347
348void Buffer::comm(const int pid, const int tid, const char *const image, const char *const comm) {
349 const int imageLen = strlen(image) + 1;
350 const int commLen = strlen(comm) + 1;
351 if (checkSpace(3 * MAXSIZE_PACK32 + imageLen + commLen)) {
352 packInt(CODE_COMM);
353 packInt(pid);
354 packInt(tid);
355 writeBytes(image, imageLen);
356 writeBytes(comm, commLen);
357 } else {
358 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
359 handleException();
360 }
361 check(1);
362}
363
364void Buffer::setDone() {
365 mIsDone = true;
223 commit(0); 366 commit(0);
224} 367}
225 368
226bool Buffer::isDone () const { 369bool Buffer::isDone() const {
227 return done && readPos == commitPos && commitPos == writePos; 370 return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;
228} 371}
diff --git a/daemon/Buffer.h b/daemon/Buffer.h
index b3c8d78..5023777 100644
--- a/daemon/Buffer.h
+++ b/daemon/Buffer.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,54 +9,89 @@
9#ifndef BUFFER_H 9#ifndef BUFFER_H
10#define BUFFER_H 10#define BUFFER_H
11 11
12#include <stddef.h>
13#include <stdint.h> 12#include <stdint.h>
14#include <semaphore.h> 13#include <semaphore.h>
15 14
15#include "k/perf_event.h"
16
16class Sender; 17class Sender;
17 18
19enum {
20 FRAME_SUMMARY = 1,
21 FRAME_BLOCK_COUNTER = 5,
22 FRAME_EXTERNAL = 10,
23 FRAME_PERF_ATTRS = 11,
24 FRAME_PERF = 12,
25};
26
18class Buffer { 27class Buffer {
19public: 28public:
20 static const size_t MAXSIZE_PACK32 = 5; 29 static const size_t MAXSIZE_PACK32 = 5;
21 static const size_t MAXSIZE_PACK64 = 10; 30 static const size_t MAXSIZE_PACK64 = 10;
22 31
23 Buffer (int32_t core, int32_t buftype, const int size, sem_t *const readerSem); 32 Buffer(int32_t core, int32_t buftype, const int size, sem_t *const readerSem);
24 ~Buffer (); 33 ~Buffer();
34
35 void write(Sender *sender);
36
37 int bytesAvailable() const;
38 int contiguousSpaceAvailable() const;
39 void commit(const uint64_t time);
40 void check(const uint64_t time);
25 41
26 void write (Sender * sender); 42 void frame();
27 43
28 int bytesAvailable () const; 44 // Summary messages
29 void commit (const uint64_t time); 45 void summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname);
30 void check (const uint64_t time); 46 void coreName(const int core, const int cpuid, const char *const name);
31 47
32 void frame (); 48 // Block Counter messages
49 bool eventHeader(uint64_t curr_time);
50 bool eventTid(int tid);
51 void event(int32_t key, int32_t value);
52 void event64(int64_t key, int64_t value);
33 53
34 bool eventHeader (uint64_t curr_time); 54 // Perf Attrs messages
35 bool eventTid (int tid); 55 void pea(const struct perf_event_attr *const pea, int key);
36 void event (int32_t key, int32_t value); 56 void keys(const int count, const __u64 *const ids, const int *const keys);
37 void event64 (int64_t key, int64_t value); 57 void format(const int length, const char *const format);
58 void maps(const int pid, const int tid, const char *const maps);
59 void comm(const int pid, const int tid, const char *const image, const char *const comm);
38 60
39 void setDone (); 61 void setDone();
40 bool isDone () const; 62 bool isDone() const;
63
64 // Prefer a new member to using these functions if possible
65 char *getWritePos() { return mBuf + mWritePos; }
66 void advanceWrite(int bytes) { mWritePos = (mWritePos + bytes) & /*mask*/(mSize - 1); }
67
68 static void writeLEInt(unsigned char *buf, int v) {
69 buf[0] = (v >> 0) & 0xFF;
70 buf[1] = (v >> 8) & 0xFF;
71 buf[2] = (v >> 16) & 0xFF;
72 buf[3] = (v >> 24) & 0xFF;
73 }
41 74
42private: 75private:
43 bool commitReady () const; 76 bool commitReady() const;
44 bool checkSpace (int bytes); 77 bool checkSpace(int bytes);
45 78
46 void packInt (int32_t x); 79 void packInt(int32_t x);
47 void packInt64 (int64_t x); 80 void packInt64(int64_t x);
48 81 void writeBytes(const void *const data, size_t count);
49 const int32_t core; 82 void writeString(const char *const str);
50 const int32_t buftype; 83
51 const int size; 84 const int32_t mCore;
52 int readPos; 85 const int32_t mBufType;
53 int writePos; 86 const int mSize;
54 int commitPos; 87 int mReadPos;
55 bool available; 88 int mWritePos;
56 bool done; 89 int mCommitPos;
57 char *const buf; 90 bool mAvailable;
58 uint64_t commitTime; 91 bool mIsDone;
59 sem_t *const readerSem; 92 char *const mBuf;
93 uint64_t mCommitTime;
94 sem_t *const mReaderSem;
60 95
61 // Intentionally unimplemented 96 // Intentionally unimplemented
62 Buffer(const Buffer &); 97 Buffer(const Buffer &);
diff --git a/daemon/CapturedXML.cpp b/daemon/CapturedXML.cpp
index 30c4c44..cf79b72 100644
--- a/daemon/CapturedXML.cpp
+++ b/daemon/CapturedXML.cpp
@@ -1,16 +1,18 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "CapturedXML.h"
10
9#include <stdlib.h> 11#include <stdlib.h>
10#include <string.h> 12#include <string.h>
11#include <dirent.h> 13#include <dirent.h>
14
12#include "SessionData.h" 15#include "SessionData.h"
13#include "CapturedXML.h"
14#include "Logging.h" 16#include "Logging.h"
15#include "OlyUtility.h" 17#include "OlyUtility.h"
16 18
@@ -30,6 +32,9 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
30 32
31 captured = mxmlNewElement(xml, "captured"); 33 captured = mxmlNewElement(xml, "captured");
32 mxmlElementSetAttr(captured, "version", "1"); 34 mxmlElementSetAttr(captured, "version", "1");
35 if (gSessionData->perf.isSetup()) {
36 mxmlElementSetAttr(captured, "type", "Perf");
37 }
33 mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION); 38 mxmlElementSetAttrf(captured, "protocol", "%d", PROTOCOL_VERSION);
34 if (includeTime) { // Send the following only after the capture is complete 39 if (includeTime) { // Send the following only after the capture is complete
35 if (time(NULL) > 1267000000) { // If the time is reasonable (after Feb 23, 2010) 40 if (time(NULL) > 1267000000) { // If the time is reasonable (after Feb 23, 2010)
@@ -41,7 +46,7 @@ mxml_node_t* CapturedXML::getTree(bool includeTime) {
41 mxmlElementSetAttr(target, "name", gSessionData->mCoreName); 46 mxmlElementSetAttr(target, "name", gSessionData->mCoreName);
42 mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData->mSampleRate); 47 mxmlElementSetAttrf(target, "sample_rate", "%d", gSessionData->mSampleRate);
43 mxmlElementSetAttrf(target, "cores", "%d", gSessionData->mCores); 48 mxmlElementSetAttrf(target, "cores", "%d", gSessionData->mCores);
44 mxmlElementSetAttrf(target, "cpuid", "0x%x", gSessionData->mCpuId); 49 mxmlElementSetAttrf(target, "cpuid", "0x%x", gSessionData->mMaxCpuId);
45 50
46 if (!gSessionData->mOneShot && (gSessionData->mSampleRate > 0)) { 51 if (!gSessionData->mOneShot && (gSessionData->mSampleRate > 0)) {
47 mxmlElementSetAttr(target, "supports_live", "yes"); 52 mxmlElementSetAttr(target, "supports_live", "yes");
diff --git a/daemon/CapturedXML.h b/daemon/CapturedXML.h
index b0482f5..efc1e52 100644
--- a/daemon/CapturedXML.h
+++ b/daemon/CapturedXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Child.cpp b/daemon/Child.cpp
index 9ee2ef8..ca33561 100644
--- a/daemon/Child.cpp
+++ b/daemon/Child.cpp
@@ -1,38 +1,39 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "Child.h"
10
9#include <stdlib.h> 11#include <stdlib.h>
10#include <string.h> 12#include <string.h>
11#include <signal.h> 13#include <signal.h>
12#include <unistd.h> 14#include <unistd.h>
13#include <sys/prctl.h> 15#include <sys/prctl.h>
16
14#include "Logging.h" 17#include "Logging.h"
15#include "CapturedXML.h" 18#include "CapturedXML.h"
16#include "SessionData.h" 19#include "SessionData.h"
17#include "Child.h"
18#include "LocalCapture.h" 20#include "LocalCapture.h"
19#include "Collector.h"
20#include "Sender.h" 21#include "Sender.h"
21#include "OlyUtility.h" 22#include "OlyUtility.h"
23#include "OlySocket.h"
22#include "StreamlineSetup.h" 24#include "StreamlineSetup.h"
23#include "ConfigurationXML.h" 25#include "ConfigurationXML.h"
24#include "Driver.h" 26#include "Driver.h"
25#include "Fifo.h" 27#include "PerfSource.h"
26#include "Buffer.h" 28#include "DriverSource.h"
27 29#include "UserSpaceSource.h"
28#define NS_PER_S ((uint64_t)1000000000) 30#include "ExternalSource.h"
29#define NS_PER_US 1000
30 31
31static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads 32static sem_t haltPipeline, senderThreadStarted, startProfile, senderSem; // Shared by Child and spawned threads
32static Fifo* collectorFifo = NULL; // Shared by Child.cpp and spawned threads 33static Source *primarySource = NULL;
33static Buffer* buffer = NULL; 34static Source *userSpaceSource = NULL;
35static Source *externalSource = NULL;
34static Sender* sender = NULL; // Shared by Child.cpp and spawned threads 36static Sender* sender = NULL; // Shared by Child.cpp and spawned threads
35static Collector* collector = NULL;
36Child* child = NULL; // shared by Child.cpp and main.cpp 37Child* child = NULL; // shared by Child.cpp and main.cpp
37 38
38extern void cleanUp(); 39extern void cleanUp();
@@ -78,7 +79,7 @@ static void child_handler(int signum) {
78 } 79 }
79 beenHere = true; 80 beenHere = true;
80 logg->logMessage("Gator is shutting down."); 81 logg->logMessage("Gator is shutting down.");
81 if (signum == SIGALRM || !collector) { 82 if (signum == SIGALRM || !primarySource) {
82 exit(1); 83 exit(1);
83 } else { 84 } else {
84 child->endSession(); 85 child->endSession();
@@ -139,77 +140,22 @@ static void *stopThread(void *) {
139 return 0; 140 return 0;
140} 141}
141 142
142static void *countersThread(void *) {
143 prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
144
145 gSessionData->hwmon.start();
146
147 int64_t monotonic_started = 0;
148 while (monotonic_started <= 0) {
149 usleep(10);
150
151 if (Collector::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
152 logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
153 handleException();
154 }
155 }
156
157 uint64_t next_time = 0;
158 while (gSessionData->mSessionIsActive) {
159 struct timespec ts;
160#ifndef CLOCK_MONOTONIC_RAW
161 // Android doesn't have this defined but it was added in Linux 2.6.28
162#define CLOCK_MONOTONIC_RAW 4
163#endif
164 if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
165 logg->logError(__FILE__, __LINE__, "Failed to get uptime");
166 handleException();
167 }
168 const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started;
169 // Sample ten times a second ignoring gSessionData->mSampleRate
170 next_time += NS_PER_S/10;//gSessionData->mSampleRate;
171 if (next_time < curr_time) {
172 logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time);
173 next_time = curr_time;
174 }
175
176 if (buffer->eventHeader(curr_time)) {
177 gSessionData->hwmon.read(buffer);
178 // Only check after writing all counters so that time and corresponding counters appear in the same frame
179 buffer->check(curr_time);
180 }
181
182 if (buffer->bytesAvailable() <= 0) {
183 logg->logMessage("One shot (counters)");
184 child->endSession();
185 }
186
187 usleep((next_time - curr_time)/NS_PER_US);
188 }
189
190 buffer->setDone();
191
192 return NULL;
193}
194
195static void *senderThread(void *) { 143static void *senderThread(void *) {
196 int length = 1;
197 char* data;
198 char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0}; 144 char end_sequence[] = {RESPONSE_APC_DATA, 0, 0, 0, 0};
199 145
200 sem_post(&senderThreadStarted); 146 sem_post(&senderThreadStarted);
201 prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0); 147 prctl(PR_SET_NAME, (unsigned long)&"gatord-sender", 0, 0, 0);
202 sem_wait(&haltPipeline); 148 sem_wait(&haltPipeline);
203 149
204 while (length > 0 || !buffer->isDone()) { 150 while (!primarySource->isDone() || (userSpaceSource != NULL && !userSpaceSource->isDone()) || (externalSource != NULL && !externalSource->isDone())) {
205 sem_wait(&senderSem); 151 sem_wait(&senderSem);
206 data = collectorFifo->read(&length); 152
207 if (data != NULL) { 153 primarySource->write(sender);
208 sender->writeData(data, length, RESPONSE_APC_DATA); 154 if (userSpaceSource != NULL) {
209 collectorFifo->release(); 155 userSpaceSource->write(sender);
210 } 156 }
211 if (!buffer->isDone()) { 157 if (externalSource != NULL) {
212 buffer->write(sender); 158 externalSource->write(sender);
213 } 159 }
214 } 160 }
215 161
@@ -255,15 +201,13 @@ void Child::initialization() {
255 201
256void Child::endSession() { 202void Child::endSession() {
257 gSessionData->mSessionIsActive = false; 203 gSessionData->mSessionIsActive = false;
258 collector->stop(); 204 primarySource->interrupt();
259 sem_post(&haltPipeline); 205 sem_post(&haltPipeline);
260} 206}
261 207
262void Child::run() { 208void Child::run() {
263 char* collectBuffer;
264 int bytesCollected = 0;
265 LocalCapture* localCapture = NULL; 209 LocalCapture* localCapture = NULL;
266 pthread_t durationThreadID, stopThreadID, senderThreadID, countersThreadID; 210 pthread_t durationThreadID, stopThreadID, senderThreadID;
267 211
268 prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0); 212 prctl(PR_SET_NAME, (unsigned long)&"gatord-child", 0, 0, 0);
269 213
@@ -282,7 +226,11 @@ void Child::run() {
282 { ConfigurationXML configuration; } 226 { ConfigurationXML configuration; }
283 227
284 // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated 228 // Set up the driver; must be done after gSessionData->mPerfCounterType[] is populated
285 collector = new Collector(); 229 if (!gSessionData->perf.isSetup()) {
230 primarySource = new DriverSource(&senderSem, &startProfile);
231 } else {
232 primarySource = new PerfSource(&senderSem, &startProfile);
233 }
286 234
287 // Initialize all drivers 235 // Initialize all drivers
288 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) { 236 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
@@ -317,15 +265,11 @@ void Child::run() {
317 free(xmlString); 265 free(xmlString);
318 } 266 }
319 267
320 // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length 268 // Must be after session XML is parsed
321 logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, collector->getBufferSize()); 269 if (!primarySource->prepare()) {
322 collectorFifo = new Fifo(collector->getBufferSize() + 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem); 270 logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
323 271 handleException();
324 // Get the initial pointer to the collect buffer 272 }
325 collectBuffer = collectorFifo->start();
326
327 // Create a new Block Counter Buffer
328 buffer = new Buffer(0, 5, gSessionData->mTotalBufferSize*1024*1024, &senderSem);
329 273
330 // Sender thread shall be halted until it is signaled for one shot mode 274 // Sender thread shall be halted until it is signaled for one shot mode
331 sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2); 275 sem_init(&haltPipeline, 0, gSessionData->mOneShot ? 0 : 2);
@@ -340,14 +284,21 @@ void Child::run() {
340 thread_creation_success = false; 284 thread_creation_success = false;
341 } 285 }
342 286
343 bool startcountersThread = gSessionData->hwmon.countersEnabled(); 287 if (gSessionData->hwmon.countersEnabled()) {
344 if (startcountersThread) { 288 userSpaceSource = new UserSpaceSource(&senderSem);
345 if (pthread_create(&countersThreadID, NULL, countersThread, this)) { 289 if (!userSpaceSource->prepare()) {
346 thread_creation_success = false; 290 logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
291 handleException();
347 } 292 }
348 } else { 293 userSpaceSource->start();
349 // Let senderThread know there is no buffer data to send 294 }
350 buffer->setDone(); 295 if (access("/tmp/gator", F_OK) == 0) {
296 externalSource = new ExternalSource(&senderSem);
297 if (!externalSource->prepare()) {
298 logg->logError(__FILE__, __LINE__, "Unable to prepare for capture");
299 handleException();
300 }
301 externalSource->start();
351 } 302 }
352 303
353 if (!thread_creation_success) { 304 if (!thread_creation_success) {
@@ -359,28 +310,13 @@ void Child::run() {
359 sem_wait(&senderThreadStarted); 310 sem_wait(&senderThreadStarted);
360 311
361 // Start profiling 312 // Start profiling
362 logg->logMessage("********** Profiling started **********"); 313 primarySource->run();
363 collector->start();
364 sem_post(&startProfile);
365
366 // Collect Data
367 do {
368 // This command will stall until data is received from the driver
369 bytesCollected = collector->collect(collectBuffer);
370
371 // In one shot mode, stop collection once all the buffers are filled
372 if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
373 if (bytesCollected == -1 || collectorFifo->willFill(bytesCollected)) {
374 logg->logMessage("One shot");
375 endSession();
376 }
377 }
378 collectBuffer = collectorFifo->write(bytesCollected);
379 } while (bytesCollected > 0);
380 logg->logMessage("Exit collect data loop");
381 314
382 if (startcountersThread) { 315 if (externalSource != NULL) {
383 pthread_join(countersThreadID, NULL); 316 externalSource->join();
317 }
318 if (userSpaceSource != NULL) {
319 userSpaceSource->join();
384 } 320 }
385 321
386 // Wait for the other threads to exit 322 // Wait for the other threads to exit
@@ -401,9 +337,9 @@ void Child::run() {
401 337
402 logg->logMessage("Profiling ended."); 338 logg->logMessage("Profiling ended.");
403 339
404 delete buffer; 340 delete externalSource;
405 delete collectorFifo; 341 delete userSpaceSource;
342 delete primarySource;
406 delete sender; 343 delete sender;
407 delete collector;
408 delete localCapture; 344 delete localCapture;
409} 345}
diff --git a/daemon/Child.h b/daemon/Child.h
index 0330e9d..9e206d7 100644
--- a/daemon/Child.h
+++ b/daemon/Child.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,8 +9,6 @@
9#ifndef __CHILD_H__ 9#ifndef __CHILD_H__
10#define __CHILD_H__ 10#define __CHILD_H__
11 11
12#include <pthread.h>
13
14class OlySocket; 12class OlySocket;
15 13
16class Child { 14class Child {
diff --git a/daemon/Collector.h b/daemon/Collector.h
deleted file mode 100644
index c5e9eac..0000000
--- a/daemon/Collector.h
+++ /dev/null
@@ -1,38 +0,0 @@
1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef __COLLECTOR_H__
10#define __COLLECTOR_H__
11
12#include <stdio.h>
13
14class Collector {
15public:
16 Collector();
17 ~Collector();
18 void start();
19 void stop();
20 int collect(char* buffer);
21 int getBufferSize() {return mBufferSize;}
22
23 static int readIntDriver(const char* path, int* value);
24 static int readInt64Driver(const char* path, int64_t* value);
25 static int writeDriver(const char* path, int value);
26 static int writeDriver(const char* path, int64_t value);
27 static int writeDriver(const char* path, const char* data);
28 static int writeReadDriver(const char* path, int* value);
29 static int writeReadDriver(const char* path, int64_t* value);
30
31private:
32 int mBufferSize;
33 int mBufferFD;
34
35 void checkVersion();
36};
37
38#endif //__COLLECTOR_H__
diff --git a/daemon/Config.h b/daemon/Config.h
new file mode 100644
index 0000000..6f5e2aa
--- /dev/null
+++ b/daemon/Config.h
@@ -0,0 +1,17 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef CONFIG_H
10#define CONFIG_H
11
12#define ARRAY_LENGTH(A) static_cast<int>(sizeof(A)/sizeof((A)[0]))
13
14#define MAX_PERFORMANCE_COUNTERS 50
15#define NR_CPUS 16
16
17#endif // CONFIG_H
diff --git a/daemon/ConfigurationXML.cpp b/daemon/ConfigurationXML.cpp
index 2a5252a..fd479f2 100644
--- a/daemon/ConfigurationXML.cpp
+++ b/daemon/ConfigurationXML.cpp
@@ -1,15 +1,17 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "ConfigurationXML.h"
10
9#include <string.h> 11#include <string.h>
10#include <stdlib.h> 12#include <stdlib.h>
11#include <dirent.h> 13#include <dirent.h>
12#include "ConfigurationXML.h" 14
13#include "Driver.h" 15#include "Driver.h"
14#include "Logging.h" 16#include "Logging.h"
15#include "OlyUtility.h" 17#include "OlyUtility.h"
@@ -67,6 +69,7 @@ int ConfigurationXML::parse(const char* configurationXML) {
67 69
68 // clear counter overflow 70 // clear counter overflow
69 gSessionData->mCounterOverflow = 0; 71 gSessionData->mCounterOverflow = 0;
72 gSessionData->mIsEBS = false;
70 mIndex = 0; 73 mIndex = 0;
71 74
72 // disable all counters prior to parsing the configuration xml 75 // disable all counters prior to parsing the configuration xml
@@ -155,6 +158,9 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
155 if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER)); 158 if (mxmlElementGetAttr(node, ATTR_COUNTER)) counter.setType(mxmlElementGetAttr(node, ATTR_COUNTER));
156 if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16)); 159 if (mxmlElementGetAttr(node, ATTR_EVENT)) counter.setEvent(strtol(mxmlElementGetAttr(node, ATTR_EVENT), NULL, 16));
157 if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10)); 160 if (mxmlElementGetAttr(node, ATTR_COUNT)) counter.setCount(strtol(mxmlElementGetAttr(node, ATTR_COUNT), NULL, 10));
161 if (counter.getCount() > 0) {
162 gSessionData->mIsEBS = true;
163 }
158 counter.setEnabled(true); 164 counter.setEnabled(true);
159 165
160 // Associate a driver with each counter 166 // Associate a driver with each counter
@@ -181,9 +187,9 @@ void ConfigurationXML::configurationTag(mxml_node_t *node) {
181} 187}
182 188
183void ConfigurationXML::getDefaultConfigurationXml(const char * & xml, unsigned int & len) { 189void ConfigurationXML::getDefaultConfigurationXml(const char * & xml, unsigned int & len) {
184#include "configuration_xml.h" // defines and initializes char configuration_xml[] and int configuration_xml_len 190#include "defaults_xml.h" // defines and initializes char defaults_xml[] and int defaults_xml_len
185 xml = (const char *)configuration_xml; 191 xml = (const char *)defaults_xml;
186 len = configuration_xml_len; 192 len = defaults_xml_len;
187} 193}
188 194
189void ConfigurationXML::getPath(char* path) { 195void ConfigurationXML::getPath(char* path) {
diff --git a/daemon/ConfigurationXML.h b/daemon/ConfigurationXML.h
index 5650f48..efa415e 100644
--- a/daemon/ConfigurationXML.h
+++ b/daemon/ConfigurationXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Counter.h b/daemon/Counter.h
index 231a85d..6891745 100644
--- a/daemon/Counter.h
+++ b/daemon/Counter.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -25,7 +25,7 @@ public:
25 void clear () { 25 void clear () {
26 mType[0] = '\0'; 26 mType[0] = '\0';
27 mEnabled = false; 27 mEnabled = false;
28 mEvent = 0; 28 mEvent = -1;
29 mCount = 0; 29 mCount = 0;
30 mKey = 0; 30 mKey = 0;
31 mDriver = NULL; 31 mDriver = NULL;
diff --git a/daemon/Driver.cpp b/daemon/Driver.cpp
index c262467..09e0401 100644
--- a/daemon/Driver.cpp
+++ b/daemon/Driver.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Driver.h b/daemon/Driver.h
index f3a932f..e5ed7b6 100644
--- a/daemon/Driver.h
+++ b/daemon/Driver.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -27,7 +27,7 @@ public:
27 virtual void setupCounter(Counter &counter) = 0; 27 virtual void setupCounter(Counter &counter) = 0;
28 28
29 // Emits available counters 29 // Emits available counters
30 virtual void writeCounters(mxml_node_t *root) const = 0; 30 virtual int writeCounters(mxml_node_t *root) const = 0;
31 // Emits possible dynamically generated events/counters 31 // Emits possible dynamically generated events/counters
32 virtual void writeEvents(mxml_node_t *) const {} 32 virtual void writeEvents(mxml_node_t *) const {}
33 33
diff --git a/daemon/Collector.cpp b/daemon/DriverSource.cpp
index bf73534..f78ec6b 100644
--- a/daemon/Collector.cpp
+++ b/daemon/DriverSource.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -8,23 +8,47 @@
8 8
9#define __STDC_FORMAT_MACROS 9#define __STDC_FORMAT_MACROS
10 10
11#include "DriverSource.h"
12
11#include <fcntl.h> 13#include <fcntl.h>
12#include <unistd.h>
13#include <string.h>
14#include <stdlib.h>
15#include <errno.h>
16#include <sys/time.h>
17#include <inttypes.h> 14#include <inttypes.h>
18#include "Collector.h" 15#include <unistd.h>
19#include "SessionData.h" 16
17#include "Child.h"
18#include "Fifo.h"
20#include "Logging.h" 19#include "Logging.h"
21#include "Sender.h" 20#include "Sender.h"
21#include "SessionData.h"
22
23extern Child *child;
22 24
23// Driver initialization independent of session settings 25DriverSource::DriverSource(sem_t *senderSem, sem_t *startProfile) : mFifo(NULL), mSenderSem(senderSem), mStartProfile(startProfile), mBufferSize(0), mBufferFD(0), mLength(1) {
24Collector::Collector() { 26 int driver_version = 0;
25 mBufferFD = 0;
26 27
27 checkVersion(); 28 if (readIntDriver("/dev/gator/version", &driver_version) == -1) {
29 logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
30 handleException();
31 }
32
33 // Verify the driver version matches the daemon version
34 if (driver_version != PROTOCOL_VERSION) {
35 if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
36 // One of the mismatched versions is development version
37 logg->logError(__FILE__, __LINE__,
38 "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
39 ">> The following must be synchronized from engineering repository:\n"
40 ">> * gator driver\n"
41 ">> * gator daemon\n"
42 ">> * Streamline", driver_version, PROTOCOL_VERSION);
43 handleException();
44 } else {
45 // Release version mismatch
46 logg->logError(__FILE__, __LINE__,
47 "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
48 ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
49 handleException();
50 }
51 }
28 52
29 int enable = -1; 53 int enable = -1;
30 if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) { 54 if (readIntDriver("/dev/gator/enable", &enable) != 0 || enable != 0) {
@@ -37,14 +61,15 @@ Collector::Collector() {
37 gSessionData->mCores = 1; 61 gSessionData->mCores = 1;
38 } 62 }
39 63
40 mBufferSize = 0;
41 if (readIntDriver("/dev/gator/buffer_size", &mBufferSize) || mBufferSize <= 0) { 64 if (readIntDriver("/dev/gator/buffer_size", &mBufferSize) || mBufferSize <= 0) {
42 logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size"); 65 logg->logError(__FILE__, __LINE__, "Unable to read the driver buffer size");
43 handleException(); 66 handleException();
44 } 67 }
45} 68}
46 69
47Collector::~Collector() { 70DriverSource::~DriverSource() {
71 delete mFifo;
72
48 // Write zero for safety, as a zero should have already been written 73 // Write zero for safety, as a zero should have already been written
49 writeDriver("/dev/gator/enable", "0"); 74 writeDriver("/dev/gator/enable", "0");
50 75
@@ -54,36 +79,21 @@ Collector::~Collector() {
54 } 79 }
55} 80}
56 81
57void Collector::checkVersion() { 82bool DriverSource::prepare() {
58 int driver_version = 0; 83 // Create user-space buffers, add 5 to the size to account for the 1-byte type and 4-byte length
59 84 logg->logMessage("Created %d MB collector buffer with a %d-byte ragged end", gSessionData->mTotalBufferSize, mBufferSize);
60 if (readIntDriver("/dev/gator/version", &driver_version) == -1) { 85 mFifo = new Fifo(mBufferSize + 5, gSessionData->mTotalBufferSize*1024*1024, mSenderSem);
61 logg->logError(__FILE__, __LINE__, "Error reading gator driver version");
62 handleException();
63 }
64 86
65 // Verify the driver version matches the daemon version 87 return true;
66 if (driver_version != PROTOCOL_VERSION) {
67 if ((driver_version > PROTOCOL_DEV) || (PROTOCOL_VERSION > PROTOCOL_DEV)) {
68 // One of the mismatched versions is development version
69 logg->logError(__FILE__, __LINE__,
70 "DEVELOPMENT BUILD MISMATCH: gator driver version \"%d\" is not in sync with gator daemon version \"%d\".\n"
71 ">> The following must be synchronized from engineering repository:\n"
72 ">> * gator driver\n"
73 ">> * gator daemon\n"
74 ">> * Streamline", driver_version, PROTOCOL_VERSION);
75 handleException();
76 } else {
77 // Release version mismatch
78 logg->logError(__FILE__, __LINE__,
79 "gator driver version \"%d\" is different than gator daemon version \"%d\".\n"
80 ">> Please upgrade the driver and daemon to the latest versions.", driver_version, PROTOCOL_VERSION);
81 handleException();
82 }
83 }
84} 88}
85 89
86void Collector::start() { 90void DriverSource::run() {
91 // Get the initial pointer to the collect buffer
92 char *collectBuffer = mFifo->start();
93 int bytesCollected = 0;
94
95 logg->logMessage("********** Profiling started **********");
96
87 // Set the maximum backtrace depth 97 // Set the maximum backtrace depth
88 if (writeReadDriver("/dev/gator/backtrace_depth", &gSessionData->mBacktraceDepth)) { 98 if (writeReadDriver("/dev/gator/backtrace_depth", &gSessionData->mBacktraceDepth)) {
89 logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth"); 99 logg->logError(__FILE__, __LINE__, "Unable to set the driver backtrace depth");
@@ -125,79 +135,112 @@ void Collector::start() {
125 } 135 }
126 136
127 lseek(mBufferFD, 0, SEEK_SET); 137 lseek(mBufferFD, 0, SEEK_SET);
138
139 sem_post(mStartProfile);
140
141 // Collect Data
142 do {
143 // This command will stall until data is received from the driver
144 // Calls event_buffer_read in the driver
145 errno = 0;
146 bytesCollected = read(mBufferFD, collectBuffer, mBufferSize);
147
148 // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data
149 if (bytesCollected == -1 && errno == EINTR) {
150 bytesCollected = read(mBufferFD, collectBuffer, mBufferSize);
151 }
152
153 // return the total bytes written
154 logg->logMessage("Driver read of %d bytes", bytesCollected);
155
156 // In one shot mode, stop collection once all the buffers are filled
157 if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
158 if (bytesCollected == -1 || mFifo->willFill(bytesCollected)) {
159 logg->logMessage("One shot");
160 child->endSession();
161 }
162 }
163 collectBuffer = mFifo->write(bytesCollected);
164 } while (bytesCollected > 0);
165
166 logg->logMessage("Exit collect data loop");
128} 167}
129 168
130// These commands should cause the read() function in collect() to return 169void DriverSource::interrupt() {
131void Collector::stop() { 170 // This command should cause the read() function in collect() to return and stop the driver from profiling
132 // This will stop the driver from profiling
133 if (writeDriver("/dev/gator/enable", "0") != 0) { 171 if (writeDriver("/dev/gator/enable", "0") != 0) {
134 logg->logMessage("Stopping kernel failed"); 172 logg->logMessage("Stopping kernel failed");
135 } 173 }
136} 174}
137 175
138int Collector::collect(char* buffer) { 176bool DriverSource::isDone() {
139 // Calls event_buffer_read in the driver 177 return mLength <= 0;
140 int bytesRead; 178}
141
142 errno = 0;
143 bytesRead = read(mBufferFD, buffer, mBufferSize);
144 179
145 // If read() returned due to an interrupt signal, re-read to obtain the last bit of collected data 180void DriverSource::write(Sender *sender) {
146 if (bytesRead == -1 && errno == EINTR) { 181 char *data = mFifo->read(&mLength);
147 bytesRead = read(mBufferFD, buffer, mBufferSize); 182 if (data != NULL) {
183 sender->writeData(data, mLength, RESPONSE_APC_DATA);
184 mFifo->release();
148 } 185 }
149
150 // return the total bytes written
151 logg->logMessage("Driver read of %d bytes", bytesRead);
152 return bytesRead;
153} 186}
154 187
155int Collector::readIntDriver(const char* fullpath, int* value) { 188int DriverSource::readIntDriver(const char *fullpath, int *value) {
156 FILE* file = fopen(fullpath, "r"); 189 char data[40]; // Sufficiently large to hold any integer
157 if (file == NULL) { 190 const int fd = open(fullpath, O_RDONLY);
191 if (fd < 0) {
192 return -1;
193 }
194
195 const ssize_t bytes = read(fd, data, sizeof(data) - 1);
196 close(fd);
197 if (bytes < 0) {
158 return -1; 198 return -1;
159 } 199 }
160 if (fscanf(file, "%u", value) != 1) { 200 data[bytes] = '\0';
161 fclose(file); 201
202 char *endptr;
203 errno = 0;
204 *value = strtol(data, &endptr, 10);
205 if (errno != 0 || *endptr != '\n') {
162 logg->logMessage("Invalid value in file %s", fullpath); 206 logg->logMessage("Invalid value in file %s", fullpath);
163 return -1; 207 return -1;
164 } 208 }
165 fclose(file); 209
166 return 0; 210 return 0;
167} 211}
168 212
169int Collector::readInt64Driver(const char* fullpath, int64_t* value) { 213int DriverSource::readInt64Driver(const char *fullpath, int64_t *value) {
170 FILE* file = fopen(fullpath, "r"); 214 char data[40]; // Sufficiently large to hold any integer
171 if (file == NULL) { 215 const int fd = open(fullpath, O_RDONLY);
216 if (fd < 0) {
172 return -1; 217 return -1;
173 } 218 }
174 if (fscanf(file, "%" SCNi64, value) != 1) { 219
175 fclose(file); 220 const ssize_t bytes = read(fd, data, sizeof(data) - 1);
176 logg->logMessage("Invalid value in file %s", fullpath); 221 close(fd);
222 if (bytes < 0) {
177 return -1; 223 return -1;
178 } 224 }
179 fclose(file); 225 data[bytes] = '\0';
180 return 0;
181}
182 226
183int Collector::writeDriver(const char* path, int value) { 227 char *endptr;
184 char data[40]; // Sufficiently large to hold any integer 228 errno = 0;
185 snprintf(data, sizeof(data), "%d", value); 229 *value = strtoll(data, &endptr, 10);
186 return writeDriver(path, data); 230 if (errno != 0 || *endptr != '\n') {
187} 231 logg->logMessage("Invalid value in file %s", fullpath);
232 return -1;
233 }
188 234
189int Collector::writeDriver(const char* path, int64_t value) { 235 return 0;
190 char data[40]; // Sufficiently large to hold any integer
191 snprintf(data, sizeof(data), "%" PRIi64, value);
192 return writeDriver(path, data);
193} 236}
194 237
195int Collector::writeDriver(const char* fullpath, const char* data) { 238int DriverSource::writeDriver(const char *fullpath, const char *data) {
196 int fd = open(fullpath, O_WRONLY); 239 int fd = open(fullpath, O_WRONLY);
197 if (fd < 0) { 240 if (fd < 0) {
198 return -1; 241 return -1;
199 } 242 }
200 if (write(fd, data, strlen(data)) < 0) { 243 if (::write(fd, data, strlen(data)) < 0) {
201 close(fd); 244 close(fd);
202 logg->logMessage("Opened but could not write to %s", fullpath); 245 logg->logMessage("Opened but could not write to %s", fullpath);
203 return -1; 246 return -1;
@@ -206,14 +249,26 @@ int Collector::writeDriver(const char* fullpath, const char* data) {
206 return 0; 249 return 0;
207} 250}
208 251
209int Collector::writeReadDriver(const char* path, int* value) { 252int DriverSource::writeDriver(const char *path, int value) {
253 char data[40]; // Sufficiently large to hold any integer
254 snprintf(data, sizeof(data), "%d", value);
255 return writeDriver(path, data);
256}
257
258int DriverSource::writeDriver(const char *path, int64_t value) {
259 char data[40]; // Sufficiently large to hold any integer
260 snprintf(data, sizeof(data), "%" PRIi64, value);
261 return writeDriver(path, data);
262}
263
264int DriverSource::writeReadDriver(const char *path, int *value) {
210 if (writeDriver(path, *value) || readIntDriver(path, value)) { 265 if (writeDriver(path, *value) || readIntDriver(path, value)) {
211 return -1; 266 return -1;
212 } 267 }
213 return 0; 268 return 0;
214} 269}
215 270
216int Collector::writeReadDriver(const char* path, int64_t* value) { 271int DriverSource::writeReadDriver(const char *path, int64_t *value) {
217 if (writeDriver(path, *value) || readInt64Driver(path, value)) { 272 if (writeDriver(path, *value) || readInt64Driver(path, value)) {
218 return -1; 273 return -1;
219 } 274 }
diff --git a/daemon/DriverSource.h b/daemon/DriverSource.h
new file mode 100644
index 0000000..dcf1078
--- /dev/null
+++ b/daemon/DriverSource.h
@@ -0,0 +1,52 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef DRIVERSOURCE_H
10#define DRIVERSOURCE_H
11
12#include <semaphore.h>
13#include <stdint.h>
14
15#include "Source.h"
16
17class Fifo;
18
19class DriverSource : public Source {
20public:
21 DriverSource(sem_t *senderSem, sem_t *startProfile);
22 ~DriverSource();
23
24 bool prepare();
25 void run();
26 void interrupt();
27
28 bool isDone();
29 void write(Sender *sender);
30
31 static int readIntDriver(const char *fullpath, int *value);
32 static int readInt64Driver(const char *fullpath, int64_t *value);
33 static int writeDriver(const char *fullpath, const char *data);
34 static int writeDriver(const char *path, int value);
35 static int writeDriver(const char *path, int64_t value);
36 static int writeReadDriver(const char *path, int *value);
37 static int writeReadDriver(const char *path, int64_t *value);
38
39private:
40 Fifo *mFifo;
41 sem_t *const mSenderSem;
42 sem_t *const mStartProfile;
43 int mBufferSize;
44 int mBufferFD;
45 int mLength;
46
47 // Intentionally unimplemented
48 DriverSource(const DriverSource &);
49 DriverSource &operator=(const DriverSource &);
50};
51
52#endif // DRIVERSOURCE_H
diff --git a/daemon/DynBuf.cpp b/daemon/DynBuf.cpp
new file mode 100644
index 0000000..6f92b33
--- /dev/null
+++ b/daemon/DynBuf.cpp
@@ -0,0 +1,139 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "DynBuf.h"
10
11#include <errno.h>
12#include <fcntl.h>
13#include <stdarg.h>
14#include <stdio.h>
15#include <unistd.h>
16
17#include "Logging.h"
18
19// Pick an aggressive size as buffer is primarily used for disk IO
20#define MIN_BUFFER_FREE (1 << 12)
21
22int DynBuf::resize(const size_t minCapacity) {
23 size_t scaledCapacity = 2 * capacity;
24 if (scaledCapacity < minCapacity) {
25 scaledCapacity = minCapacity;
26 }
27 if (scaledCapacity < 2 * MIN_BUFFER_FREE) {
28 scaledCapacity = 2 * MIN_BUFFER_FREE;
29 }
30 capacity = scaledCapacity;
31
32 buf = static_cast<char *>(realloc(buf, capacity));
33 if (buf == NULL) {
34 return -errno;
35 }
36
37 return 0;
38}
39
40bool DynBuf::read(const char *const path) {
41 int result = false;
42
43 const int fd = open(path, O_RDONLY);
44 if (fd < 0) {
45 logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
46 return false;
47 }
48
49 length = 0;
50
51 for (;;) {
52 const size_t minCapacity = length + MIN_BUFFER_FREE + 1;
53 if (capacity < minCapacity) {
54 if (resize(minCapacity) != 0) {
55 logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
56 goto fail;
57 }
58 }
59
60 const ssize_t bytes = ::read(fd, buf + length, capacity - length - 1);
61 if (bytes < 0) {
62 logg->logMessage("%s(%s:%i): read failed", __FUNCTION__, __FILE__, __LINE__);
63 goto fail;
64 } else if (bytes == 0) {
65 break;
66 }
67 length += bytes;
68 }
69
70 buf[length] = '\0';
71 result = true;
72
73 fail:
74 close(fd);
75
76 return result;
77}
78
79int DynBuf::readlink(const char *const path) {
80 ssize_t bytes = MIN_BUFFER_FREE;
81
82 for (;;) {
83 if (static_cast<size_t>(bytes) >= capacity) {
84 const int err = resize(2 * bytes);
85 if (err != 0) {
86 return err;
87 }
88 }
89 bytes = ::readlink(path, buf, capacity);
90 if (bytes < 0) {
91 return -errno;
92 } else if (static_cast<size_t>(bytes) < capacity) {
93 break;
94 }
95 }
96
97 length = bytes;
98 buf[bytes] = '\0';
99
100 return 0;
101}
102
103bool DynBuf::printf(const char *format, ...) {
104 va_list ap;
105
106 if (capacity <= 0) {
107 if (resize(2 * MIN_BUFFER_FREE) != 0) {
108 logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
109 return false;
110 }
111 }
112
113 va_start(ap, format);
114 int bytes = vsnprintf(buf, capacity, format, ap);
115 va_end(ap);
116 if (bytes < 0) {
117 logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
118 return false;
119 }
120
121 if (static_cast<size_t>(bytes) > capacity) {
122 if (resize(bytes + 1) != 0) {
123 logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
124 return false;
125 }
126
127 va_start(ap, format);
128 bytes = vsnprintf(buf, capacity, format, ap);
129 va_end(ap);
130 if (bytes < 0) {
131 logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
132 return false;
133 }
134 }
135
136 length = bytes;
137
138 return true;
139}
diff --git a/daemon/DynBuf.h b/daemon/DynBuf.h
new file mode 100644
index 0000000..2f4554a
--- /dev/null
+++ b/daemon/DynBuf.h
@@ -0,0 +1,52 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef DYNBUF_H
10#define DYNBUF_H
11
12#include <stdlib.h>
13
14class DynBuf {
15public:
16 DynBuf() : capacity(0), length(0), buf(NULL) {}
17 ~DynBuf() {
18 reset();
19 }
20
21 inline void reset() {
22 capacity = 0;
23 length = 0;
24 if (buf != NULL) {
25 free(buf);
26 buf = NULL;
27 }
28 }
29
30 bool read(const char *const path);
31 // On error instead of printing the error and returning false, this returns -errno
32 int readlink(const char *const path);
33 __attribute__ ((format(printf, 2, 3)))
34 bool printf(const char *format, ...);
35
36 size_t getLength() const { return length; }
37 const char *getBuf() const { return buf; }
38 char *getBuf() { return buf; }
39
40private:
41 int resize(const size_t minCapacity);
42
43 size_t capacity;
44 size_t length;
45 char *buf;
46
47 // Intentionally undefined
48 DynBuf(const DynBuf &);
49 DynBuf &operator=(const DynBuf &);
50};
51
52#endif // DYNBUF_H
diff --git a/daemon/EventsXML.cpp b/daemon/EventsXML.cpp
index 2a80482..a07a046 100644
--- a/daemon/EventsXML.cpp
+++ b/daemon/EventsXML.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -35,7 +35,7 @@ char* EventsXML::getXML() {
35 fclose(fl); 35 fclose(fl);
36 } else { 36 } else {
37 logg->logMessage("Unable to locate events.xml, using default"); 37 logg->logMessage("Unable to locate events.xml, using default");
38 xml = mxmlLoadString(NULL, (char *)events_xml, MXML_NO_CALLBACK); 38 xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK);
39 } 39 }
40 40
41 // Add dynamic events from the drivers 41 // Add dynamic events from the drivers
diff --git a/daemon/EventsXML.h b/daemon/EventsXML.h
index 8e693ef..6cd1560 100644
--- a/daemon/EventsXML.h
+++ b/daemon/EventsXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/ExternalSource.cpp b/daemon/ExternalSource.cpp
new file mode 100644
index 0000000..fe5824b
--- /dev/null
+++ b/daemon/ExternalSource.cpp
@@ -0,0 +1,56 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "ExternalSource.h"
10
11#include <sys/prctl.h>
12
13#include "Logging.h"
14#include "OlySocket.h"
15#include "SessionData.h"
16
17ExternalSource::ExternalSource(sem_t *senderSem) : mBuffer(0, FRAME_EXTERNAL, 1024, senderSem), mSock("/tmp/gator") {
18}
19
20ExternalSource::~ExternalSource() {
21}
22
23bool ExternalSource::prepare() {
24 return true;
25}
26
27void ExternalSource::run() {
28 prctl(PR_SET_NAME, (unsigned long)&"gatord-uds", 0, 0, 0);
29
30 while (gSessionData->mSessionIsActive) {
31 // Will be aborted when the socket is closed at the end of the capture
32 int length = mSock.receive(mBuffer.getWritePos(), mBuffer.contiguousSpaceAvailable());
33 if (length <= 0) {
34 break;
35 }
36
37 mBuffer.advanceWrite(length);
38 mBuffer.check(0);
39 }
40
41 mBuffer.setDone();
42}
43
44void ExternalSource::interrupt() {
45 // Do nothing
46}
47
48bool ExternalSource::isDone() {
49 return mBuffer.isDone();
50}
51
52void ExternalSource::write(Sender *sender) {
53 if (!mBuffer.isDone()) {
54 mBuffer.write(sender);
55 }
56}
diff --git a/daemon/ExternalSource.h b/daemon/ExternalSource.h
new file mode 100644
index 0000000..2052bdf
--- /dev/null
+++ b/daemon/ExternalSource.h
@@ -0,0 +1,40 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef EXTERNALSOURCE_H
10#define EXTERNALSOURCE_H
11
12#include <semaphore.h>
13
14#include "Buffer.h"
15#include "OlySocket.h"
16#include "Source.h"
17
18// Unix domain socket counters from external sources like graphics drivers
19class ExternalSource : public Source {
20public:
21 ExternalSource(sem_t *senderSem);
22 ~ExternalSource();
23
24 bool prepare();
25 void run();
26 void interrupt();
27
28 bool isDone();
29 void write(Sender *sender);
30
31private:
32 Buffer mBuffer;
33 OlySocket mSock;
34
35 // Intentionally unimplemented
36 ExternalSource(const ExternalSource &);
37 ExternalSource &operator=(const ExternalSource &);
38};
39
40#endif // EXTERNALSOURCE_H
diff --git a/daemon/Fifo.cpp b/daemon/Fifo.cpp
index 250a4d0..f672e92 100644
--- a/daemon/Fifo.cpp
+++ b/daemon/Fifo.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Fifo.h b/daemon/Fifo.h
index d25cd68..7dd7426 100644
--- a/daemon/Fifo.h
+++ b/daemon/Fifo.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -12,7 +12,7 @@
12#ifdef WIN32 12#ifdef WIN32
13#include <windows.h> 13#include <windows.h>
14#define sem_t HANDLE 14#define sem_t HANDLE
15#define sem_init(sem, pshared, value) ((*(sem) = CreateSemaphore(NULL, value, INFINITE, NULL)) == NULL) 15#define sem_init(sem, pshared, value) ((*(sem) = CreateSemaphore(NULL, value, LONG_MAX, NULL)) == NULL)
16#define sem_wait(sem) WaitForSingleObject(*(sem), INFINITE) 16#define sem_wait(sem) WaitForSingleObject(*(sem), INFINITE)
17#define sem_post(sem) ReleaseSemaphore(*(sem), 1, NULL) 17#define sem_post(sem) ReleaseSemaphore(*(sem), 1, NULL)
18#define sem_destroy(sem) CloseHandle(*(sem)) 18#define sem_destroy(sem) CloseHandle(*(sem))
diff --git a/daemon/Hwmon.cpp b/daemon/Hwmon.cpp
index 1d7c0da..778f307 100644
--- a/daemon/Hwmon.cpp
+++ b/daemon/Hwmon.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -17,7 +17,7 @@
17 17
18class HwmonCounter { 18class HwmonCounter {
19public: 19public:
20 HwmonCounter(HwmonCounter *next, int key, const sensors_chip_name *chip, const sensors_feature *feature); 20 HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature);
21 ~HwmonCounter(); 21 ~HwmonCounter();
22 22
23 HwmonCounter *getNext() const { return next; } 23 HwmonCounter *getNext() const { return next; }
@@ -69,7 +69,7 @@ private:
69 HwmonCounter &operator=(const HwmonCounter &); 69 HwmonCounter &operator=(const HwmonCounter &);
70}; 70};
71 71
72HwmonCounter::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) { 72HwmonCounter::HwmonCounter(HwmonCounter *next, const sensors_chip_name *chip, const sensors_feature *feature) : next(next), key(getEventKey()), polled(false), readable(false), enabled(false), duplicate(false), chip(chip), feature(feature) {
73 73
74 int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1; 74 int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
75 char *chip_name = new char[len]; 75 char *chip_name = new char[len];
@@ -205,6 +205,23 @@ bool HwmonCounter::canRead() {
205} 205}
206 206
207Hwmon::Hwmon() : counters(NULL) { 207Hwmon::Hwmon() : counters(NULL) {
208}
209
210Hwmon::~Hwmon() {
211 while (counters != NULL) {
212 HwmonCounter * counter = counters;
213 counters = counter->getNext();
214 delete counter;
215 }
216 sensors_cleanup();
217}
218
219void Hwmon::setup() {
220 // hwmon does not currently work with perf
221 if (gSessionData->perf.isSetup()) {
222 return;
223 }
224
208 int err = sensors_init(NULL); 225 int err = sensors_init(NULL);
209 if (err) { 226 if (err) {
210 logg->logMessage("Failed to initialize libsensors! (%d)", err); 227 logg->logMessage("Failed to initialize libsensors! (%d)", err);
@@ -218,20 +235,11 @@ Hwmon::Hwmon() : counters(NULL) {
218 int feature_nr = 0; 235 int feature_nr = 0;
219 const sensors_feature *feature; 236 const sensors_feature *feature;
220 while ((feature = sensors_get_features(chip, &feature_nr))) { 237 while ((feature = sensors_get_features(chip, &feature_nr))) {
221 counters = new HwmonCounter(counters, getEventKey(), chip, feature); 238 counters = new HwmonCounter(counters, chip, feature);
222 } 239 }
223 } 240 }
224} 241}
225 242
226Hwmon::~Hwmon() {
227 while (counters != NULL) {
228 HwmonCounter * counter = counters;
229 counters = counter->getNext();
230 delete counter;
231 }
232 sensors_cleanup();
233}
234
235HwmonCounter *Hwmon::findCounter(const Counter &counter) const { 243HwmonCounter *Hwmon::findCounter(const Counter &counter) const {
236 for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) { 244 for (HwmonCounter * hwmonCounter = counters; hwmonCounter != NULL; hwmonCounter = hwmonCounter->getNext()) {
237 if (hwmonCounter->canRead() && strcmp(hwmonCounter->getName(), counter.getType()) == 0) { 245 if (hwmonCounter->canRead() && strcmp(hwmonCounter->getName(), counter.getType()) == 0) {
@@ -271,14 +279,18 @@ void Hwmon::setupCounter(Counter &counter) {
271 counter.setKey(hwmonCounter->getKey()); 279 counter.setKey(hwmonCounter->getKey());
272} 280}
273 281
274void Hwmon::writeCounters(mxml_node_t *root) const { 282int Hwmon::writeCounters(mxml_node_t *root) const {
283 int count = 0;
275 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) { 284 for (HwmonCounter * counter = counters; counter != NULL; counter = counter->getNext()) {
276 if (!counter->canRead()) { 285 if (!counter->canRead()) {
277 continue; 286 continue;
278 } 287 }
279 mxml_node_t *node = mxmlNewElement(root, "counter"); 288 mxml_node_t *node = mxmlNewElement(root, "counter");
280 mxmlElementSetAttr(node, "name", counter->getName()); 289 mxmlElementSetAttr(node, "name", counter->getName());
290 ++count;
281 } 291 }
292
293 return count;
282} 294}
283 295
284void Hwmon::writeEvents(mxml_node_t *root) const { 296void Hwmon::writeEvents(mxml_node_t *root) const {
diff --git a/daemon/Hwmon.h b/daemon/Hwmon.h
index 46bb42e..a22a360 100644
--- a/daemon/Hwmon.h
+++ b/daemon/Hwmon.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -19,12 +19,14 @@ public:
19 Hwmon(); 19 Hwmon();
20 ~Hwmon(); 20 ~Hwmon();
21 21
22 void setup();
23
22 bool claimCounter(const Counter &counter) const; 24 bool claimCounter(const Counter &counter) const;
23 bool countersEnabled() const; 25 bool countersEnabled() const;
24 void resetCounters(); 26 void resetCounters();
25 void setupCounter(Counter &counter); 27 void setupCounter(Counter &counter);
26 28
27 void writeCounters(mxml_node_t *root) const; 29 int writeCounters(mxml_node_t *root) const;
28 void writeEvents(mxml_node_t *root) const; 30 void writeEvents(mxml_node_t *root) const;
29 31
30 void start(); 32 void start();
diff --git a/daemon/KMod.cpp b/daemon/KMod.cpp
index 559297f..9300002 100644
--- a/daemon/KMod.cpp
+++ b/daemon/KMod.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,9 @@
12#include <dirent.h> 12#include <dirent.h>
13#include <unistd.h> 13#include <unistd.h>
14 14
15#include "Collector.h"
16#include "ConfigurationXML.h" 15#include "ConfigurationXML.h"
17#include "Counter.h" 16#include "Counter.h"
17#include "DriverSource.h"
18#include "Logging.h" 18#include "Logging.h"
19 19
20// Claim all the counters in /dev/gator/events 20// Claim all the counters in /dev/gator/events
@@ -38,9 +38,9 @@ void KMod::resetCounters() {
38 continue; 38 continue;
39 snprintf(base, sizeof(base), "/dev/gator/events/%s", ent->d_name); 39 snprintf(base, sizeof(base), "/dev/gator/events/%s", ent->d_name);
40 snprintf(text, sizeof(text), "%s/enabled", base); 40 snprintf(text, sizeof(text), "%s/enabled", base);
41 Collector::writeDriver(text, 0); 41 DriverSource::writeDriver(text, 0);
42 snprintf(text, sizeof(text), "%s/count", base); 42 snprintf(text, sizeof(text), "%s/count", base);
43 Collector::writeDriver(text, 0); 43 DriverSource::writeDriver(text, 0);
44 } 44 }
45 closedir(dir); 45 closedir(dir);
46 } 46 }
@@ -53,22 +53,22 @@ void KMod::setupCounter(Counter &counter) {
53 53
54 snprintf(text, sizeof(text), "%s/enabled", base); 54 snprintf(text, sizeof(text), "%s/enabled", base);
55 int enabled = true; 55 int enabled = true;
56 if (Collector::writeReadDriver(text, &enabled) || !enabled) { 56 if (DriverSource::writeReadDriver(text, &enabled) || !enabled) {
57 counter.setEnabled(false); 57 counter.setEnabled(false);
58 return; 58 return;
59 } 59 }
60 60
61 snprintf(text, sizeof(text), "%s/key", base); 61 snprintf(text, sizeof(text), "%s/key", base);
62 int key = 0; 62 int key = 0;
63 Collector::readIntDriver(text, &key); 63 DriverSource::readIntDriver(text, &key);
64 counter.setKey(key); 64 counter.setKey(key);
65 65
66 snprintf(text, sizeof(text), "%s/event", base); 66 snprintf(text, sizeof(text), "%s/event", base);
67 Collector::writeDriver(text, counter.getEvent()); 67 DriverSource::writeDriver(text, counter.getEvent());
68 snprintf(text, sizeof(text), "%s/count", base); 68 snprintf(text, sizeof(text), "%s/count", base);
69 if (access(text, F_OK) == 0) { 69 if (access(text, F_OK) == 0) {
70 int count = counter.getCount(); 70 int count = counter.getCount();
71 if (Collector::writeReadDriver(text, &count) && counter.getCount() > 0) { 71 if (DriverSource::writeReadDriver(text, &count) && counter.getCount() > 0) {
72 logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%i with a count of %d\n", counter.getType(), counter.getEvent(), counter.getCount()); 72 logg->logError(__FILE__, __LINE__, "Cannot enable EBS for %s:%i with a count of %d\n", counter.getType(), counter.getEvent(), counter.getCount());
73 handleException(); 73 handleException();
74 } 74 }
@@ -80,23 +80,26 @@ void KMod::setupCounter(Counter &counter) {
80 } 80 }
81} 81}
82 82
83void KMod::writeCounters(mxml_node_t *root) const { 83int KMod::writeCounters(mxml_node_t *root) const {
84 struct dirent *ent; 84 struct dirent *ent;
85 mxml_node_t *counter; 85 mxml_node_t *counter;
86 86
87 // counters.xml is simply a file listing of /dev/gator/events 87 // counters.xml is simply a file listing of /dev/gator/events
88 DIR* dir = opendir("/dev/gator/events"); 88 DIR* dir = opendir("/dev/gator/events");
89 if (dir == NULL) { 89 if (dir == NULL) {
90 logg->logError(__FILE__, __LINE__, "Cannot create counters.xml since unable to read /dev/gator/events"); 90 return 0;
91 handleException();
92 } 91 }
93 92
93 int count = 0;
94 while ((ent = readdir(dir)) != NULL) { 94 while ((ent = readdir(dir)) != NULL) {
95 // skip hidden files, current dir, and parent dir 95 // skip hidden files, current dir, and parent dir
96 if (ent->d_name[0] == '.') 96 if (ent->d_name[0] == '.')
97 continue; 97 continue;
98 counter = mxmlNewElement(root, "counter"); 98 counter = mxmlNewElement(root, "counter");
99 mxmlElementSetAttr(counter, "name", ent->d_name); 99 mxmlElementSetAttr(counter, "name", ent->d_name);
100 ++count;
100 } 101 }
101 closedir(dir); 102 closedir(dir);
103
104 return count;
102} 105}
diff --git a/daemon/KMod.h b/daemon/KMod.h
index 7974262..fb7fc8a 100644
--- a/daemon/KMod.h
+++ b/daemon/KMod.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2013. All rights reserved. 2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -21,7 +21,7 @@ public:
21 void resetCounters(); 21 void resetCounters();
22 void setupCounter(Counter &counter); 22 void setupCounter(Counter &counter);
23 23
24 void writeCounters(mxml_node_t *root) const; 24 int writeCounters(mxml_node_t *root) const;
25}; 25};
26 26
27#endif // KMOD_H 27#endif // KMOD_H
diff --git a/daemon/LocalCapture.cpp b/daemon/LocalCapture.cpp
index 3235a34..d2a4b79 100644
--- a/daemon/LocalCapture.cpp
+++ b/daemon/LocalCapture.cpp
@@ -1,18 +1,20 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "LocalCapture.h"
10
9#include <sys/stat.h> 11#include <sys/stat.h>
10#include <sys/types.h> 12#include <sys/types.h>
11#include <dirent.h> 13#include <dirent.h>
12#include <string.h> 14#include <string.h>
13#include <stdlib.h> 15#include <stdlib.h>
14#include <unistd.h> 16#include <unistd.h>
15#include "LocalCapture.h" 17
16#include "SessionData.h" 18#include "SessionData.h"
17#include "Logging.h" 19#include "Logging.h"
18#include "OlyUtility.h" 20#include "OlyUtility.h"
diff --git a/daemon/LocalCapture.h b/daemon/LocalCapture.h
index 8042d6a..aadecce 100644
--- a/daemon/LocalCapture.h
+++ b/daemon/LocalCapture.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/Logging.cpp b/daemon/Logging.cpp
index 5fd45b5..b8d3178 100644
--- a/daemon/Logging.cpp
+++ b/daemon/Logging.cpp
@@ -1,11 +1,13 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "Logging.h"
10
9#include <stdio.h> 11#include <stdio.h>
10#include <stdlib.h> 12#include <stdlib.h>
11#include <stdarg.h> 13#include <stdarg.h>
@@ -23,8 +25,6 @@
23#define MUTEX_UNLOCK() pthread_mutex_unlock(&mLoggingMutex) 25#define MUTEX_UNLOCK() pthread_mutex_unlock(&mLoggingMutex)
24#endif 26#endif
25 27
26#include "Logging.h"
27
28// Global thread-safe logging 28// Global thread-safe logging
29Logging* logg = NULL; 29Logging* logg = NULL;
30 30
diff --git a/daemon/Logging.h b/daemon/Logging.h
index 8f960de..6ae3280 100644
--- a/daemon/Logging.h
+++ b/daemon/Logging.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,14 +9,7 @@
9#ifndef __LOGGING_H__ 9#ifndef __LOGGING_H__
10#define __LOGGING_H__ 10#define __LOGGING_H__
11 11
12#include <stdio.h>
13#include <string.h>
14#include <limits.h>
15#ifdef WIN32
16#include <windows.h>
17#else
18#include <pthread.h> 12#include <pthread.h>
19#endif
20 13
21#define DRIVER_ERROR "\n Driver issue:\n >> gator.ko must be built against the current kernel version & configuration\n >> gator.ko should be co-located with gatord in the same directory\n >> OR insmod gator.ko prior to launching gatord" 14#define DRIVER_ERROR "\n Driver issue:\n >> gator.ko must be built against the current kernel version & configuration\n >> gator.ko should be co-located with gatord in the same directory\n >> OR insmod gator.ko prior to launching gatord"
22 15
@@ -33,11 +26,7 @@ private:
33 char mErrBuf[4096]; // Arbitrarily large buffer to hold a string 26 char mErrBuf[4096]; // Arbitrarily large buffer to hold a string
34 char mLogBuf[4096]; // Arbitrarily large buffer to hold a string 27 char mLogBuf[4096]; // Arbitrarily large buffer to hold a string
35 bool mDebug; 28 bool mDebug;
36#ifdef WIN32
37 HANDLE mLoggingMutex;
38#else
39 pthread_mutex_t mLoggingMutex; 29 pthread_mutex_t mLoggingMutex;
40#endif
41}; 30};
42 31
43extern Logging* logg; 32extern Logging* logg;
diff --git a/daemon/Monitor.cpp b/daemon/Monitor.cpp
new file mode 100644
index 0000000..90d5c47
--- /dev/null
+++ b/daemon/Monitor.cpp
@@ -0,0 +1,61 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Monitor.h"
10
11#include <errno.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "Logging.h"
16
17Monitor::Monitor() : mFd(-1) {
18}
19
20Monitor::~Monitor() {
21 if (mFd >= -1) {
22 close(mFd);
23 }
24}
25
26bool Monitor::init() {
27 mFd = epoll_create(16);
28 if (mFd < 0) {
29 logg->logMessage("%s(%s:%i): epoll_create1 failed", __FUNCTION__, __FILE__, __LINE__);
30 return false;
31 }
32
33 return true;
34}
35
36bool Monitor::add(const int fd) {
37 struct epoll_event event;
38 memset(&event, 0, sizeof(event));
39 event.data.fd = fd;
40 event.events = EPOLLIN;
41 if (epoll_ctl(mFd, EPOLL_CTL_ADD, fd, &event) != 0) {
42 logg->logMessage("%s(%s:%i): epoll_ctl failed", __FUNCTION__, __FILE__, __LINE__);
43 return false;
44 }
45
46 return true;
47}
48
49int Monitor::wait(struct epoll_event *const events, int maxevents, int timeout) {
50 int result = epoll_wait(mFd, events, maxevents, timeout);
51 if (result < 0) {
52 // Ignore if the call was interrupted as this will happen when SIGINT is received
53 if (errno == EINTR) {
54 result = 0;
55 } else {
56 logg->logMessage("%s(%s:%i): epoll_wait failed", __FUNCTION__, __FILE__, __LINE__);
57 }
58 }
59
60 return result;
61}
diff --git a/daemon/Monitor.h b/daemon/Monitor.h
new file mode 100644
index 0000000..6e268b6
--- /dev/null
+++ b/daemon/Monitor.h
@@ -0,0 +1,32 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef MONITOR_H
10#define MONITOR_H
11
12#include <sys/epoll.h>
13
14class Monitor {
15public:
16 Monitor();
17 ~Monitor();
18
19 bool init();
20 bool add(const int fd);
21 int wait(struct epoll_event *const events, int maxevents, int timeout);
22
23private:
24
25 int mFd;
26
27 // Intentionally unimplemented
28 Monitor(const Monitor &);
29 Monitor &operator=(const Monitor &);
30};
31
32#endif // MONITOR_H
diff --git a/daemon/OlySocket.cpp b/daemon/OlySocket.cpp
index ab5c3c2..26e4768 100644
--- a/daemon/OlySocket.cpp
+++ b/daemon/OlySocket.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,7 @@
15#else 15#else
16#include <netinet/in.h> 16#include <netinet/in.h>
17#include <sys/socket.h> 17#include <sys/socket.h>
18#include <sys/un.h>
18#include <unistd.h> 19#include <unistd.h>
19#include <netdb.h> 20#include <netdb.h>
20#endif 21#endif
@@ -30,7 +31,7 @@
30#define SHUTDOWN_RX_TX SHUT_RDWR 31#define SHUTDOWN_RX_TX SHUT_RDWR
31#endif 32#endif
32 33
33OlySocket::OlySocket(int port, bool multiple) { 34OlyServerSocket::OlyServerSocket(int port) {
34#ifdef WIN32 35#ifdef WIN32
35 WSADATA wsaData; 36 WSADATA wsaData;
36 if (WSAStartup(0x0202, &wsaData) != 0) { 37 if (WSAStartup(0x0202, &wsaData) != 0) {
@@ -39,24 +40,82 @@ OlySocket::OlySocket(int port, bool multiple) {
39 } 40 }
40#endif 41#endif
41 42
42 if (multiple) { 43 createServerSocket(port);
43 createServerSocket(port);
44 } else {
45 createSingleServerConnection(port);
46 }
47} 44}
48 45
49OlySocket::OlySocket(int port, char* host) { 46OlySocket::OlySocket(int port, const char* host) {
50 mFDServer = 0;
51 createClientSocket(host, port); 47 createClientSocket(host, port);
52} 48}
53 49
50OlySocket::OlySocket(int socketID) : mSocketID(socketID) {
51}
52
53#ifndef WIN32
54
55OlyServerSocket::OlyServerSocket(const char* path) {
56 // Create socket
57 mFDServer = socket(PF_UNIX, SOCK_STREAM, 0);
58 if (mFDServer < 0) {
59 logg->logError(__FILE__, __LINE__, "Error creating server socket");
60 handleException();
61 }
62
63 unlink(path);
64
65 // Create sockaddr_in structure, ensuring non-populated fields are zero
66 struct sockaddr_un sockaddr;
67 memset((void*)&sockaddr, 0, sizeof(sockaddr));
68 sockaddr.sun_family = AF_UNIX;
69 strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
70 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
71
72 // Bind the socket to an address
73 if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
74 logg->logError(__FILE__, __LINE__, "Binding of server socket failed.");
75 handleException();
76 }
77
78 // Listen for connections on this socket
79 if (listen(mFDServer, 1) < 0) {
80 logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
81 handleException();
82 }
83}
84
85OlySocket::OlySocket(const char* path) {
86 mSocketID = socket(PF_UNIX, SOCK_STREAM, 0);
87 if (mSocketID < 0) {
88 return;
89 }
90
91 // Create sockaddr_in structure, ensuring non-populated fields are zero
92 struct sockaddr_un sockaddr;
93 memset((void*)&sockaddr, 0, sizeof(sockaddr));
94 sockaddr.sun_family = AF_UNIX;
95 strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
96 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
97
98 if (connect(mSocketID, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
99 close(mSocketID);
100 mSocketID = -1;
101 return;
102 }
103}
104
105#endif
106
54OlySocket::~OlySocket() { 107OlySocket::~OlySocket() {
55 if (mSocketID > 0) { 108 if (mSocketID > 0) {
56 CLOSE_SOCKET(mSocketID); 109 CLOSE_SOCKET(mSocketID);
57 } 110 }
58} 111}
59 112
113OlyServerSocket::~OlyServerSocket() {
114 if (mFDServer > 0) {
115 CLOSE_SOCKET(mFDServer);
116 }
117}
118
60void OlySocket::shutdownConnection() { 119void OlySocket::shutdownConnection() {
61 // Shutdown is primarily used to unblock other threads that are blocking on send/receive functions 120 // Shutdown is primarily used to unblock other threads that are blocking on send/receive functions
62 shutdown(mSocketID, SHUTDOWN_RX_TX); 121 shutdown(mSocketID, SHUTDOWN_RX_TX);
@@ -70,7 +129,7 @@ void OlySocket::closeSocket() {
70 } 129 }
71} 130}
72 131
73void OlySocket::closeServerSocket() { 132void OlyServerSocket::closeServerSocket() {
74 if (CLOSE_SOCKET(mFDServer) != 0) { 133 if (CLOSE_SOCKET(mFDServer) != 0) {
75 logg->logError(__FILE__, __LINE__, "Failed to close server socket."); 134 logg->logError(__FILE__, __LINE__, "Failed to close server socket.");
76 handleException(); 135 handleException();
@@ -78,7 +137,7 @@ void OlySocket::closeServerSocket() {
78 mFDServer = 0; 137 mFDServer = 0;
79} 138}
80 139
81void OlySocket::createClientSocket(char* hostname, int portno) { 140void OlySocket::createClientSocket(const char* hostname, int portno) {
82#ifdef WIN32 141#ifdef WIN32
83 // TODO: Implement for Windows 142 // TODO: Implement for Windows
84#else 143#else
@@ -119,14 +178,7 @@ void OlySocket::createClientSocket(char* hostname, int portno) {
119#endif 178#endif
120} 179}
121 180
122void OlySocket::createSingleServerConnection(int port) { 181void OlyServerSocket::createServerSocket(int port) {
123 createServerSocket(port);
124
125 mSocketID = acceptConnection();
126 closeServerSocket();
127}
128
129void OlySocket::createServerSocket(int port) {
130 int family = AF_INET6; 182 int family = AF_INET6;
131 183
132 // Create socket 184 // Create socket
@@ -169,22 +221,23 @@ void OlySocket::createServerSocket(int port) {
169 221
170// mSocketID is always set to the most recently accepted connection 222// mSocketID is always set to the most recently accepted connection
171// The user of this class should maintain the different socket connections, e.g. by forking the process 223// The user of this class should maintain the different socket connections, e.g. by forking the process
172int OlySocket::acceptConnection() { 224int OlyServerSocket::acceptConnection() {
225 int socketID;
173 if (mFDServer <= 0) { 226 if (mFDServer <= 0) {
174 logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket"); 227 logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket");
175 handleException(); 228 handleException();
176 } 229 }
177 230
178 // Accept a connection, note that this call blocks until a client connects 231 // Accept a connection, note that this call blocks until a client connects
179 mSocketID = accept(mFDServer, NULL, NULL); 232 socketID = accept(mFDServer, NULL, NULL);
180 if (mSocketID < 0) { 233 if (socketID < 0) {
181 logg->logError(__FILE__, __LINE__, "Socket acceptance failed"); 234 logg->logError(__FILE__, __LINE__, "Socket acceptance failed");
182 handleException(); 235 handleException();
183 } 236 }
184 return mSocketID; 237 return socketID;
185} 238}
186 239
187void OlySocket::send(char* buffer, int size) { 240void OlySocket::send(const char* buffer, int size) {
188 if (size <= 0 || buffer == NULL) { 241 if (size <= 0 || buffer == NULL) {
189 return; 242 return;
190 } 243 }
diff --git a/daemon/OlySocket.h b/daemon/OlySocket.h
index 5bab7d1..eab786b 100644
--- a/daemon/OlySocket.h
+++ b/daemon/OlySocket.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,27 +9,44 @@
9#ifndef __OLY_SOCKET_H__ 9#ifndef __OLY_SOCKET_H__
10#define __OLY_SOCKET_H__ 10#define __OLY_SOCKET_H__
11 11
12#include <string.h>
13
14class OlySocket { 12class OlySocket {
15public: 13public:
16 OlySocket(int port, bool multipleConnections = false); 14 OlySocket(int port, const char* hostname);
17 OlySocket(int port, char* hostname); 15 OlySocket(int socketID);
16#ifndef WIN32
17 OlySocket(const char* path);
18#endif
18 ~OlySocket(); 19 ~OlySocket();
19 int acceptConnection(); 20
20 void closeSocket(); 21 void closeSocket();
21 void closeServerSocket();
22 void shutdownConnection(); 22 void shutdownConnection();
23 void send(char* buffer, int size); 23 void send(const char* buffer, int size);
24 void sendString(const char* string) {send((char*)string, strlen(string));}
25 int receive(char* buffer, int size); 24 int receive(char* buffer, int size);
26 int receiveNBytes(char* buffer, int size); 25 int receiveNBytes(char* buffer, int size);
27 int receiveString(char* buffer, int size); 26 int receiveString(char* buffer, int size);
28 int getSocketID() {return mSocketID;} 27
28 bool isValid() const { return mSocketID >= 0; }
29
30private:
31 int mSocketID;
32
33 void createClientSocket(const char* hostname, int port);
34};
35
36class OlyServerSocket {
37public:
38 OlyServerSocket(int port);
39#ifndef WIN32
40 OlyServerSocket(const char* path);
41#endif
42 ~OlyServerSocket();
43
44 int acceptConnection();
45 void closeServerSocket();
46
29private: 47private:
30 int mSocketID, mFDServer; 48 int mFDServer;
31 void createClientSocket(char* hostname, int port); 49
32 void createSingleServerConnection(int port);
33 void createServerSocket(int port); 50 void createServerSocket(int port);
34}; 51};
35 52
diff --git a/daemon/OlyUtility.cpp b/daemon/OlyUtility.cpp
index 0b22d6e..45340a2 100644
--- a/daemon/OlyUtility.cpp
+++ b/daemon/OlyUtility.cpp
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/OlyUtility.h b/daemon/OlyUtility.h
index abab0a5..1d26beb 100644
--- a/daemon/OlyUtility.h
+++ b/daemon/OlyUtility.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/PerfBuffer.cpp b/daemon/PerfBuffer.cpp
new file mode 100644
index 0000000..5fad583
--- /dev/null
+++ b/daemon/PerfBuffer.cpp
@@ -0,0 +1,139 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfBuffer.h"
10
11#include <sys/ioctl.h>
12#include <sys/mman.h>
13
14#include "Buffer.h"
15#include "Logging.h"
16#include "Sender.h"
17#include "SessionData.h"
18
19PerfBuffer::PerfBuffer() {
20 for (int cpu = 0; cpu < ARRAY_LENGTH(mBuf); ++cpu) {
21 mBuf[cpu] = MAP_FAILED;
22 mDiscard[cpu] = false;
23 }
24}
25
26PerfBuffer::~PerfBuffer() {
27 for (int cpu = ARRAY_LENGTH(mBuf) - 1; cpu >= 0; --cpu) {
28 if (mBuf[cpu] != MAP_FAILED) {
29 munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
30 }
31 }
32}
33
34bool PerfBuffer::useFd(const int cpu, const int fd, const int groupFd) {
35 if (fd == groupFd) {
36 if (mBuf[cpu] != MAP_FAILED) {
37 logg->logMessage("%s(%s:%i): cpu %i already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__, cpu);
38 return false;
39 }
40
41 // The buffer isn't mapped yet
42 mBuf[cpu] = mmap(NULL, gSessionData->mPageSize + BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
43 if (mBuf[cpu] == MAP_FAILED) {
44 logg->logMessage("%s(%s:%i): mmap failed", __FUNCTION__, __FILE__, __LINE__);
45 return false;
46 }
47
48 // Check the version
49 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
50 if (pemp->compat_version != 0) {
51 logg->logMessage("%s(%s:%i): Incompatible perf_event_mmap_page compat_version", __FUNCTION__, __FILE__, __LINE__);
52 return false;
53 }
54 } else {
55 if (mBuf[cpu] == MAP_FAILED) {
56 logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
57 return false;
58 }
59
60 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, groupFd) < 0) {
61 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
62 return false;
63 }
64 }
65
66 return true;
67}
68
69void PerfBuffer::discard(const int cpu) {
70 if (mBuf[cpu] != MAP_FAILED) {
71 mDiscard[cpu] = true;
72 }
73}
74
75bool PerfBuffer::isEmpty() {
76 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
77 if (mBuf[cpu] != MAP_FAILED) {
78 // Take a snapshot of the positions
79 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
80 const __u64 head = pemp->data_head;
81 const __u64 tail = pemp->data_tail;
82
83 if (head != tail) {
84 return false;
85 }
86 }
87 }
88
89 return true;
90}
91
92bool PerfBuffer::send(Sender *const sender) {
93 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
94 if (mBuf[cpu] == MAP_FAILED) {
95 continue;
96 }
97
98 // Take a snapshot of the positions
99 struct perf_event_mmap_page *pemp = static_cast<struct perf_event_mmap_page *>(mBuf[cpu]);
100 const __u64 head = pemp->data_head;
101 const __u64 tail = pemp->data_tail;
102
103 if (head > tail) {
104 const uint8_t *const b = static_cast<uint8_t *>(mBuf[cpu]) + gSessionData->mPageSize;
105 const int offset = gSessionData->mLocalCapture ? 1 : 0;
106 unsigned char header[7];
107 header[0] = RESPONSE_APC_DATA;
108 Buffer::writeLEInt(header + 1, head - tail + sizeof(header) - 5);
109 // Should use real packing functions
110 header[5] = FRAME_PERF;
111 header[6] = cpu;
112
113 // Write header
114 sender->writeData(reinterpret_cast<const char *>(&header) + offset, sizeof(header) - offset, RESPONSE_APC_DATA);
115
116 // Write data
117 if ((head & ~BUF_MASK) == (tail & ~BUF_MASK)) {
118 // Not wrapped
119 sender->writeData(reinterpret_cast<const char *>(b + (tail & BUF_MASK)), head - tail, RESPONSE_APC_DATA);
120 } else {
121 // Wrapped
122 sender->writeData(reinterpret_cast<const char *>(b + (tail & BUF_MASK)), BUF_SIZE - (tail & BUF_MASK), RESPONSE_APC_DATA);
123 sender->writeData(reinterpret_cast<const char *>(b), head & BUF_MASK, RESPONSE_APC_DATA);
124 }
125
126 // Update tail with the data read
127 pemp->data_tail = head;
128 }
129
130 if (mDiscard[cpu]) {
131 munmap(mBuf[cpu], gSessionData->mPageSize + BUF_SIZE);
132 mBuf[cpu] = MAP_FAILED;
133 mDiscard[cpu] = false;
134 logg->logMessage("%s(%s:%i): Unmaped cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
135 }
136 }
137
138 return true;
139}
diff --git a/daemon/PerfBuffer.h b/daemon/PerfBuffer.h
new file mode 100644
index 0000000..278a3b9
--- /dev/null
+++ b/daemon/PerfBuffer.h
@@ -0,0 +1,39 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERF_BUFFER
10#define PERF_BUFFER
11
12#include "Config.h"
13
14#define BUF_SIZE (gSessionData->mTotalBufferSize * 1024 * 1024)
15#define BUF_MASK (BUF_SIZE - 1)
16
17class Sender;
18
19class PerfBuffer {
20public:
21 PerfBuffer();
22 ~PerfBuffer();
23
24 bool useFd(const int cpu, const int fd, const int groupFd);
25 void discard(const int cpu);
26 bool isEmpty();
27 bool send(Sender *const sender);
28
29private:
30 void *mBuf[NR_CPUS];
31 // After the buffer is flushed it should be unmaped
32 bool mDiscard[NR_CPUS];
33
34 // Intentionally undefined
35 PerfBuffer(const PerfBuffer &);
36 PerfBuffer &operator=(const PerfBuffer &);
37};
38
39#endif // PERF_BUFFER
diff --git a/daemon/PerfDriver.cpp b/daemon/PerfDriver.cpp
new file mode 100644
index 0000000..8e25c22
--- /dev/null
+++ b/daemon/PerfDriver.cpp
@@ -0,0 +1,355 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfDriver.h"
10
11#include <dirent.h>
12#include <sys/utsname.h>
13#include <time.h>
14
15#include "Buffer.h"
16#include "Config.h"
17#include "ConfigurationXML.h"
18#include "Counter.h"
19#include "DriverSource.h"
20#include "DynBuf.h"
21#include "Logging.h"
22#include "PerfGroup.h"
23#include "SessionData.h"
24
25#define PERF_DEVICES "/sys/bus/event_source/devices"
26
27#define TYPE_DERIVED ~0U
28
29// From gator.h
30struct gator_cpu {
31 const int cpuid;
32 // Human readable name
33 const char core_name[32];
34 // gatorfs event and Perf PMU name
35 const char *const pmnc_name;
36 const int pmnc_counters;
37};
38
39// From gator_main.c
40static const struct gator_cpu gator_cpus[] = {
41 { 0xb36, "ARM1136", "ARM_ARM11", 3 },
42 { 0xb56, "ARM1156", "ARM_ARM11", 3 },
43 { 0xb76, "ARM1176", "ARM_ARM11", 3 },
44 { 0xb02, "ARM11MPCore", "ARM_ARM11MPCore", 3 },
45 { 0xc05, "Cortex-A5", "ARMv7_Cortex_A5", 2 },
46 { 0xc07, "Cortex-A7", "ARMv7_Cortex_A7", 4 },
47 { 0xc08, "Cortex-A8", "ARMv7_Cortex_A8", 4 },
48 { 0xc09, "Cortex-A9", "ARMv7_Cortex_A9", 6 },
49 { 0xc0d, "Cortex-A12", "ARMv7_Cortex_A12", 6 },
50 { 0xc0f, "Cortex-A15", "ARMv7_Cortex_A15", 6 },
51 { 0xc0e, "Cortex-A17", "ARMv7_Cortex_A17", 6 },
52 { 0x00f, "Scorpion", "Scorpion", 4 },
53 { 0x02d, "ScorpionMP", "ScorpionMP", 4 },
54 { 0x049, "KraitSIM", "Krait", 4 },
55 { 0x04d, "Krait", "Krait", 4 },
56 { 0x06f, "Krait S4 Pro", "Krait", 4 },
57 { 0xd03, "Cortex-A53", "ARM_Cortex-A53", 6 },
58 { 0xd07, "Cortex-A57", "ARM_Cortex-A57", 6 },
59 { 0xd0f, "AArch64", "ARM_AArch64", 6 },
60};
61
62static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-";
63static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_";
64
65class PerfCounter {
66public:
67 PerfCounter(PerfCounter *next, const char *name, uint32_t type, uint64_t config) : mNext(next), mName(name), mType(type), mCount(0), mKey(getEventKey()), mConfig(config), mEnabled(false) {}
68 ~PerfCounter() {
69 delete [] mName;
70 }
71
72 PerfCounter *getNext() const { return mNext; }
73 const char *getName() const { return mName; }
74 uint32_t getType() const { return mType; }
75 int getCount() const { return mCount; }
76 void setCount(const int count) { mCount = count; }
77 int getKey() const { return mKey; }
78 uint64_t getConfig() const { return mConfig; }
79 void setConfig(const uint64_t config) { mConfig = config; }
80 bool isEnabled() const { return mEnabled; }
81 void setEnabled(const bool enabled) { mEnabled = enabled; }
82
83private:
84 PerfCounter *const mNext;
85 const char *const mName;
86 const uint32_t mType;
87 int mCount;
88 const int mKey;
89 uint64_t mConfig;
90 bool mEnabled;
91};
92
93PerfDriver::PerfDriver() : mCounters(NULL), mIsSetup(false) {
94}
95
96PerfDriver::~PerfDriver() {
97 while (mCounters != NULL) {
98 PerfCounter *counter = mCounters;
99 mCounters = counter->getNext();
100 delete counter;
101 }
102}
103
104void PerfDriver::addCpuCounters(const char *const counterName, const int type, const int numCounters) {
105 int len = snprintf(NULL, 0, "%s_ccnt", counterName) + 1;
106 char *name = new char[len];
107 snprintf(name, len, "%s_ccnt", counterName);
108 mCounters = new PerfCounter(mCounters, name, type, -1);
109
110 for (int j = 0; j < numCounters; ++j) {
111 len = snprintf(NULL, 0, "%s_cnt%d", counterName, j) + 1;
112 name = new char[len];
113 snprintf(name, len, "%s_cnt%d", counterName, j);
114 mCounters = new PerfCounter(mCounters, name, type, -1);
115 }
116}
117
118// From include/generated/uapi/linux/version.h
119#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
120
121bool PerfDriver::setup() {
122 // Check the kernel version
123 struct utsname utsname;
124 if (uname(&utsname) != 0) {
125 logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
126 return false;
127 }
128
129 int release[3] = { 0, 0, 0 };
130 int part = 0;
131 char *ch = utsname.release;
132 while (*ch >= '0' && *ch <= '9' && part < ARRAY_LENGTH(release)) {
133 release[part] = 10*release[part] + *ch - '0';
134
135 ++ch;
136 if (*ch == '.') {
137 ++part;
138 ++ch;
139 }
140 }
141
142 if (KERNEL_VERSION(release[0], release[1], release[2]) < KERNEL_VERSION(3, 12, 0)) {
143 logg->logMessage("%s(%s:%i): Unsupported kernel version", __FUNCTION__, __FILE__, __LINE__);
144 return false;
145 }
146
147 // Add supported PMUs
148 bool foundCpu = false;
149 DIR *dir = opendir(PERF_DEVICES);
150 if (dir == NULL) {
151 logg->logMessage("%s(%s:%i): opendif failed", __FUNCTION__, __FILE__, __LINE__);
152 return false;
153 }
154
155 struct dirent *dirent;
156 while ((dirent = readdir(dir)) != NULL) {
157 for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
158 // Do the names match exactly?
159 if (strcmp(dirent->d_name, gator_cpus[i].pmnc_name) != 0 &&
160 // Do these names match but have the old vs new prefix?
161 (strncmp(dirent->d_name, OLD_PMU_PREFIX, sizeof(OLD_PMU_PREFIX) - 1) != 0 ||
162 strncmp(gator_cpus[i].pmnc_name, NEW_PMU_PREFIX, sizeof(NEW_PMU_PREFIX) - 1) != 0 ||
163 strcmp(dirent->d_name + sizeof(OLD_PMU_PREFIX) - 1, gator_cpus[i].pmnc_name + sizeof(NEW_PMU_PREFIX) - 1) != 0)) {
164 continue;
165 }
166
167 int type;
168 char buf[256];
169 snprintf(buf, sizeof(buf), PERF_DEVICES "/%s/type", dirent->d_name);
170 if (DriverSource::readIntDriver(buf, &type) != 0) {
171 continue;
172 }
173
174 foundCpu = true;
175 addCpuCounters(gator_cpus[i].pmnc_name, type, gator_cpus[i].pmnc_counters);
176 }
177 }
178 closedir(dir);
179
180 if (!foundCpu) {
181 // If no cpu was found based on pmu names, try by cpuid
182 for (int i = 0; i < ARRAY_LENGTH(gator_cpus); ++i) {
183 if (gSessionData->mMaxCpuId != gator_cpus[i].cpuid) {
184 continue;
185 }
186
187 foundCpu = true;
188 addCpuCounters(gator_cpus[i].pmnc_name, PERF_TYPE_RAW, gator_cpus[i].pmnc_counters);
189 }
190 }
191
192 /*
193 if (!foundCpu) {
194 // If all else fails, use the perf architected counters
195 // 9 because that's how many are in events-Perf-Hardware.xml - assume they can all be enabled at once
196 addCpuCounters("Perf_Hardware", PERF_TYPE_HARDWARE, 9);
197 }
198 */
199
200 // Add supported software counters
201 long long id;
202 DynBuf printb;
203
204 id = getTracepointId("irq/softirq_exit", &printb);
205 if (id >= 0) {
206 mCounters = new PerfCounter(mCounters, "Linux_irq_softirq", PERF_TYPE_TRACEPOINT, id);
207 }
208
209 id = getTracepointId("irq/irq_handler_exit", &printb);
210 if (id >= 0) {
211 mCounters = new PerfCounter(mCounters, "Linux_irq_irq", PERF_TYPE_TRACEPOINT, id);
212 }
213
214 //Linux_block_rq_wr
215 //Linux_block_rq_rd
216 //Linux_net_rx
217 //Linux_net_tx
218
219 id = getTracepointId(SCHED_SWITCH, &printb);
220 if (id >= 0) {
221 mCounters = new PerfCounter(mCounters, "Linux_sched_switch", PERF_TYPE_TRACEPOINT, id);
222 }
223
224 //Linux_meminfo_memused
225 //Linux_meminfo_memfree
226 //Linux_meminfo_bufferram
227 //Linux_power_cpu_freq
228 //Linux_power_cpu_idle
229
230 mCounters = new PerfCounter(mCounters, "Linux_cpu_wait_contention", TYPE_DERIVED, -1);
231
232 //Linux_cpu_wait_io
233
234 mIsSetup = true;
235 return true;
236}
237
238bool PerfDriver::summary(Buffer *const buffer) {
239 struct utsname utsname;
240 if (uname(&utsname) != 0) {
241 logg->logMessage("%s(%s:%i): uname failed", __FUNCTION__, __FILE__, __LINE__);
242 return false;
243 }
244
245 char buf[512];
246 snprintf(buf, sizeof(buf), "%s %s %s %s %s GNU/Linux", utsname.sysname, utsname.nodename, utsname.release, utsname.version, utsname.machine);
247
248 struct timespec ts;
249 if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
250 logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__);
251 return false;
252 }
253 const int64_t timestamp = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec;
254
255 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
256 logg->logMessage("%s(%s:%i): clock_gettime failed", __FUNCTION__, __FILE__, __LINE__);
257 return false;
258 }
259 const int64_t uptime = (int64_t)ts.tv_sec * 1000000000L + ts.tv_nsec;
260
261 buffer->summary(timestamp, uptime, 0, buf);
262
263 for (int i = 0; i < gSessionData->mCores; ++i) {
264 int j;
265 for (j = 0; j < ARRAY_LENGTH(gator_cpus); ++j) {
266 if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) {
267 break;
268 }
269 }
270 if (gator_cpus[j].cpuid == gSessionData->mCpuIds[i]) {
271 buffer->coreName(i, gSessionData->mCpuIds[i], gator_cpus[j].core_name);
272 } else {
273 snprintf(buf, sizeof(buf), "Unknown (0x%.3x)", gSessionData->mCpuIds[i]);
274 buffer->coreName(i, gSessionData->mCpuIds[i], buf);
275 }
276 }
277 buffer->commit(1);
278
279 return true;
280}
281
282PerfCounter *PerfDriver::findCounter(const Counter &counter) const {
283 for (PerfCounter * perfCounter = mCounters; perfCounter != NULL; perfCounter = perfCounter->getNext()) {
284 if (strcmp(perfCounter->getName(), counter.getType()) == 0) {
285 return perfCounter;
286 }
287 }
288
289 return NULL;
290}
291
292bool PerfDriver::claimCounter(const Counter &counter) const {
293 return findCounter(counter) != NULL;
294}
295
296void PerfDriver::resetCounters() {
297 for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
298 counter->setEnabled(false);
299 }
300}
301
302void PerfDriver::setupCounter(Counter &counter) {
303 PerfCounter *const perfCounter = findCounter(counter);
304 if (perfCounter == NULL) {
305 counter.setEnabled(false);
306 return;
307 }
308
309 // Don't use the config from counters XML if it's not set, ex: software counters
310 if (counter.getEvent() != -1) {
311 perfCounter->setConfig(counter.getEvent());
312 }
313 perfCounter->setCount(counter.getCount());
314 perfCounter->setEnabled(true);
315 counter.setKey(perfCounter->getKey());
316}
317
318int PerfDriver::writeCounters(mxml_node_t *root) const {
319 int count = 0;
320 for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
321 mxml_node_t *node = mxmlNewElement(root, "counter");
322 mxmlElementSetAttr(node, "name", counter->getName());
323 ++count;
324 }
325
326 return count;
327}
328
329bool PerfDriver::enable(PerfGroup *group, Buffer *const buffer) const {
330 for (PerfCounter * counter = mCounters; counter != NULL; counter = counter->getNext()) {
331 if (counter->isEnabled() && (counter->getType() != TYPE_DERIVED)) {
332 if (!group->add(buffer, counter->getKey(), counter->getType(), counter->getConfig(), counter->getCount(), 0, 0)) {
333 logg->logMessage("%s(%s:%i): PerfGroup::add failed", __FUNCTION__, __FILE__, __LINE__);
334 return false;
335 }
336 }
337 }
338
339 return true;
340}
341
342long long PerfDriver::getTracepointId(const char *const name, DynBuf *const printb) {
343 if (!printb->printf(EVENTS_PATH "/%s/id", name)) {
344 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
345 return -1;
346 }
347
348 int64_t result;
349 if (DriverSource::readInt64Driver(printb->getBuf(), &result) != 0) {
350 logg->logMessage("%s(%s:%i): DriverSource::readInt64Driver failed", __FUNCTION__, __FILE__, __LINE__);
351 return -1;
352 }
353
354 return result;
355}
diff --git a/daemon/PerfDriver.h b/daemon/PerfDriver.h
new file mode 100644
index 0000000..3181b74
--- /dev/null
+++ b/daemon/PerfDriver.h
@@ -0,0 +1,56 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERFDRIVER_H
10#define PERFDRIVER_H
11
12#include "Driver.h"
13
14// If debugfs is not mounted at /sys/kernel/debug, update DEBUGFS_PATH
15#define DEBUGFS_PATH "/sys/kernel/debug"
16#define EVENTS_PATH DEBUGFS_PATH "/tracing/events"
17
18#define SCHED_SWITCH "sched/sched_switch"
19
20class Buffer;
21class DynBuf;
22class PerfCounter;
23class PerfGroup;
24
25class PerfDriver : public Driver {
26public:
27 PerfDriver();
28 ~PerfDriver();
29
30 bool setup();
31 bool summary(Buffer *const buffer);
32 bool isSetup() const { return mIsSetup; }
33
34 bool claimCounter(const Counter &counter) const;
35 void resetCounters();
36 void setupCounter(Counter &counter);
37
38 int writeCounters(mxml_node_t *root) const;
39
40 bool enable(PerfGroup *group, Buffer *const buffer) const;
41
42 static long long getTracepointId(const char *const name, DynBuf *const printb);
43
44private:
45 PerfCounter *findCounter(const Counter &counter) const;
46 void addCpuCounters(const char *const counterName, const int type, const int numCounters);
47
48 PerfCounter *mCounters;
49 bool mIsSetup;
50
51 // Intentionally undefined
52 PerfDriver(const PerfDriver &);
53 PerfDriver &operator=(const PerfDriver &);
54};
55
56#endif // PERFDRIVER_H
diff --git a/daemon/PerfGroup.cpp b/daemon/PerfGroup.cpp
new file mode 100644
index 0000000..faf5fca
--- /dev/null
+++ b/daemon/PerfGroup.cpp
@@ -0,0 +1,206 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfGroup.h"
10
11#include <errno.h>
12#include <string.h>
13#include <sys/ioctl.h>
14#include <sys/syscall.h>
15#include <unistd.h>
16
17#include "Buffer.h"
18#include "Logging.h"
19#include "Monitor.h"
20#include "PerfBuffer.h"
21#include "SessionData.h"
22
23#define DEFAULT_PEA_ARGS(pea, additionalSampleType) \
24 pea.size = sizeof(pea); \
25 /* Emit time, read_format below, group leader id, and raw tracepoint info */ \
26 pea.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_READ | PERF_SAMPLE_IDENTIFIER | additionalSampleType; \
27 /* Emit emit value in group format */ \
28 pea.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP; \
29 /* start out disabled */ \
30 pea.disabled = 1; \
31 /* have a sampling interrupt happen when we cross the wakeup_watermark boundary */ \
32 pea.watermark = 1; \
33 /* Be conservative in flush size as only one buffer set is monitored */ \
34 pea.wakeup_watermark = 3 * BUF_SIZE / 4
35
36static int sys_perf_event_open(struct perf_event_attr *const attr, const pid_t pid, const int cpu, const int group_fd, const unsigned long flags) {
37 return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
38}
39
40PerfGroup::PerfGroup(PerfBuffer *const pb) : mPb(pb) {
41 memset(&mAttrs, 0, sizeof(mAttrs));
42 memset(&mKeys, -1, sizeof(mKeys));
43 memset(&mFds, -1, sizeof(mFds));
44}
45
46PerfGroup::~PerfGroup() {
47 for (int pos = ARRAY_LENGTH(mFds) - 1; pos >= 0; --pos) {
48 if (mFds[pos] >= 0) {
49 close(mFds[pos]);
50 }
51 }
52}
53
54bool PerfGroup::add(Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags) {
55 int i;
56 for (i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
57 if (mKeys[i] < 0) {
58 break;
59 }
60 }
61
62 if (i >= ARRAY_LENGTH(mKeys)) {
63 logg->logMessage("%s(%s:%i): Too many counters", __FUNCTION__, __FILE__, __LINE__);
64 return false;
65 }
66
67 DEFAULT_PEA_ARGS(mAttrs[i], sampleType);
68 mAttrs[i].type = type;
69 mAttrs[i].config = config;
70 mAttrs[i].sample_period = sample;
71 // always be on the CPU but only a group leader can be pinned
72 mAttrs[i].pinned = (i == 0 ? 1 : 0);
73 mAttrs[i].mmap = (flags & PERF_GROUP_MMAP ? 1 : 0);
74 mAttrs[i].comm = (flags & PERF_GROUP_COMM ? 1 : 0);
75 mAttrs[i].freq = (flags & PERF_GROUP_FREQ ? 1 : 0);
76 mAttrs[i].task = (flags & PERF_GROUP_TASK ? 1 : 0);
77 mAttrs[i].sample_id_all = (flags & PERF_GROUP_SAMPLE_ID_ALL ? 1 : 0);
78
79 mKeys[i] = key;
80
81 buffer->pea(&mAttrs[i], key);
82
83 return true;
84}
85
86bool PerfGroup::prepareCPU(const int cpu) {
87 logg->logMessage("%s(%s:%i): Onlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
88
89 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
90 if (mKeys[i] < 0) {
91 continue;
92 }
93
94 const int offset = i * gSessionData->mCores;
95 if (mFds[cpu + offset] >= 0) {
96 logg->logMessage("%s(%s:%i): cpu already online or not correctly cleaned up", __FUNCTION__, __FILE__, __LINE__);
97 return false;
98 }
99
100 logg->logMessage("%s(%s:%i): perf_event_open cpu: %i type: %lli config: %lli sample: %lli sample_type: %lli", __FUNCTION__, __FILE__, __LINE__, cpu, (long long)mAttrs[i].type, (long long)mAttrs[i].config, (long long)mAttrs[i].sample_period, (long long)mAttrs[i].sample_type);
101 mFds[cpu + offset] = sys_perf_event_open(&mAttrs[i], -1, cpu, i == 0 ? -1 : mFds[cpu], i == 0 ? 0 : PERF_FLAG_FD_OUTPUT);
102 if (mFds[cpu + offset] < 0) {
103 logg->logMessage("%s(%s:%i): failed %s", __FUNCTION__, __FILE__, __LINE__, strerror(errno));
104 continue;
105 }
106
107 if (!mPb->useFd(cpu, mFds[cpu + offset], mFds[cpu])) {
108 logg->logMessage("%s(%s:%i): PerfBuffer::useFd failed", __FUNCTION__, __FILE__, __LINE__);
109 return false;
110 }
111 }
112
113 return true;
114}
115
116int PerfGroup::onlineCPU(const int cpu, const bool start, Buffer *const buffer, Monitor *const monitor) {
117 __u64 ids[ARRAY_LENGTH(mKeys)];
118 int coreKeys[ARRAY_LENGTH(mKeys)];
119 int idCount = 0;
120
121 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
122 const int fd = mFds[cpu + i * gSessionData->mCores];
123 if (fd < 0) {
124 continue;
125 }
126
127 coreKeys[idCount] = mKeys[i];
128 if (ioctl(fd, PERF_EVENT_IOC_ID, &ids[idCount]) != 0) {
129 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
130 return false;
131 }
132 ++idCount;
133 }
134
135 if (!monitor->add(mFds[cpu])) {
136 logg->logMessage("%s(%s:%i): Monitor::add failed", __FUNCTION__, __FILE__, __LINE__);
137 return false;
138 }
139
140 buffer->keys(idCount, ids, coreKeys);
141
142 if (start) {
143 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
144 int offset = i * gSessionData->mCores + cpu;
145 if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_ENABLE) < 0) {
146 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
147 return false;
148 }
149 }
150 }
151
152 return idCount;
153}
154
155bool PerfGroup::offlineCPU(const int cpu) {
156 logg->logMessage("%s(%s:%i): Offlining cpu %i", __FUNCTION__, __FILE__, __LINE__, cpu);
157
158 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
159 int offset = i * gSessionData->mCores + cpu;
160 if (mFds[offset] >= 0 && ioctl(mFds[offset], PERF_EVENT_IOC_DISABLE) < 0) {
161 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
162 return false;
163 }
164 }
165
166 // Mark the buffer so that it will be released next time it's read
167 mPb->discard(cpu);
168
169 for (int i = 0; i < ARRAY_LENGTH(mKeys); ++i) {
170 if (mKeys[i] < 0) {
171 continue;
172 }
173
174 int offset = i * gSessionData->mCores + cpu;
175 if (mFds[offset] >= 0) {
176 close(mFds[offset]);
177 mFds[offset] = -1;
178 }
179 }
180
181 return true;
182}
183
184bool PerfGroup::start() {
185 for (int pos = 0; pos < ARRAY_LENGTH(mFds); ++pos) {
186 if (mFds[pos] >= 0 && ioctl(mFds[pos], PERF_EVENT_IOC_ENABLE) < 0) {
187 logg->logMessage("%s(%s:%i): ioctl failed", __FUNCTION__, __FILE__, __LINE__);
188 goto fail;
189 }
190 }
191
192 return true;
193
194 fail:
195 stop();
196
197 return false;
198}
199
200void PerfGroup::stop() {
201 for (int pos = ARRAY_LENGTH(mFds) - 1; pos >= 0; --pos) {
202 if (mFds[pos] >= 0) {
203 ioctl(mFds[pos], PERF_EVENT_IOC_DISABLE);
204 }
205 }
206}
diff --git a/daemon/PerfGroup.h b/daemon/PerfGroup.h
new file mode 100644
index 0000000..af496d4
--- /dev/null
+++ b/daemon/PerfGroup.h
@@ -0,0 +1,55 @@
1 /**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERF_GROUP
10#define PERF_GROUP
11
12// Use a snapshot of perf_event.h as it may be more recent than what is on the target and if not newer features won't be supported anyways
13#include "k/perf_event.h"
14
15#include "Config.h"
16
17class Buffer;
18class Monitor;
19class PerfBuffer;
20
21enum PerfGroupFlags {
22 PERF_GROUP_MMAP = 1 << 0,
23 PERF_GROUP_COMM = 1 << 1,
24 PERF_GROUP_FREQ = 1 << 2,
25 PERF_GROUP_TASK = 1 << 3,
26 PERF_GROUP_SAMPLE_ID_ALL = 1 << 4,
27};
28
29class PerfGroup {
30public:
31 PerfGroup(PerfBuffer *const pb);
32 ~PerfGroup();
33
34 bool add(Buffer *const buffer, const int key, const __u32 type, const __u64 config, const __u64 sample, const __u64 sampleType, const int flags);
35 // Safe to call concurrently
36 bool prepareCPU(const int cpu);
37 // Not safe to call concurrently. Returns the number of events enabled
38 int onlineCPU(const int cpu, const bool start, Buffer *const buffer, Monitor *const monitor);
39 bool offlineCPU(int cpu);
40 bool start();
41 void stop();
42
43private:
44 // +1 for the group leader
45 struct perf_event_attr mAttrs[MAX_PERFORMANCE_COUNTERS + 1];
46 int mKeys[MAX_PERFORMANCE_COUNTERS + 1];
47 int mFds[NR_CPUS * (MAX_PERFORMANCE_COUNTERS + 1)];
48 PerfBuffer *const mPb;
49
50 // Intentionally undefined
51 PerfGroup(const PerfGroup &);
52 PerfGroup &operator=(const PerfGroup &);
53};
54
55#endif // PERF_GROUP
diff --git a/daemon/PerfSource.cpp b/daemon/PerfSource.cpp
new file mode 100644
index 0000000..1f1cb19
--- /dev/null
+++ b/daemon/PerfSource.cpp
@@ -0,0 +1,271 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "PerfSource.h"
10
11#include <errno.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "Child.h"
16#include "DynBuf.h"
17#include "Logging.h"
18#include "PerfDriver.h"
19#include "Proc.h"
20#include "SessionData.h"
21
22#define MS_PER_US 1000000
23
24extern Child *child;
25
26static bool sendTracepointFormat(Buffer *const buffer, const char *const name, DynBuf *const printb, DynBuf *const b) {
27 if (!printb->printf(EVENTS_PATH "/%s/format", name)) {
28 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
29 return false;
30 }
31 if (!b->read(printb->getBuf())) {
32 logg->logMessage("%s(%s:%i): DynBuf::read failed", __FUNCTION__, __FILE__, __LINE__);
33 return false;
34 }
35 buffer->format(b->getLength(), b->getBuf());
36
37 return true;
38}
39
40PerfSource::PerfSource(sem_t *senderSem, sem_t *startProfile) : mSummary(0, FRAME_SUMMARY, 1024, senderSem), mBuffer(0, FRAME_PERF_ATTRS, 1024*1024, senderSem), mCountersBuf(), mCountersGroup(&mCountersBuf), mMonitor(), mUEvent(), mSenderSem(senderSem), mStartProfile(startProfile), mInterruptFd(-1), mIsDone(false) {
41 long l = sysconf(_SC_PAGE_SIZE);
42 if (l < 0) {
43 logg->logError(__FILE__, __LINE__, "Unable to obtain the page size");
44 handleException();
45 }
46 gSessionData->mPageSize = static_cast<int>(l);
47
48 l = sysconf(_SC_NPROCESSORS_CONF);
49 if (l < 0) {
50 logg->logError(__FILE__, __LINE__, "Unable to obtain the number of cores");
51 handleException();
52 }
53 gSessionData->mCores = static_cast<int>(l);
54}
55
56PerfSource::~PerfSource() {
57}
58
59struct PrepareParallelArgs {
60 PerfGroup *pg;
61 int cpu;
62};
63
64void *prepareParallel(void *arg) {
65 const PrepareParallelArgs *const args = (PrepareParallelArgs *)arg;
66 args->pg->prepareCPU(args->cpu);
67 return NULL;
68}
69
70bool PerfSource::prepare() {
71 DynBuf printb;
72 DynBuf b1;
73 DynBuf b2;
74 DynBuf b3;
75 long long schedSwitchId;
76
77 if (0
78 || !mMonitor.init()
79 || !mUEvent.init()
80 || !mMonitor.add(mUEvent.getFd())
81
82 || (schedSwitchId = PerfDriver::getTracepointId(SCHED_SWITCH, &printb)) < 0
83 || !sendTracepointFormat(&mBuffer, SCHED_SWITCH, &printb, &b1)
84
85 // Only want RAW but not IP on sched_switch and don't want TID on SAMPLE_ID
86 || !mCountersGroup.add(&mBuffer, 100/**/, PERF_TYPE_TRACEPOINT, schedSwitchId, 1, PERF_SAMPLE_RAW, PERF_GROUP_MMAP | PERF_GROUP_COMM | PERF_GROUP_TASK | PERF_GROUP_SAMPLE_ID_ALL)
87
88 // Only want TID and IP but not RAW on timer
89 || (gSessionData->mSampleRate > 0 && !gSessionData->mIsEBS && !mCountersGroup.add(&mBuffer, 99/**/, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK, 1000000000UL / gSessionData->mSampleRate, PERF_SAMPLE_TID | PERF_SAMPLE_IP, 0))
90
91 || !gSessionData->perf.enable(&mCountersGroup, &mBuffer)
92 || 0) {
93 logg->logMessage("%s(%s:%i): perf setup failed, are you running Linux 3.12 or later?", __FUNCTION__, __FILE__, __LINE__);
94 return false;
95 }
96
97 if (!gSessionData->perf.summary(&mSummary)) {
98 logg->logMessage("%s(%s:%i): PerfDriver::summary failed", __FUNCTION__, __FILE__, __LINE__);
99 return false;
100 }
101
102 {
103 // Run prepareCPU in parallel as perf_event_open can take more than 1 sec in some cases
104 pthread_t threads[NR_CPUS];
105 PrepareParallelArgs args[NR_CPUS];
106 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
107 args[cpu].pg = &mCountersGroup;
108 args[cpu].cpu = cpu;
109 if (pthread_create(&threads[cpu], NULL, prepareParallel, &args[cpu]) != 0) {
110 logg->logMessage("%s(%s:%i): pthread_create failed", __FUNCTION__, __FILE__, __LINE__);
111 return false;
112 }
113 }
114 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
115 if (pthread_join(threads[cpu], NULL) != 0) {
116 logg->logMessage("%s(%s:%i): pthread_join failed", __FUNCTION__, __FILE__, __LINE__);
117 return false;
118 }
119 }
120 }
121
122 int numEvents = 0;
123 for (int cpu = 0; cpu < gSessionData->mCores; ++cpu) {
124 numEvents += mCountersGroup.onlineCPU(cpu, false, &mBuffer, &mMonitor);
125 }
126 if (numEvents <= 0) {
127 logg->logMessage("%s(%s:%i): PerfGroup::onlineCPU failed on all cores", __FUNCTION__, __FILE__, __LINE__);
128 return false;
129 }
130
131 // Start events before reading proc to avoid race conditions
132 if (!mCountersGroup.start()) {
133 logg->logMessage("%s(%s:%i): PerfGroup::start failed", __FUNCTION__, __FILE__, __LINE__);
134 return false;
135 }
136
137 if (!readProc(&mBuffer, &printb, &b1, &b2, &b3)) {
138 logg->logMessage("%s(%s:%i): readProc failed", __FUNCTION__, __FILE__, __LINE__);
139 return false;
140 }
141
142 mBuffer.commit(1);
143
144 return true;
145}
146
147static const char CPU_DEVPATH[] = "/devices/system/cpu/cpu";
148
149void PerfSource::run() {
150 int pipefd[2];
151
152 if (pipe(pipefd) != 0) {
153 logg->logError(__FILE__, __LINE__, "pipe failed");
154 handleException();
155 }
156 mInterruptFd = pipefd[1];
157
158 if (!mMonitor.add(pipefd[0])) {
159 logg->logError(__FILE__, __LINE__, "Monitor::add failed");
160 handleException();
161 }
162
163 int timeout = -1;
164 if (gSessionData->mLiveRate > 0) {
165 timeout = gSessionData->mLiveRate/MS_PER_US;
166 }
167
168 sem_post(mStartProfile);
169
170 while (gSessionData->mSessionIsActive) {
171 // +1 for uevents, +1 for pipe
172 struct epoll_event events[NR_CPUS + 2];
173 int ready = mMonitor.wait(events, ARRAY_LENGTH(events), timeout);
174 if (ready < 0) {
175 logg->logError(__FILE__, __LINE__, "Monitor::wait failed");
176 handleException();
177 }
178
179 for (int i = 0; i < ready; ++i) {
180 if (events[i].data.fd == mUEvent.getFd()) {
181 if (!handleUEvent()) {
182 logg->logError(__FILE__, __LINE__, "PerfSource::handleUEvent failed");
183 handleException();
184 }
185 break;
186 }
187 }
188
189 // send a notification that data is ready
190 sem_post(mSenderSem);
191
192 // In one shot mode, stop collection once all the buffers are filled
193 // Assume timeout == 0 in this case
194 if (gSessionData->mOneShot && gSessionData->mSessionIsActive) {
195 logg->logMessage("%s(%s:%i): One shot", __FUNCTION__, __FILE__, __LINE__);
196 child->endSession();
197 }
198 }
199
200 mCountersGroup.stop();
201 mBuffer.setDone();
202 mIsDone = true;
203
204 // send a notification that data is ready
205 sem_post(mSenderSem);
206
207 mInterruptFd = -1;
208 close(pipefd[0]);
209 close(pipefd[1]);
210}
211
212bool PerfSource::handleUEvent() {
213 UEventResult result;
214 if (!mUEvent.read(&result)) {
215 logg->logMessage("%s(%s:%i): UEvent::Read failed", __FUNCTION__, __FILE__, __LINE__);
216 return false;
217 }
218
219 if (strcmp(result.mSubsystem, "cpu") == 0) {
220 if (strncmp(result.mDevPath, CPU_DEVPATH, sizeof(CPU_DEVPATH) - 1) != 0) {
221 logg->logMessage("%s(%s:%i): Unexpected cpu DEVPATH format", __FUNCTION__, __FILE__, __LINE__);
222 return false;
223 }
224 char *endptr;
225 errno = 0;
226 int cpu = strtol(result.mDevPath + sizeof(CPU_DEVPATH) - 1, &endptr, 10);
227 if (errno != 0 || *endptr != '\0') {
228 logg->logMessage("%s(%s:%i): strtol failed", __FUNCTION__, __FILE__, __LINE__);
229 return false;
230 }
231 if (strcmp(result.mAction, "online") == 0) {
232 // Only call onlineCPU if prepareCPU succeeded
233 const bool result = mCountersGroup.prepareCPU(cpu) &&
234 mCountersGroup.onlineCPU(cpu, true, &mBuffer, &mMonitor);
235 mBuffer.commit(1);
236 return result;
237 } else if (strcmp(result.mAction, "offline") == 0) {
238 return mCountersGroup.offlineCPU(cpu);
239 }
240 }
241
242 return true;
243}
244
245void PerfSource::interrupt() {
246 if (mInterruptFd >= 0) {
247 int8_t c = 0;
248 // Write to the pipe to wake the monitor which will cause mSessionIsActive to be reread
249 if (::write(mInterruptFd, &c, sizeof(c)) != sizeof(c)) {
250 logg->logError(__FILE__, __LINE__, "write failed");
251 handleException();
252 }
253 }
254}
255
256bool PerfSource::isDone () {
257 return mBuffer.isDone() && mIsDone && mCountersBuf.isEmpty();
258}
259
260void PerfSource::write (Sender *sender) {
261 if (!mSummary.isDone()) {
262 mSummary.write(sender);
263 }
264 if (!mBuffer.isDone()) {
265 mBuffer.write(sender);
266 }
267 if (!mCountersBuf.send(sender)) {
268 logg->logError(__FILE__, __LINE__, "PerfBuffer::send failed");
269 handleException();
270 }
271}
diff --git a/daemon/PerfSource.h b/daemon/PerfSource.h
new file mode 100644
index 0000000..3f471c8
--- /dev/null
+++ b/daemon/PerfSource.h
@@ -0,0 +1,54 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PERFSOURCE_H
10#define PERFSOURCE_H
11
12#include <semaphore.h>
13
14#include "Buffer.h"
15#include "Monitor.h"
16#include "PerfBuffer.h"
17#include "PerfGroup.h"
18#include "Source.h"
19#include "UEvent.h"
20
21class Sender;
22
23class PerfSource : public Source {
24public:
25 PerfSource(sem_t *senderSem, sem_t *startProfile);
26 ~PerfSource();
27
28 bool prepare();
29 void run();
30 void interrupt();
31
32 bool isDone();
33 void write(Sender *sender);
34
35private:
36 bool handleUEvent();
37
38 Buffer mSummary;
39 Buffer mBuffer;
40 PerfBuffer mCountersBuf;
41 PerfGroup mCountersGroup;
42 Monitor mMonitor;
43 UEvent mUEvent;
44 sem_t *const mSenderSem;
45 sem_t *const mStartProfile;
46 int mInterruptFd;
47 bool mIsDone;
48
49 // Intentionally undefined
50 PerfSource(const PerfSource &);
51 PerfSource &operator=(const PerfSource &);
52};
53
54#endif // PERFSOURCE_H
diff --git a/daemon/Proc.cpp b/daemon/Proc.cpp
new file mode 100644
index 0000000..e0b9e22
--- /dev/null
+++ b/daemon/Proc.cpp
@@ -0,0 +1,179 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Proc.h"
10
11#include <dirent.h>
12#include <errno.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include "Buffer.h"
18#include "DynBuf.h"
19#include "Logging.h"
20
21struct ProcStat {
22 // From linux-dev/include/linux/sched.h
23#define TASK_COMM_LEN 16
24 // TASK_COMM_LEN may grow, so be ready for it to get larger
25 char comm[2*TASK_COMM_LEN];
26 long numThreads;
27};
28
29static bool readProcStat(ProcStat *const ps, const char *const pathname, DynBuf *const b) {
30 if (!b->read(pathname)) {
31 logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the thread exited", __FUNCTION__, __FILE__, __LINE__);
32 // This is not a fatal error - the thread just doesn't exist any more
33 return true;
34 }
35
36 char *comm = strchr(b->getBuf(), '(');
37 if (comm == NULL) {
38 logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
39 return false;
40 }
41 ++comm;
42 char *const str = strrchr(comm, ')');
43 if (str == NULL) {
44 logg->logMessage("%s(%s:%i): parsing stat failed", __FUNCTION__, __FILE__, __LINE__);
45 return false;
46 }
47 *str = '\0';
48 strncpy(ps->comm, comm, sizeof(ps->comm) - 1);
49 ps->comm[sizeof(ps->comm) - 1] = '\0';
50
51 const int count = sscanf(str + 2, " %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %ld", &ps->numThreads);
52 if (count != 1) {
53 logg->logMessage("%s(%s:%i): sscanf failed", __FUNCTION__, __FILE__, __LINE__);
54 return false;
55 }
56
57 return true;
58}
59
60static bool readProcTask(Buffer *const buffer, const int pid, const char *const image, DynBuf *const printb, DynBuf *const b) {
61 bool result = false;
62
63 if (!b->printf("/proc/%i/task", pid)) {
64 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
65 return result;
66 }
67 DIR *task = opendir(b->getBuf());
68 if (task == NULL) {
69 logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
70 return result;
71 }
72
73 struct dirent *dirent;
74 while ((dirent = readdir(task)) != NULL) {
75 char *endptr;
76 const int tid = strtol(dirent->d_name, &endptr, 10);
77 if (*endptr != '\0') {
78 // Ignore task items that are not integers like ., etc...
79 continue;
80 }
81
82 if (!printb->printf("/proc/%i/task/%i/stat", pid, tid)) {
83 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
84 goto fail;
85 }
86 ProcStat ps;
87 if (!readProcStat(&ps, printb->getBuf(), b)) {
88 logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
89 goto fail;
90 }
91
92 buffer->comm(pid, tid, image, ps.comm);
93 }
94
95 result = true;
96
97 fail:
98 closedir(task);
99
100 return result;
101}
102
103bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3) {
104 bool result = false;
105
106 DIR *proc = opendir("/proc");
107 if (proc == NULL) {
108 logg->logMessage("%s(%s:%i): opendir failed", __FUNCTION__, __FILE__, __LINE__);
109 return result;
110 }
111
112 struct dirent *dirent;
113 while ((dirent = readdir(proc)) != NULL) {
114 char *endptr;
115 const int pid = strtol(dirent->d_name, &endptr, 10);
116 if (*endptr != '\0') {
117 // Ignore proc items that are not integers like ., cpuinfo, etc...
118 continue;
119 }
120
121 if (!printb->printf("/proc/%i/stat", pid)) {
122 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
123 goto fail;
124 }
125 ProcStat ps;
126 if (!readProcStat(&ps, printb->getBuf(), b1)) {
127 logg->logMessage("%s(%s:%i): readProcStat failed", __FUNCTION__, __FILE__, __LINE__);
128 goto fail;
129 }
130
131 if (!printb->printf("/proc/%i/exe", pid)) {
132 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
133 goto fail;
134 }
135 const int err = b1->readlink(printb->getBuf());
136 const char *image;
137 if (err == 0) {
138 image = strrchr(b1->getBuf(), '/');
139 if (image == NULL) {
140 image = b1->getBuf();
141 } else {
142 ++image;
143 }
144 } else if (err == -ENOENT) {
145 // readlink /proc/[pid]/exe returns ENOENT for kernel threads
146 image = "\0";
147 } else {
148 logg->logMessage("%s(%s:%i): DynBuf::readlink failed", __FUNCTION__, __FILE__, __LINE__);
149 goto fail;
150 }
151
152 if (!printb->printf("/proc/%i/maps", pid)) {
153 logg->logMessage("%s(%s:%i): DynBuf::printf failed", __FUNCTION__, __FILE__, __LINE__);
154 goto fail;
155 }
156 if (!b2->read(printb->getBuf())) {
157 logg->logMessage("%s(%s:%i): DynBuf::read failed, likely because the process exited", __FUNCTION__, __FILE__, __LINE__);
158 // This is not a fatal error - the process just doesn't exist any more
159 continue;
160 }
161
162 buffer->maps(pid, pid, b2->getBuf());
163 if (ps.numThreads <= 1) {
164 buffer->comm(pid, pid, image, ps.comm);
165 } else {
166 if (!readProcTask(buffer, pid, image, printb, b3)) {
167 logg->logMessage("%s(%s:%i): readProcTask failed", __FUNCTION__, __FILE__, __LINE__);
168 goto fail;
169 }
170 }
171 }
172
173 result = true;
174
175 fail:
176 closedir(proc);
177
178 return result;
179}
diff --git a/daemon/Proc.h b/daemon/Proc.h
new file mode 100644
index 0000000..057b610
--- /dev/null
+++ b/daemon/Proc.h
@@ -0,0 +1,17 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef PROC_H
10#define PROC_H
11
12class Buffer;
13class DynBuf;
14
15bool readProc(Buffer *const buffer, DynBuf *const printb, DynBuf *const b1, DynBuf *const b2, DynBuf *const b3);
16
17#endif // PROC_H
diff --git a/daemon/Sender.cpp b/daemon/Sender.cpp
index 8eb348f..3a981a6 100644
--- a/daemon/Sender.cpp
+++ b/daemon/Sender.cpp
@@ -1,19 +1,18 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <string.h> 9#include "Sender.h"
10#include <sys/socket.h> 10
11#include <netinet/in.h>
12#include <sys/types.h>
13#include <arpa/inet.h>
14#include <stdlib.h> 11#include <stdlib.h>
12#include <string.h>
15#include <unistd.h> 13#include <unistd.h>
16#include "Sender.h" 14
15#include "Buffer.h"
17#include "Logging.h" 16#include "Logging.h"
18#include "OlySocket.h" 17#include "OlySocket.h"
19#include "SessionData.h" 18#include "SessionData.h"
@@ -49,9 +48,12 @@ Sender::Sender(OlySocket* socket) {
49} 48}
50 49
51Sender::~Sender() { 50Sender::~Sender() {
52 delete mDataSocket; 51 // Just close it as the client socket is on the stack
53 mDataSocket = NULL; 52 if (mDataSocket != NULL) {
54 if (mDataFile) { 53 mDataSocket->closeSocket();
54 mDataSocket = NULL;
55 }
56 if (mDataFile != NULL) {
55 fclose(mDataFile); 57 fclose(mDataFile);
56 } 58 }
57} 59}
@@ -95,10 +97,7 @@ void Sender::writeData(const char* data, int length, int type) {
95 // type and length already added by the Collector for apc data 97 // type and length already added by the Collector for apc data
96 unsigned char header[5]; 98 unsigned char header[5];
97 header[0] = type; 99 header[0] = type;
98 header[1] = (length >> 0) & 0xff; 100 Buffer::writeLEInt(header + 1, length);
99 header[2] = (length >> 8) & 0xff;
100 header[3] = (length >> 16) & 0xff;
101 header[4] = (length >> 24) & 0xff;
102 mDataSocket->send((char*)&header, sizeof(header)); 101 mDataSocket->send((char*)&header, sizeof(header));
103 } 102 }
104 103
@@ -106,7 +105,7 @@ void Sender::writeData(const char* data, int length, int type) {
106 const int chunkSize = 100*1000 * alarmDuration / 8; 105 const int chunkSize = 100*1000 * alarmDuration / 8;
107 int pos = 0; 106 int pos = 0;
108 while (true) { 107 while (true) {
109 mDataSocket->send((char*)data + pos, min(length - pos, chunkSize)); 108 mDataSocket->send((const char*)data + pos, min(length - pos, chunkSize));
110 pos += chunkSize; 109 pos += chunkSize;
111 if (pos >= length) { 110 if (pos >= length) {
112 break; 111 break;
diff --git a/daemon/Sender.h b/daemon/Sender.h
index b388f03..4c359db 100644
--- a/daemon/Sender.h
+++ b/daemon/Sender.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/SessionData.cpp b/daemon/SessionData.cpp
index cf84407..c169299 100644
--- a/daemon/SessionData.cpp
+++ b/daemon/SessionData.cpp
@@ -1,13 +1,15 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <string.h>
10#include "SessionData.h" 9#include "SessionData.h"
10
11#include <string.h>
12
11#include "SessionXML.h" 13#include "SessionXML.h"
12#include "Logging.h" 14#include "Logging.h"
13 15
@@ -38,6 +40,7 @@ void SessionData::initialize() {
38 mTotalBufferSize = 0; 40 mTotalBufferSize = 0;
39 // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module 41 // sysconf(_SC_NPROCESSORS_CONF) is unreliable on 2.6 Android, get the value from the kernel module
40 mCores = 1; 42 mCores = 1;
43 mPageSize = 0;
41} 44}
42 45
43void SessionData::parseSessionXML(char* xmlString) { 46void SessionData::parseSessionXML(char* xmlString) {
@@ -88,7 +91,8 @@ void SessionData::parseSessionXML(char* xmlString) {
88void SessionData::readCpuInfo() { 91void SessionData::readCpuInfo() {
89 char temp[256]; // arbitrarily large amount 92 char temp[256]; // arbitrarily large amount
90 strcpy(mCoreName, "unknown"); 93 strcpy(mCoreName, "unknown");
91 mCpuId = -1; 94 memset(&mCpuIds, -1, sizeof(mCpuIds));
95 mMaxCpuId = -1;
92 96
93 FILE* f = fopen("/proc/cpuinfo", "r"); 97 FILE* f = fopen("/proc/cpuinfo", "r");
94 if (f == NULL) { 98 if (f == NULL) {
@@ -98,15 +102,16 @@ void SessionData::readCpuInfo() {
98 } 102 }
99 103
100 bool foundCoreName = false; 104 bool foundCoreName = false;
101 bool foundCpuId = false; 105 int processor = 0;
102 while (fgets(temp, sizeof(temp), f) && (!foundCoreName || !foundCpuId)) { 106 while (fgets(temp, sizeof(temp), f)) {
103 if (strlen(temp) > 0) { 107 if (strlen(temp) > 0) {
104 temp[strlen(temp) - 1] = 0; // Replace the line feed with a null 108 temp[strlen(temp) - 1] = 0; // Replace the line feed with a null
105 } 109 }
106 110
107 const bool foundHardware = strstr(temp, "Hardware") != 0; 111 const bool foundHardware = strstr(temp, "Hardware") != 0;
108 const bool foundCPUPart = strstr(temp, "CPU part") != 0; 112 const bool foundCPUPart = strstr(temp, "CPU part") != 0;
109 if (foundHardware || foundCPUPart) { 113 const bool foundProcessor = strstr(temp, "processor") != 0;
114 if (foundHardware || foundCPUPart || foundProcessor) {
110 char* position = strchr(temp, ':'); 115 char* position = strchr(temp, ':');
111 if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) { 116 if (position == NULL || (unsigned int)(position - temp) + 2 >= strlen(temp)) {
112 logg->logMessage("Unknown format of /proc/cpuinfo\n" 117 logg->logMessage("Unknown format of /proc/cpuinfo\n"
@@ -122,11 +127,15 @@ void SessionData::readCpuInfo() {
122 } 127 }
123 128
124 if (foundCPUPart) { 129 if (foundCPUPart) {
125 int cpuId = strtol(position, NULL, 16); 130 mCpuIds[processor] = strtol(position, NULL, 0);
126 if (cpuId > mCpuId) { 131 // If this does not have the full topology in /proc/cpuinfo, mCpuIds[0] may not have the 1 CPU part emitted - this guarantees it's in mMaxCpuId
127 mCpuId = cpuId; 132 if (mCpuIds[processor] > mMaxCpuId) {
133 mMaxCpuId = mCpuIds[processor];
128 } 134 }
129 foundCpuId = true; 135 }
136
137 if (foundProcessor) {
138 processor = strtol(position, NULL, 0);
130 } 139 }
131 } 140 }
132 } 141 }
diff --git a/daemon/SessionData.h b/daemon/SessionData.h
index c834251..ea34240 100644
--- a/daemon/SessionData.h
+++ b/daemon/SessionData.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -11,12 +11,12 @@
11 11
12#include <stdint.h> 12#include <stdint.h>
13 13
14#include "Config.h"
14#include "Counter.h" 15#include "Counter.h"
15#include "Hwmon.h" 16#include "Hwmon.h"
17#include "PerfDriver.h"
16 18
17#define MAX_PERFORMANCE_COUNTERS 50 19#define PROTOCOL_VERSION 18
18
19#define PROTOCOL_VERSION 17
20#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions 20#define PROTOCOL_DEV 1000 // Differentiates development versions (timestamp) from release versions
21 21
22struct ImageLinkList { 22struct ImageLinkList {
@@ -34,6 +34,7 @@ public:
34 void parseSessionXML(char* xmlString); 34 void parseSessionXML(char* xmlString);
35 35
36 Hwmon hwmon; 36 Hwmon hwmon;
37 PerfDriver perf;
37 38
38 char mCoreName[MAX_STRING_LEN]; 39 char mCoreName[MAX_STRING_LEN];
39 struct ImageLinkList *mImages; 40 struct ImageLinkList *mImages;
@@ -47,6 +48,7 @@ public:
47 bool mSessionIsActive; 48 bool mSessionIsActive;
48 bool mLocalCapture; 49 bool mLocalCapture;
49 bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled 50 bool mOneShot; // halt processing of the driver data until profiling is complete or the buffer is filled
51 bool mIsEBS;
50 52
51 int mBacktraceDepth; 53 int mBacktraceDepth;
52 int mTotalBufferSize; // number of MB to use for the entire collection buffer 54 int mTotalBufferSize; // number of MB to use for the entire collection buffer
@@ -54,7 +56,9 @@ public:
54 int64_t mLiveRate; 56 int64_t mLiveRate;
55 int mDuration; 57 int mDuration;
56 int mCores; 58 int mCores;
57 int mCpuId; 59 int mPageSize;
60 int mCpuIds[NR_CPUS];
61 int mMaxCpuId;
58 62
59 // PMU Counters 63 // PMU Counters
60 int mCounterOverflow; 64 int mCounterOverflow;
diff --git a/daemon/SessionXML.cpp b/daemon/SessionXML.cpp
index 0a0a027..55b2f92 100644
--- a/daemon/SessionXML.cpp
+++ b/daemon/SessionXML.cpp
@@ -1,15 +1,17 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include "SessionXML.h"
10
9#include <string.h> 11#include <string.h>
10#include <stdlib.h> 12#include <stdlib.h>
11#include <limits.h> 13#include <limits.h>
12#include "SessionXML.h" 14
13#include "Logging.h" 15#include "Logging.h"
14#include "OlyUtility.h" 16#include "OlyUtility.h"
15#include "SessionData.h" 17#include "SessionData.h"
@@ -25,7 +27,7 @@ static const char* ATTR_DURATION = "duration";
25static const char* ATTR_PATH = "path"; 27static const char* ATTR_PATH = "path";
26static const char* ATTR_LIVE_RATE = "live_rate"; 28static const char* ATTR_LIVE_RATE = "live_rate";
27 29
28SessionXML::SessionXML(const char* str) { 30SessionXML::SessionXML(const char *str) {
29 parameters.buffer_mode[0] = 0; 31 parameters.buffer_mode[0] = 0;
30 parameters.sample_rate[0] = 0; 32 parameters.sample_rate[0] = 0;
31 parameters.duration = 0; 33 parameters.duration = 0;
@@ -33,13 +35,13 @@ SessionXML::SessionXML(const char* str) {
33 parameters.live_rate = 0; 35 parameters.live_rate = 0;
34 parameters.images = NULL; 36 parameters.images = NULL;
35 mPath = 0; 37 mPath = 0;
36 mSessionXML = (char*)str; 38 mSessionXML = (const char *)str;
37 logg->logMessage(mSessionXML); 39 logg->logMessage(mSessionXML);
38} 40}
39 41
40SessionXML::~SessionXML() { 42SessionXML::~SessionXML() {
41 if (mPath != 0) { 43 if (mPath != 0) {
42 free(mSessionXML); 44 free((char *)mSessionXML);
43 } 45 }
44} 46}
45 47
diff --git a/daemon/SessionXML.h b/daemon/SessionXML.h
index 0fb03bd..e146094 100644
--- a/daemon/SessionXML.h
+++ b/daemon/SessionXML.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -24,13 +24,13 @@ struct ConfigParameters {
24 24
25class SessionXML { 25class SessionXML {
26public: 26public:
27 SessionXML(const char* str); 27 SessionXML(const char *str);
28 ~SessionXML(); 28 ~SessionXML();
29 void parse(); 29 void parse();
30 ConfigParameters parameters; 30 ConfigParameters parameters;
31private: 31private:
32 char* mSessionXML; 32 const char *mSessionXML;
33 char* mPath; 33 const char *mPath;
34 void sessionTag(mxml_node_t *tree, mxml_node_t *node); 34 void sessionTag(mxml_node_t *tree, mxml_node_t *node);
35 void sessionImage(mxml_node_t *node); 35 void sessionImage(mxml_node_t *node);
36 36
diff --git a/daemon/Source.cpp b/daemon/Source.cpp
new file mode 100644
index 0000000..60cf704
--- /dev/null
+++ b/daemon/Source.cpp
@@ -0,0 +1,33 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Source.h"
10
11#include "Logging.h"
12
13Source::Source() : mThreadID() {
14}
15
16Source::~Source() {
17}
18
19void Source::start() {
20 if (pthread_create(&mThreadID, NULL, runStatic, this)) {
21 logg->logError(__FILE__, __LINE__, "Failed to create source thread");
22 handleException();
23 }
24}
25
26void Source::join() {
27 pthread_join(mThreadID, NULL);
28}
29
30void *Source::runStatic(void *arg) {
31 static_cast<Source *>(arg)->run();
32 return NULL;
33}
diff --git a/daemon/Source.h b/daemon/Source.h
new file mode 100644
index 0000000..56ac3d6
--- /dev/null
+++ b/daemon/Source.h
@@ -0,0 +1,40 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef SOURCE_H
10#define SOURCE_H
11
12#include <pthread.h>
13
14class Sender;
15
16class Source {
17public:
18 Source();
19 virtual ~Source();
20
21 virtual bool prepare() = 0;
22 void start();
23 virtual void run() = 0;
24 virtual void interrupt() = 0;
25 void join();
26
27 virtual bool isDone() = 0;
28 virtual void write(Sender *sender) = 0;
29
30private:
31 static void *runStatic(void *arg);
32
33 pthread_t mThreadID;
34
35 // Intentionally undefined
36 Source(const Source &);
37 Source &operator=(const Source &);
38};
39
40#endif // SOURCE_H
diff --git a/daemon/StreamlineSetup.cpp b/daemon/StreamlineSetup.cpp
index 2faada2..caa665e 100644
--- a/daemon/StreamlineSetup.cpp
+++ b/daemon/StreamlineSetup.cpp
@@ -1,26 +1,23 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2011-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2011-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <string.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include <arpa/inet.h>
13#include <sys/socket.h>
14#include <netinet/in.h>
15#include "Sender.h"
16#include "Logging.h"
17#include "OlyUtility.h"
18#include "SessionData.h"
19#include "CapturedXML.h"
20#include "StreamlineSetup.h" 9#include "StreamlineSetup.h"
10
11#include "Buffer.h"
12#include "CapturedXML.h"
21#include "ConfigurationXML.h" 13#include "ConfigurationXML.h"
22#include "Driver.h" 14#include "Driver.h"
23#include "EventsXML.h" 15#include "EventsXML.h"
16#include "Logging.h"
17#include "OlySocket.h"
18#include "OlyUtility.h"
19#include "Sender.h"
20#include "SessionData.h"
24 21
25static const char* TAG_SESSION = "session"; 22static const char* TAG_SESSION = "session";
26static const char* TAG_REQUEST = "request"; 23static const char* TAG_REQUEST = "request";
@@ -198,12 +195,9 @@ void StreamlineSetup::handleDeliver(char* xml) {
198void StreamlineSetup::sendData(const char* data, uint32_t length, char type) { 195void StreamlineSetup::sendData(const char* data, uint32_t length, char type) {
199 unsigned char header[5]; 196 unsigned char header[5];
200 header[0] = type; 197 header[0] = type;
201 header[1] = (length >> 0) & 0xff; 198 Buffer::writeLEInt(header + 1, length);
202 header[2] = (length >> 8) & 0xff;
203 header[3] = (length >> 16) & 0xff;
204 header[4] = (length >> 24) & 0xff;
205 mSocket->send((char*)&header, sizeof(header)); 199 mSocket->send((char*)&header, sizeof(header));
206 mSocket->send((char*)data, length); 200 mSocket->send((const char*)data, length);
207} 201}
208 202
209void StreamlineSetup::sendEvents() { 203void StreamlineSetup::sendEvents() {
@@ -241,8 +235,14 @@ void StreamlineSetup::sendCounters() {
241 235
242 xml = mxmlNewXML("1.0"); 236 xml = mxmlNewXML("1.0");
243 counters = mxmlNewElement(xml, "counters"); 237 counters = mxmlNewElement(xml, "counters");
238 int count = 0;
244 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) { 239 for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
245 driver->writeCounters(counters); 240 count += driver->writeCounters(counters);
241 }
242
243 if (count == 0) {
244 logg->logError(__FILE__, __LINE__, "No counters found, this could be because /dev/gator/events can not be read or because perf is not working correctly");
245 handleException();
246 } 246 }
247 247
248 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB); 248 char* string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
diff --git a/daemon/StreamlineSetup.h b/daemon/StreamlineSetup.h
index d6d9a6e..74bb197 100644
--- a/daemon/StreamlineSetup.h
+++ b/daemon/StreamlineSetup.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -9,7 +9,10 @@
9#ifndef __STREAMLINE_SETUP_H__ 9#ifndef __STREAMLINE_SETUP_H__
10#define __STREAMLINE_SETUP_H__ 10#define __STREAMLINE_SETUP_H__
11 11
12#include "OlySocket.h" 12#include <stdint.h>
13#include <string.h>
14
15class OlySocket;
13 16
14// Commands from Streamline 17// Commands from Streamline
15enum { 18enum {
diff --git a/daemon/UEvent.cpp b/daemon/UEvent.cpp
new file mode 100644
index 0000000..282e965
--- /dev/null
+++ b/daemon/UEvent.cpp
@@ -0,0 +1,75 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "UEvent.h"
10
11#include <linux/netlink.h>
12#include <string.h>
13#include <sys/socket.h>
14#include <unistd.h>
15
16#include "Logging.h"
17
18static const char EMPTY[] = "";
19static const char ACTION[] = "ACTION=";
20static const char DEVPATH[] = "DEVPATH=";
21static const char SUBSYSTEM[] = "SUBSYSTEM=";
22
23UEvent::UEvent() : mFd(-1) {
24}
25
26UEvent::~UEvent() {
27 if (mFd >= 0) {
28 close(mFd);
29 }
30}
31
32bool UEvent::init() {
33 mFd = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
34 if (mFd < 0) {
35 logg->logMessage("%s(%s:%i): socket failed", __FUNCTION__, __FILE__, __LINE__);
36 return false;
37 }
38
39 struct sockaddr_nl sockaddr;
40 memset(&sockaddr, 0, sizeof(sockaddr));
41 sockaddr.nl_family = AF_NETLINK;
42 sockaddr.nl_groups = 1; // bitmask: (1 << 0) == kernel events, (1 << 1) == udev events
43 sockaddr.nl_pid = 0;
44 if (bind(mFd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0) {
45 logg->logMessage("%s(%s:%i): bind failed", __FUNCTION__, __FILE__, __LINE__);
46 return false;
47 }
48
49 return true;
50}
51
52bool UEvent::read(UEventResult *const result) {
53 ssize_t bytes = recv(mFd, result->mBuf, sizeof(result->mBuf), 0);
54 if (bytes <= 0) {
55 logg->logMessage("%s(%s:%i): recv failed", __FUNCTION__, __FILE__, __LINE__);
56 return false;
57 }
58
59 result->mAction = EMPTY;
60 result->mDevPath = EMPTY;
61 result->mSubsystem = EMPTY;
62
63 for (int pos = 0; pos < bytes; pos += strlen(result->mBuf + pos) + 1) {
64 char *const str = result->mBuf + pos;
65 if (strncmp(str, ACTION, sizeof(ACTION) - 1) == 0) {
66 result->mAction = str + sizeof(ACTION) - 1;
67 } else if (strncmp(str, DEVPATH, sizeof(DEVPATH) - 1) == 0) {
68 result->mDevPath = str + sizeof(DEVPATH) - 1;
69 } else if (strncmp(str, SUBSYSTEM, sizeof(SUBSYSTEM) - 1) == 0) {
70 result->mSubsystem = str + sizeof(SUBSYSTEM) - 1;
71 }
72 }
73
74 return true;
75}
diff --git a/daemon/UEvent.h b/daemon/UEvent.h
new file mode 100644
index 0000000..2f7ef2c
--- /dev/null
+++ b/daemon/UEvent.h
@@ -0,0 +1,36 @@
1/**
2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef UEVENT_H
10#define UEVENT_H
11
12struct UEventResult {
13 const char *mAction;
14 const char *mDevPath;
15 const char *mSubsystem;
16 char mBuf[1<<13];
17};
18
19class UEvent {
20public:
21 UEvent();
22 ~UEvent();
23
24 bool init();
25 bool read(UEventResult *const result);
26 int getFd() const { return mFd; }
27
28private:
29 int mFd;
30
31 // Intentionally undefined
32 UEvent(const UEvent &);
33 UEvent &operator=(const UEvent &);
34};
35
36#endif // UEVENT_H
diff --git a/daemon/UserSpaceSource.cpp b/daemon/UserSpaceSource.cpp
new file mode 100644
index 0000000..debe696
--- /dev/null
+++ b/daemon/UserSpaceSource.cpp
@@ -0,0 +1,97 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "UserSpaceSource.h"
10
11#include <sys/prctl.h>
12#include <unistd.h>
13
14#include "Child.h"
15#include "DriverSource.h"
16#include "Logging.h"
17#include "SessionData.h"
18
19#define NS_PER_S ((uint64_t)1000000000)
20#define NS_PER_US 1000
21
22extern Child *child;
23
24UserSpaceSource::UserSpaceSource(sem_t *senderSem) : mBuffer(0, FRAME_BLOCK_COUNTER, gSessionData->mTotalBufferSize*1024*1024, senderSem) {
25}
26
27UserSpaceSource::~UserSpaceSource() {
28}
29
30bool UserSpaceSource::prepare() {
31 return true;
32}
33
34void UserSpaceSource::run() {
35 prctl(PR_SET_NAME, (unsigned long)&"gatord-counters", 0, 0, 0);
36
37 gSessionData->hwmon.start();
38
39 int64_t monotonic_started = 0;
40 while (monotonic_started <= 0) {
41 usleep(10);
42
43 if (DriverSource::readInt64Driver("/dev/gator/started", &monotonic_started) == -1) {
44 logg->logError(__FILE__, __LINE__, "Error reading gator driver start time");
45 handleException();
46 }
47 }
48
49 uint64_t next_time = 0;
50 while (gSessionData->mSessionIsActive) {
51 struct timespec ts;
52#ifndef CLOCK_MONOTONIC_RAW
53 // Android doesn't have this defined but it was added in Linux 2.6.28
54#define CLOCK_MONOTONIC_RAW 4
55#endif
56 if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) != 0) {
57 logg->logError(__FILE__, __LINE__, "Failed to get uptime");
58 handleException();
59 }
60 const uint64_t curr_time = (NS_PER_S*ts.tv_sec + ts.tv_nsec) - monotonic_started;
61 // Sample ten times a second ignoring gSessionData->mSampleRate
62 next_time += NS_PER_S/10;//gSessionData->mSampleRate;
63 if (next_time < curr_time) {
64 logg->logMessage("Too slow, curr_time: %lli next_time: %lli", curr_time, next_time);
65 next_time = curr_time;
66 }
67
68 if (mBuffer.eventHeader(curr_time)) {
69 gSessionData->hwmon.read(&mBuffer);
70 // Only check after writing all counters so that time and corresponding counters appear in the same frame
71 mBuffer.check(curr_time);
72 }
73
74 if (mBuffer.bytesAvailable() <= 0) {
75 logg->logMessage("One shot (counters)");
76 child->endSession();
77 }
78
79 usleep((next_time - curr_time)/NS_PER_US);
80 }
81
82 mBuffer.setDone();
83}
84
85void UserSpaceSource::interrupt() {
86 // Do nothing
87}
88
89bool UserSpaceSource::isDone() {
90 return mBuffer.isDone();
91}
92
93void UserSpaceSource::write(Sender *sender) {
94 if (!mBuffer.isDone()) {
95 mBuffer.write(sender);
96 }
97}
diff --git a/daemon/UserSpaceSource.h b/daemon/UserSpaceSource.h
new file mode 100644
index 0000000..fb5889d
--- /dev/null
+++ b/daemon/UserSpaceSource.h
@@ -0,0 +1,38 @@
1/**
2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef USERSPACESOURCE_H
10#define USERSPACESOURCE_H
11
12#include <semaphore.h>
13
14#include "Buffer.h"
15#include "Source.h"
16
17// User space counters - currently just hwmon
18class UserSpaceSource : public Source {
19public:
20 UserSpaceSource(sem_t *senderSem);
21 ~UserSpaceSource();
22
23 bool prepare();
24 void run();
25 void interrupt();
26
27 bool isDone();
28 void write(Sender *sender);
29
30private:
31 Buffer mBuffer;
32
33 // Intentionally unimplemented
34 UserSpaceSource(const UserSpaceSource &);
35 UserSpaceSource &operator=(const UserSpaceSource &);
36};
37
38#endif // USERSPACESOURCE_H
diff --git a/daemon/common.mk b/daemon/common.mk
index 031d169..d9dc146 100644
--- a/daemon/common.mk
+++ b/daemon/common.mk
@@ -25,7 +25,7 @@ include $(wildcard *.d)
25include $(wildcard mxml/*.d) 25include $(wildcard mxml/*.d)
26 26
27EventsXML.cpp: events_xml.h 27EventsXML.cpp: events_xml.h
28ConfigurationXML.cpp: configuration_xml.h 28ConfigurationXML.cpp: defaults_xml.h
29 29
30# Don't regenerate conf-lex.c or conf-parse.c 30# Don't regenerate conf-lex.c or conf-parse.c
31libsensors/conf-lex.c: ; 31libsensors/conf-lex.c: ;
@@ -47,4 +47,4 @@ escape: escape.c
47 gcc $^ -o $@ 47 gcc $^ -o $@
48 48
49clean: 49clean:
50 rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h configuration_xml.h 50 rm -f *.d *.o mxml/*.d mxml/*.o libsensors/*.d libsensors/*.o $(TARGET) escape events.xml events_xml.h defaults_xml.h
diff --git a/daemon/configuration.xml b/daemon/defaults.xml
index b44c00a..5bf096c 100644
--- a/daemon/configuration.xml
+++ b/daemon/defaults.xml
@@ -6,29 +6,34 @@
6 <configuration counter="ARM_ARM11MPCore_ccnt" event="0xff"/> 6 <configuration counter="ARM_ARM11MPCore_ccnt" event="0xff"/>
7 <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08"/> 7 <configuration counter="ARM_ARM11MPCore_cnt0" event="0x08"/>
8 <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b"/> 8 <configuration counter="ARM_ARM11MPCore_cnt1" event="0x0b"/>
9 <configuration counter="ARM_Cortex-A5_ccnt" event="0xff"/> 9 <configuration counter="ARMv7_Cortex_A5_ccnt" event="0xff"/>
10 <configuration counter="ARM_Cortex-A5_cnt0" event="0x8"/> 10 <configuration counter="ARMv7_Cortex_A5_cnt0" event="0x8"/>
11 <configuration counter="ARM_Cortex-A5_cnt1" event="0x1"/> 11 <configuration counter="ARMv7_Cortex_A5_cnt1" event="0x1"/>
12 <configuration counter="ARM_Cortex-A7_ccnt" event="0xff"/> 12 <configuration counter="ARMv7_Cortex_A7_ccnt" event="0xff"/>
13 <configuration counter="ARM_Cortex-A7_cnt0" event="0x08"/> 13 <configuration counter="ARMv7_Cortex_A7_cnt0" event="0x08"/>
14 <configuration counter="ARM_Cortex-A7_cnt1" event="0x10"/> 14 <configuration counter="ARMv7_Cortex_A7_cnt1" event="0x10"/>
15 <configuration counter="ARM_Cortex-A7_cnt2" event="0x16"/> 15 <configuration counter="ARMv7_Cortex_A7_cnt2" event="0x16"/>
16 <configuration counter="ARM_Cortex-A8_ccnt" event="0xff"/> 16 <configuration counter="ARMv7_Cortex_A8_ccnt" event="0xff"/>
17 <configuration counter="ARM_Cortex-A8_cnt0" event="0x8"/> 17 <configuration counter="ARMv7_Cortex_A8_cnt0" event="0x8"/>
18 <configuration counter="ARM_Cortex-A8_cnt1" event="0x44"/> 18 <configuration counter="ARMv7_Cortex_A8_cnt1" event="0x44"/>
19 <configuration counter="ARM_Cortex-A8_cnt2" event="0x43"/> 19 <configuration counter="ARMv7_Cortex_A8_cnt2" event="0x43"/>
20 <configuration counter="ARM_Cortex-A8_cnt3" event="0x10"/> 20 <configuration counter="ARMv7_Cortex_A8_cnt3" event="0x10"/>
21 <configuration counter="ARM_Cortex-A9_ccnt" event="0xff"/> 21 <configuration counter="ARMv7_Cortex_A9_ccnt" event="0xff"/>
22 <configuration counter="ARM_Cortex-A9_cnt0" event="0x68"/> 22 <configuration counter="ARMv7_Cortex_A9_cnt0" event="0x68"/>
23 <configuration counter="ARM_Cortex-A9_cnt1" event="0x06"/> 23 <configuration counter="ARMv7_Cortex_A9_cnt1" event="0x06"/>
24 <configuration counter="ARM_Cortex-A9_cnt2" event="0x07"/> 24 <configuration counter="ARMv7_Cortex_A9_cnt2" event="0x07"/>
25 <configuration counter="ARM_Cortex-A9_cnt3" event="0x03"/> 25 <configuration counter="ARMv7_Cortex_A9_cnt3" event="0x03"/>
26 <configuration counter="ARM_Cortex-A9_cnt4" event="0x04"/> 26 <configuration counter="ARMv7_Cortex_A9_cnt4" event="0x04"/>
27 <configuration counter="ARM_Cortex-A15_ccnt" event="0xff"/> 27 <configuration counter="ARMv7_Cortex_A12_ccnt" event="0xff"/>
28 <configuration counter="ARM_Cortex-A15_cnt0" event="0x8"/> 28 <configuration counter="ARMv7_Cortex_A12_cnt0" event="0x08"/>
29 <configuration counter="ARM_Cortex-A15_cnt1" event="0x16"/> 29 <configuration counter="ARMv7_Cortex_A12_cnt1" event="0x16"/>
30 <configuration counter="ARM_Cortex-A15_cnt2" event="0x10"/> 30 <configuration counter="ARMv7_Cortex_A12_cnt2" event="0x10"/>
31 <configuration counter="ARM_Cortex-A15_cnt3" event="0x19"/> 31 <configuration counter="ARMv7_Cortex_A12_cnt3" event="0x19"/>
32 <configuration counter="ARMv7_Cortex_A15_ccnt" event="0xff"/>
33 <configuration counter="ARMv7_Cortex_A15_cnt0" event="0x8"/>
34 <configuration counter="ARMv7_Cortex_A15_cnt1" event="0x16"/>
35 <configuration counter="ARMv7_Cortex_A15_cnt2" event="0x10"/>
36 <configuration counter="ARMv7_Cortex_A15_cnt3" event="0x19"/>
32 <configuration counter="ARM_Cortex-A53_ccnt" event="0x11"/> 37 <configuration counter="ARM_Cortex-A53_ccnt" event="0x11"/>
33 <configuration counter="ARM_Cortex-A53_cnt0" event="0x8"/> 38 <configuration counter="ARM_Cortex-A53_cnt0" event="0x8"/>
34 <configuration counter="ARM_Cortex-A53_cnt1" event="0x16"/> 39 <configuration counter="ARM_Cortex-A53_cnt1" event="0x16"/>
diff --git a/daemon/escape.c b/daemon/escape.c
index 3eec1f8..c54aa1c 100644
--- a/daemon/escape.c
+++ b/daemon/escape.c
@@ -1,5 +1,5 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
diff --git a/daemon/events-Cortex-A12.xml b/daemon/events-Cortex-A12.xml
index 20a4772..9c04354 100644
--- a/daemon/events-Cortex-A12.xml
+++ b/daemon/events-Cortex-A12.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A12_cnt" count="6"/> 1 <counter_set name="ARMv7_Cortex_A12_cnt" count="6"/>
2 <category name="Cortex-A12" counter_set="ARM_Cortex-A12_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A12" counter_set="ARMv7_Cortex_A12_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A12_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A12_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 4 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
5 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 5 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
6 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/> 6 <event event="0x03" title="Cache" name="Data refill" description="Memory Read or Write operation that causes a refill of at least the level of data or unified cache closest to the processor"/>
diff --git a/daemon/events-Cortex-A15.xml b/daemon/events-Cortex-A15.xml
index faa8b1c..f50e55d 100644
--- a/daemon/events-Cortex-A15.xml
+++ b/daemon/events-Cortex-A15.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A15_cnt" count="6"/> 1 <counter_set name="ARMv7_Cortex_A15_cnt" count="6"/>
2 <category name="Cortex-A15" counter_set="ARM_Cortex-A15_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A15" counter_set="ARMv7_Cortex_A15_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A15_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A15_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/> 4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Cortex-A5.xml b/daemon/events-Cortex-A5.xml
index a5b1546..d67581d 100644
--- a/daemon/events-Cortex-A5.xml
+++ b/daemon/events-Cortex-A5.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A5_cnt" count="2"/> 1 <counter_set name="ARMv7_Cortex_A5_cnt" count="2"/>
2 <category name="Cortex-A5" counter_set="ARM_Cortex-A5_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A5" counter_set="ARMv7_Cortex_A5_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A5_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A5_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Cortex-A7.xml b/daemon/events-Cortex-A7.xml
index 54d7264..6e078b3 100644
--- a/daemon/events-Cortex-A7.xml
+++ b/daemon/events-Cortex-A7.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A7_cnt" count="4"/> 1 <counter_set name="ARMv7_Cortex_A7_cnt" count="4"/>
2 <category name="Cortex-A7" counter_set="ARM_Cortex-A7_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A7" counter_set="ARMv7_Cortex_A7_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A7_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A7_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/> 4 <event event="0x00" title="Software" name="Increment" description="Software increment architecturally executed"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Cortex-A8.xml b/daemon/events-Cortex-A8.xml
index f251823..a69e25a 100644
--- a/daemon/events-Cortex-A8.xml
+++ b/daemon/events-Cortex-A8.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A8_cnt" count="4"/> 1 <counter_set name="ARMv7_Cortex_A8_cnt" count="4"/>
2 <category name="Cortex-A8" counter_set="ARM_Cortex-A8_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A8" counter_set="ARMv7_Cortex_A8_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A8_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A8_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Cortex-A9.xml b/daemon/events-Cortex-A9.xml
index 75f09c8..3e7f828 100644
--- a/daemon/events-Cortex-A9.xml
+++ b/daemon/events-Cortex-A9.xml
@@ -1,6 +1,6 @@
1 <counter_set name="ARM_Cortex-A9_cnt" count="6"/> 1 <counter_set name="ARMv7_Cortex_A9_cnt" count="6"/>
2 <category name="Cortex-A9" counter_set="ARM_Cortex-A9_cnt" per_cpu="yes" supports_event_based_sampling="yes"> 2 <category name="Cortex-A9" counter_set="ARMv7_Cortex_A9_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="ARM_Cortex-A9_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/> 3 <event counter="ARMv7_Cortex_A9_ccnt" event="0xff" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/> 4 <event event="0x00" title="Software" name="Increment" description="Incremented only on writes to the Software Increment Register"/>
5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/> 5 <event event="0x01" title="Cache" name="Instruction refill" description="Instruction fetch that causes a refill of at least the level of instruction or unified cache closest to the processor"/>
6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/> 6 <event event="0x02" title="Cache" name="Inst TLB refill" description="Instruction fetch that causes a TLB refill of at least the level of TLB closest to the processor"/>
diff --git a/daemon/events-Linux.xml b/daemon/events-Linux.xml
index 31a90a1..4d677e1 100644
--- a/daemon/events-Linux.xml
+++ b/daemon/events-Linux.xml
@@ -6,12 +6,12 @@
6 <event counter="Linux_net_rx" title="Network" name="Receive" units="B" description="Receive network traffic, including effect from Streamline"/> 6 <event counter="Linux_net_rx" title="Network" name="Receive" units="B" description="Receive network traffic, including effect from Streamline"/>
7 <event counter="Linux_net_tx" title="Network" name="Transmit" units="B" description="Transmit network traffic, including effect from Streamline"/> 7 <event counter="Linux_net_tx" title="Network" name="Transmit" units="B" description="Transmit network traffic, including effect from Streamline"/>
8 <event counter="Linux_sched_switch" title="Scheduler" name="Switch" per_cpu="yes" description="Context switch events"/> 8 <event counter="Linux_sched_switch" title="Scheduler" name="Switch" per_cpu="yes" description="Context switch events"/>
9 <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."/> 9 <event counter="Linux_meminfo_memused" title="Memory" name="Used" class="absolute" 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."/>
10 <event counter="Linux_meminfo_memfree" title="Memory" name="Free" display="minimum" units="B" description="Available memory size"/> 10 <event counter="Linux_meminfo_memfree" title="Memory" name="Free" class="absolute" display="minimum" units="B" description="Available memory size"/>
11 <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" display="maximum" units="B" description="Memory used by OS disk buffers"/> 11 <event counter="Linux_meminfo_bufferram" title="Memory" name="Buffer" class="absolute" units="B" description="Memory used by OS disk buffers"/>
12 <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"/> 12 <event counter="Linux_power_cpu_freq" title="Clock" name="Frequency" per_cpu="yes" class="absolute" units="Hz" series_composition="overlay" average_cores="yes" description="Frequency setting of the CPU"/>
13 <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"/> 13 <event counter="Linux_power_cpu_idle" title="Idle" name="State" per_cpu="yes" class="absolute" description="CPU Idle State + 1, set the Sample Rate to None to prevent the hrtimer from interrupting the system"/>
14 <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"/> 14 <event counter="Linux_cpu_wait_contention" title="CPU Contention" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on contended resource"/>
15 <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"/> 15 <event counter="Linux_cpu_wait_io" title="CPU I/O" name="Wait" per_cpu="no" class="activity" derived="yes" rendering_type="bar" average_selection="yes" percentage="yes" modifier="10000" description="Thread waiting on I/O resource"/>
16 </category> 16 </category>
17 17
diff --git a/daemon/events-Mali-4xx.xml b/daemon/events-Mali-4xx.xml
index 8772ce4..5a71386 100644
--- a/daemon/events-Mali-4xx.xml
+++ b/daemon/events-Mali-4xx.xml
@@ -207,7 +207,7 @@
207 <event event="0x0400" option_set="fs" title="ARM Mali-4xx" name="Filmstrip" description="Scaled framebuffer"/> 207 <event event="0x0400" option_set="fs" title="ARM Mali-4xx" name="Filmstrip" description="Scaled framebuffer"/>
208 </category> 208 </category>
209 <category name="ARM_Mali-4xx_Voltage" per_cpu="no"> 209 <category name="ARM_Mali-4xx_Voltage" per_cpu="no">
210 <event counter="ARM_Mali-4xx_Voltage" title="Mali GPU Voltage" name="Voltage" display="average" average_selection="yes" units="mV" description="GPU core voltage."/> 210 <event counter="ARM_Mali-4xx_Voltage" title="Mali GPU Voltage" name="Voltage" class="absolute" display="average" average_selection="yes" units="mV" description="GPU core voltage."/>
211 </category> 211 </category>
212 <category name="ARM_Mali-4xx_Frequency" per_cpu="no"> 212 <category name="ARM_Mali-4xx_Frequency" per_cpu="no">
213 <event counter="ARM_Mali-4xx_Frequency" title="Mali GPU Frequency" name="Frequency" display="average" average_selection="yes" units="MHz" description="GPU core frequency."/> 213 <event counter="ARM_Mali-4xx_Frequency" title="Mali GPU Frequency" name="Frequency" display="average" average_selection="yes" units="MHz" description="GPU core frequency."/>
diff --git a/daemon/events-Mali-T6xx.xml b/daemon/events-Mali-T6xx.xml
index 2465238..ec9ca00 100644
--- a/daemon/events-Mali-T6xx.xml
+++ b/daemon/events-Mali-T6xx.xml
@@ -4,14 +4,14 @@
4 </category> 4 </category>
5 5
6 <category name="Mali-T6xx-PMShader" per_cpu="no"> 6 <category name="Mali-T6xx-PMShader" per_cpu="no">
7 <event counter="ARM_Mali-T6xx_PM_SHADER_0" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 0" description="Mali PM Shader: PM Shader Core 0."/> 7 <event counter="ARM_Mali-T6xx_PM_SHADER_0" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 0" description="Mali PM Shader: PM Shader Core 0."/>
8 <event counter="ARM_Mali-T6xx_PM_SHADER_1" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 1" description="Mali PM Shader: PM Shader Core 1."/> 8 <event counter="ARM_Mali-T6xx_PM_SHADER_1" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 1" description="Mali PM Shader: PM Shader Core 1."/>
9 <event counter="ARM_Mali-T6xx_PM_SHADER_2" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 2" description="Mali PM Shader: PM Shader Core 2."/> 9 <event counter="ARM_Mali-T6xx_PM_SHADER_2" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 2" description="Mali PM Shader: PM Shader Core 2."/>
10 <event counter="ARM_Mali-T6xx_PM_SHADER_3" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 3" description="Mali PM Shader: PM Shader Core 3."/> 10 <event counter="ARM_Mali-T6xx_PM_SHADER_3" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 3" description="Mali PM Shader: PM Shader Core 3."/>
11 <event counter="ARM_Mali-T6xx_PM_SHADER_4" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 4" description="Mali PM Shader: PM Shader Core 4."/> 11 <event counter="ARM_Mali-T6xx_PM_SHADER_4" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 4" description="Mali PM Shader: PM Shader Core 4."/>
12 <event counter="ARM_Mali-T6xx_PM_SHADER_5" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 5" description="Mali PM Shader: PM Shader Core 5."/> 12 <event counter="ARM_Mali-T6xx_PM_SHADER_5" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 5" description="Mali PM Shader: PM Shader Core 5."/>
13 <event counter="ARM_Mali-T6xx_PM_SHADER_6" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 6" description="Mali PM Shader: PM Shader Core 6."/> 13 <event counter="ARM_Mali-T6xx_PM_SHADER_6" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 6" description="Mali PM Shader: PM Shader Core 6."/>
14 <event counter="ARM_Mali-T6xx_PM_SHADER_7" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 7" description="Mali PM Shader: PM Shader Core 7."/> 14 <event counter="ARM_Mali-T6xx_PM_SHADER_7" class="absolute" display="average" average_selection="yes" percentage="yes" title="Mali PM Shader" name="PM Shader Core 7" description="Mali PM Shader: PM Shader Core 7."/>
15 </category> 15 </category>
16 16
17 <category name="Mali-T6xx-PMTiler" per_cpu="no"> 17 <category name="Mali-T6xx-PMTiler" per_cpu="no">
diff --git a/daemon/events-Perf-Hardware.xml b/daemon/events-Perf-Hardware.xml
new file mode 100644
index 0000000..423696f
--- /dev/null
+++ b/daemon/events-Perf-Hardware.xml
@@ -0,0 +1,12 @@
1 <counter_set name="Perf_Hardware_cnt" count="6"/>
2 <category name="Perf Hardware" counter_set="Perf_Hardware_cnt" per_cpu="yes" supports_event_based_sampling="yes">
3 <event counter="Perf_Hardware_ccnt" event="0" title="Clock" name="Cycles" display="hertz" units="Hz" average_selection="yes" average_cores="yes" description="The number of core clock cycles"/>
4 <event event="1" title="Instruction" name="Executed" description="Instruction executed"/>
5 <event event="2" title="Cache" name="References" description="Cache References"/>
6 <event event="3" title="Cache" name="Misses" description="Cache Misses"/>
7 <event event="4" title="Branch" name="Instructions" description="Branch or other change in program flow that could have been predicted by the branch prediction resources of the processor"/>
8 <event event="5" title="Branch" name="Misses" description="Branch mispredicted or not predicted"/>
9 <event event="6" title="Bus" name="Cycles" description="Bus Cycles"/>
10 <event event="7" title="Instruction" name="Stalled Frontend" description="Stalled Frontend Cycles"/>
11 <event event="8" title="Instruction" name="Stalled Backend" description="Stalled Backend Cycles"/>
12 </category>
diff --git a/daemon/k/perf_event.3.12.h b/daemon/k/perf_event.3.12.h
new file mode 100644
index 0000000..e886c48
--- /dev/null
+++ b/daemon/k/perf_event.3.12.h
@@ -0,0 +1,792 @@
1/*
2 * Performance events:
3 *
4 * Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
5 * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar
6 * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra
7 *
8 * Data type definitions, declarations, prototypes.
9 *
10 * Started by: Thomas Gleixner and Ingo Molnar
11 *
12 * For licencing details see kernel-base/COPYING
13 */
14#ifndef _LINUX_PERF_EVENT_H
15#define _LINUX_PERF_EVENT_H
16
17#include <linux/types.h>
18#include <linux/ioctl.h>
19#include <asm/byteorder.h>
20
21/*
22 * User-space ABI bits:
23 */
24
25/*
26 * attr.type
27 */
28enum perf_type_id {
29 PERF_TYPE_HARDWARE = 0,
30 PERF_TYPE_SOFTWARE = 1,
31 PERF_TYPE_TRACEPOINT = 2,
32 PERF_TYPE_HW_CACHE = 3,
33 PERF_TYPE_RAW = 4,
34 PERF_TYPE_BREAKPOINT = 5,
35
36 PERF_TYPE_MAX, /* non-ABI */
37};
38
39/*
40 * Generalized performance event event_id types, used by the
41 * attr.event_id parameter of the sys_perf_event_open()
42 * syscall:
43 */
44enum perf_hw_id {
45 /*
46 * Common hardware events, generalized by the kernel:
47 */
48 PERF_COUNT_HW_CPU_CYCLES = 0,
49 PERF_COUNT_HW_INSTRUCTIONS = 1,
50 PERF_COUNT_HW_CACHE_REFERENCES = 2,
51 PERF_COUNT_HW_CACHE_MISSES = 3,
52 PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4,
53 PERF_COUNT_HW_BRANCH_MISSES = 5,
54 PERF_COUNT_HW_BUS_CYCLES = 6,
55 PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7,
56 PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8,
57 PERF_COUNT_HW_REF_CPU_CYCLES = 9,
58
59 PERF_COUNT_HW_MAX, /* non-ABI */
60};
61
62/*
63 * Generalized hardware cache events:
64 *
65 * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x
66 * { read, write, prefetch } x
67 * { accesses, misses }
68 */
69enum perf_hw_cache_id {
70 PERF_COUNT_HW_CACHE_L1D = 0,
71 PERF_COUNT_HW_CACHE_L1I = 1,
72 PERF_COUNT_HW_CACHE_LL = 2,
73 PERF_COUNT_HW_CACHE_DTLB = 3,
74 PERF_COUNT_HW_CACHE_ITLB = 4,
75 PERF_COUNT_HW_CACHE_BPU = 5,
76 PERF_COUNT_HW_CACHE_NODE = 6,
77
78 PERF_COUNT_HW_CACHE_MAX, /* non-ABI */
79};
80
81enum perf_hw_cache_op_id {
82 PERF_COUNT_HW_CACHE_OP_READ = 0,
83 PERF_COUNT_HW_CACHE_OP_WRITE = 1,
84 PERF_COUNT_HW_CACHE_OP_PREFETCH = 2,
85
86 PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */
87};
88
89enum perf_hw_cache_op_result_id {
90 PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0,
91 PERF_COUNT_HW_CACHE_RESULT_MISS = 1,
92
93 PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */
94};
95
96/*
97 * Special "software" events provided by the kernel, even if the hardware
98 * does not support performance events. These events measure various
99 * physical and sw events of the kernel (and allow the profiling of them as
100 * well):
101 */
102enum perf_sw_ids {
103 PERF_COUNT_SW_CPU_CLOCK = 0,
104 PERF_COUNT_SW_TASK_CLOCK = 1,
105 PERF_COUNT_SW_PAGE_FAULTS = 2,
106 PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
107 PERF_COUNT_SW_CPU_MIGRATIONS = 4,
108 PERF_COUNT_SW_PAGE_FAULTS_MIN = 5,
109 PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6,
110 PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
111 PERF_COUNT_SW_EMULATION_FAULTS = 8,
112 PERF_COUNT_SW_DUMMY = 9,
113
114 PERF_COUNT_SW_MAX, /* non-ABI */
115};
116
117/*
118 * Bits that can be set in attr.sample_type to request information
119 * in the overflow packets.
120 */
121enum perf_event_sample_format {
122 PERF_SAMPLE_IP = 1U << 0,
123 PERF_SAMPLE_TID = 1U << 1,
124 PERF_SAMPLE_TIME = 1U << 2,
125 PERF_SAMPLE_ADDR = 1U << 3,
126 PERF_SAMPLE_READ = 1U << 4,
127 PERF_SAMPLE_CALLCHAIN = 1U << 5,
128 PERF_SAMPLE_ID = 1U << 6,
129 PERF_SAMPLE_CPU = 1U << 7,
130 PERF_SAMPLE_PERIOD = 1U << 8,
131 PERF_SAMPLE_STREAM_ID = 1U << 9,
132 PERF_SAMPLE_RAW = 1U << 10,
133 PERF_SAMPLE_BRANCH_STACK = 1U << 11,
134 PERF_SAMPLE_REGS_USER = 1U << 12,
135 PERF_SAMPLE_STACK_USER = 1U << 13,
136 PERF_SAMPLE_WEIGHT = 1U << 14,
137 PERF_SAMPLE_DATA_SRC = 1U << 15,
138 PERF_SAMPLE_IDENTIFIER = 1U << 16,
139
140 PERF_SAMPLE_MAX = 1U << 17, /* non-ABI */
141};
142
143/*
144 * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set
145 *
146 * If the user does not pass priv level information via branch_sample_type,
147 * the kernel uses the event's priv level. Branch and event priv levels do
148 * not have to match. Branch priv level is checked for permissions.
149 *
150 * The branch types can be combined, however BRANCH_ANY covers all types
151 * of branches and therefore it supersedes all the other types.
152 */
153enum perf_branch_sample_type {
154 PERF_SAMPLE_BRANCH_USER = 1U << 0, /* user branches */
155 PERF_SAMPLE_BRANCH_KERNEL = 1U << 1, /* kernel branches */
156 PERF_SAMPLE_BRANCH_HV = 1U << 2, /* hypervisor branches */
157
158 PERF_SAMPLE_BRANCH_ANY = 1U << 3, /* any branch types */
159 PERF_SAMPLE_BRANCH_ANY_CALL = 1U << 4, /* any call branch */
160 PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << 5, /* any return branch */
161 PERF_SAMPLE_BRANCH_IND_CALL = 1U << 6, /* indirect calls */
162 PERF_SAMPLE_BRANCH_ABORT_TX = 1U << 7, /* transaction aborts */
163 PERF_SAMPLE_BRANCH_IN_TX = 1U << 8, /* in transaction */
164 PERF_SAMPLE_BRANCH_NO_TX = 1U << 9, /* not in transaction */
165
166 PERF_SAMPLE_BRANCH_MAX = 1U << 10, /* non-ABI */
167};
168
169#define PERF_SAMPLE_BRANCH_PLM_ALL \
170 (PERF_SAMPLE_BRANCH_USER|\
171 PERF_SAMPLE_BRANCH_KERNEL|\
172 PERF_SAMPLE_BRANCH_HV)
173
174/*
175 * Values to determine ABI of the registers dump.
176 */
177enum perf_sample_regs_abi {
178 PERF_SAMPLE_REGS_ABI_NONE = 0,
179 PERF_SAMPLE_REGS_ABI_32 = 1,
180 PERF_SAMPLE_REGS_ABI_64 = 2,
181};
182
183/*
184 * The format of the data returned by read() on a perf event fd,
185 * as specified by attr.read_format:
186 *
187 * struct read_format {
188 * { u64 value;
189 * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
190 * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
191 * { u64 id; } && PERF_FORMAT_ID
192 * } && !PERF_FORMAT_GROUP
193 *
194 * { u64 nr;
195 * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
196 * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
197 * { u64 value;
198 * { u64 id; } && PERF_FORMAT_ID
199 * } cntr[nr];
200 * } && PERF_FORMAT_GROUP
201 * };
202 */
203enum perf_event_read_format {
204 PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0,
205 PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
206 PERF_FORMAT_ID = 1U << 2,
207 PERF_FORMAT_GROUP = 1U << 3,
208
209 PERF_FORMAT_MAX = 1U << 4, /* non-ABI */
210};
211
212#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */
213#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */
214#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
215#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
216 /* add: sample_stack_user */
217
218/*
219 * Hardware event_id to monitor via a performance monitoring event:
220 */
221struct perf_event_attr {
222
223 /*
224 * Major type: hardware/software/tracepoint/etc.
225 */
226 __u32 type;
227
228 /*
229 * Size of the attr structure, for fwd/bwd compat.
230 */
231 __u32 size;
232
233 /*
234 * Type specific configuration information.
235 */
236 __u64 config;
237
238 union {
239 __u64 sample_period;
240 __u64 sample_freq;
241 };
242
243 __u64 sample_type;
244 __u64 read_format;
245
246 __u64 disabled : 1, /* off by default */
247 inherit : 1, /* children inherit it */
248 pinned : 1, /* must always be on PMU */
249 exclusive : 1, /* only group on PMU */
250 exclude_user : 1, /* don't count user */
251 exclude_kernel : 1, /* ditto kernel */
252 exclude_hv : 1, /* ditto hypervisor */
253 exclude_idle : 1, /* don't count when idle */
254 mmap : 1, /* include mmap data */
255 comm : 1, /* include comm data */
256 freq : 1, /* use freq, not period */
257 inherit_stat : 1, /* per task counts */
258 enable_on_exec : 1, /* next exec enables */
259 task : 1, /* trace fork/exit */
260 watermark : 1, /* wakeup_watermark */
261 /*
262 * precise_ip:
263 *
264 * 0 - SAMPLE_IP can have arbitrary skid
265 * 1 - SAMPLE_IP must have constant skid
266 * 2 - SAMPLE_IP requested to have 0 skid
267 * 3 - SAMPLE_IP must have 0 skid
268 *
269 * See also PERF_RECORD_MISC_EXACT_IP
270 */
271 precise_ip : 2, /* skid constraint */
272 mmap_data : 1, /* non-exec mmap data */
273 sample_id_all : 1, /* sample_type all events */
274
275 exclude_host : 1, /* don't count in host */
276 exclude_guest : 1, /* don't count in guest */
277
278 exclude_callchain_kernel : 1, /* exclude kernel callchains */
279 exclude_callchain_user : 1, /* exclude user callchains */
280 mmap2 : 1, /* include mmap with inode data */
281
282 __reserved_1 : 40;
283
284 union {
285 __u32 wakeup_events; /* wakeup every n events */
286 __u32 wakeup_watermark; /* bytes before wakeup */
287 };
288
289 __u32 bp_type;
290 union {
291 __u64 bp_addr;
292 __u64 config1; /* extension of config */
293 };
294 union {
295 __u64 bp_len;
296 __u64 config2; /* extension of config1 */
297 };
298 __u64 branch_sample_type; /* enum perf_branch_sample_type */
299
300 /*
301 * Defines set of user regs to dump on samples.
302 * See asm/perf_regs.h for details.
303 */
304 __u64 sample_regs_user;
305
306 /*
307 * Defines size of the user stack to dump on samples.
308 */
309 __u32 sample_stack_user;
310
311 /* Align to u64. */
312 __u32 __reserved_2;
313};
314
315#define perf_flags(attr) (*(&(attr)->read_format + 1))
316
317/*
318 * Ioctls that can be done on a perf event fd:
319 */
320#define PERF_EVENT_IOC_ENABLE _IO ('$', 0)
321#define PERF_EVENT_IOC_DISABLE _IO ('$', 1)
322#define PERF_EVENT_IOC_REFRESH _IO ('$', 2)
323#define PERF_EVENT_IOC_RESET _IO ('$', 3)
324#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64)
325#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5)
326#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *)
327#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *)
328
329enum perf_event_ioc_flags {
330 PERF_IOC_FLAG_GROUP = 1U << 0,
331};
332
333/*
334 * Structure of the page that can be mapped via mmap
335 */
336struct perf_event_mmap_page {
337 __u32 version; /* version number of this structure */
338 __u32 compat_version; /* lowest version this is compat with */
339
340 /*
341 * Bits needed to read the hw events in user-space.
342 *
343 * u32 seq, time_mult, time_shift, idx, width;
344 * u64 count, enabled, running;
345 * u64 cyc, time_offset;
346 * s64 pmc = 0;
347 *
348 * do {
349 * seq = pc->lock;
350 * barrier()
351 *
352 * enabled = pc->time_enabled;
353 * running = pc->time_running;
354 *
355 * if (pc->cap_usr_time && enabled != running) {
356 * cyc = rdtsc();
357 * time_offset = pc->time_offset;
358 * time_mult = pc->time_mult;
359 * time_shift = pc->time_shift;
360 * }
361 *
362 * idx = pc->index;
363 * count = pc->offset;
364 * if (pc->cap_usr_rdpmc && idx) {
365 * width = pc->pmc_width;
366 * pmc = rdpmc(idx - 1);
367 * }
368 *
369 * barrier();
370 * } while (pc->lock != seq);
371 *
372 * NOTE: for obvious reason this only works on self-monitoring
373 * processes.
374 */
375 __u32 lock; /* seqlock for synchronization */
376 __u32 index; /* hardware event identifier */
377 __s64 offset; /* add to hardware event value */
378 __u64 time_enabled; /* time event active */
379 __u64 time_running; /* time event on cpu */
380 union {
381 __u64 capabilities;
382 struct {
383 __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */
384 cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */
385
386 cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */
387 cap_user_time : 1, /* The time_* fields are used */
388 cap_user_time_zero : 1, /* The time_zero field is used */
389 cap_____res : 59;
390 };
391 };
392
393 /*
394 * If cap_usr_rdpmc this field provides the bit-width of the value
395 * read using the rdpmc() or equivalent instruction. This can be used
396 * to sign extend the result like:
397 *
398 * pmc <<= 64 - width;
399 * pmc >>= 64 - width; // signed shift right
400 * count += pmc;
401 */
402 __u16 pmc_width;
403
404 /*
405 * If cap_usr_time the below fields can be used to compute the time
406 * delta since time_enabled (in ns) using rdtsc or similar.
407 *
408 * u64 quot, rem;
409 * u64 delta;
410 *
411 * quot = (cyc >> time_shift);
412 * rem = cyc & ((1 << time_shift) - 1);
413 * delta = time_offset + quot * time_mult +
414 * ((rem * time_mult) >> time_shift);
415 *
416 * Where time_offset,time_mult,time_shift and cyc are read in the
417 * seqcount loop described above. This delta can then be added to
418 * enabled and possible running (if idx), improving the scaling:
419 *
420 * enabled += delta;
421 * if (idx)
422 * running += delta;
423 *
424 * quot = count / running;
425 * rem = count % running;
426 * count = quot * enabled + (rem * enabled) / running;
427 */
428 __u16 time_shift;
429 __u32 time_mult;
430 __u64 time_offset;
431 /*
432 * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated
433 * from sample timestamps.
434 *
435 * time = timestamp - time_zero;
436 * quot = time / time_mult;
437 * rem = time % time_mult;
438 * cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
439 *
440 * And vice versa:
441 *
442 * quot = cyc >> time_shift;
443 * rem = cyc & ((1 << time_shift) - 1);
444 * timestamp = time_zero + quot * time_mult +
445 * ((rem * time_mult) >> time_shift);
446 */
447 __u64 time_zero;
448 __u32 size; /* Header size up to __reserved[] fields. */
449
450 /*
451 * Hole for extension of the self monitor capabilities
452 */
453
454 __u8 __reserved[118*8+4]; /* align to 1k. */
455
456 /*
457 * Control data for the mmap() data buffer.
458 *
459 * User-space reading the @data_head value should issue an smp_rmb(),
460 * after reading this value.
461 *
462 * When the mapping is PROT_WRITE the @data_tail value should be
463 * written by userspace to reflect the last read data, after issueing
464 * an smp_mb() to separate the data read from the ->data_tail store.
465 * In this case the kernel will not over-write unread data.
466 *
467 * See perf_output_put_handle() for the data ordering.
468 */
469 __u64 data_head; /* head in the data section */
470 __u64 data_tail; /* user-space written tail */
471};
472
473#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
474#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
475#define PERF_RECORD_MISC_KERNEL (1 << 0)
476#define PERF_RECORD_MISC_USER (2 << 0)
477#define PERF_RECORD_MISC_HYPERVISOR (3 << 0)
478#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0)
479#define PERF_RECORD_MISC_GUEST_USER (5 << 0)
480
481#define PERF_RECORD_MISC_MMAP_DATA (1 << 13)
482/*
483 * Indicates that the content of PERF_SAMPLE_IP points to
484 * the actual instruction that triggered the event. See also
485 * perf_event_attr::precise_ip.
486 */
487#define PERF_RECORD_MISC_EXACT_IP (1 << 14)
488/*
489 * Reserve the last bit to indicate some extended misc field
490 */
491#define PERF_RECORD_MISC_EXT_RESERVED (1 << 15)
492
493struct perf_event_header {
494 __u32 type;
495 __u16 misc;
496 __u16 size;
497};
498
499enum perf_event_type {
500
501 /*
502 * If perf_event_attr.sample_id_all is set then all event types will
503 * have the sample_type selected fields related to where/when
504 * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
505 * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
506 * just after the perf_event_header and the fields already present for
507 * the existing fields, i.e. at the end of the payload. That way a newer
508 * perf.data file will be supported by older perf tools, with these new
509 * optional fields being ignored.
510 *
511 * struct sample_id {
512 * { u32 pid, tid; } && PERF_SAMPLE_TID
513 * { u64 time; } && PERF_SAMPLE_TIME
514 * { u64 id; } && PERF_SAMPLE_ID
515 * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
516 * { u32 cpu, res; } && PERF_SAMPLE_CPU
517 * { u64 id; } && PERF_SAMPLE_IDENTIFIER
518 * } && perf_event_attr::sample_id_all
519 *
520 * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The
521 * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
522 * relative to header.size.
523 */
524
525 /*
526 * The MMAP events record the PROT_EXEC mappings so that we can
527 * correlate userspace IPs to code. They have the following structure:
528 *
529 * struct {
530 * struct perf_event_header header;
531 *
532 * u32 pid, tid;
533 * u64 addr;
534 * u64 len;
535 * u64 pgoff;
536 * char filename[];
537 * struct sample_id sample_id;
538 * };
539 */
540 PERF_RECORD_MMAP = 1,
541
542 /*
543 * struct {
544 * struct perf_event_header header;
545 * u64 id;
546 * u64 lost;
547 * struct sample_id sample_id;
548 * };
549 */
550 PERF_RECORD_LOST = 2,
551
552 /*
553 * struct {
554 * struct perf_event_header header;
555 *
556 * u32 pid, tid;
557 * char comm[];
558 * struct sample_id sample_id;
559 * };
560 */
561 PERF_RECORD_COMM = 3,
562
563 /*
564 * struct {
565 * struct perf_event_header header;
566 * u32 pid, ppid;
567 * u32 tid, ptid;
568 * u64 time;
569 * struct sample_id sample_id;
570 * };
571 */
572 PERF_RECORD_EXIT = 4,
573
574 /*
575 * struct {
576 * struct perf_event_header header;
577 * u64 time;
578 * u64 id;
579 * u64 stream_id;
580 * struct sample_id sample_id;
581 * };
582 */
583 PERF_RECORD_THROTTLE = 5,
584 PERF_RECORD_UNTHROTTLE = 6,
585
586 /*
587 * struct {
588 * struct perf_event_header header;
589 * u32 pid, ppid;
590 * u32 tid, ptid;
591 * u64 time;
592 * struct sample_id sample_id;
593 * };
594 */
595 PERF_RECORD_FORK = 7,
596
597 /*
598 * struct {
599 * struct perf_event_header header;
600 * u32 pid, tid;
601 *
602 * struct read_format values;
603 * struct sample_id sample_id;
604 * };
605 */
606 PERF_RECORD_READ = 8,
607
608 /*
609 * struct {
610 * struct perf_event_header header;
611 *
612 * #
613 * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
614 * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
615 * # is fixed relative to header.
616 * #
617 *
618 * { u64 id; } && PERF_SAMPLE_IDENTIFIER
619 * { u64 ip; } && PERF_SAMPLE_IP
620 * { u32 pid, tid; } && PERF_SAMPLE_TID
621 * { u64 time; } && PERF_SAMPLE_TIME
622 * { u64 addr; } && PERF_SAMPLE_ADDR
623 * { u64 id; } && PERF_SAMPLE_ID
624 * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
625 * { u32 cpu, res; } && PERF_SAMPLE_CPU
626 * { u64 period; } && PERF_SAMPLE_PERIOD
627 *
628 * { struct read_format values; } && PERF_SAMPLE_READ
629 *
630 * { u64 nr,
631 * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
632 *
633 * #
634 * # The RAW record below is opaque data wrt the ABI
635 * #
636 * # That is, the ABI doesn't make any promises wrt to
637 * # the stability of its content, it may vary depending
638 * # on event, hardware, kernel version and phase of
639 * # the moon.
640 * #
641 * # In other words, PERF_SAMPLE_RAW contents are not an ABI.
642 * #
643 *
644 * { u32 size;
645 * char data[size];}&& PERF_SAMPLE_RAW
646 *
647 * { u64 nr;
648 * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
649 *
650 * { u64 abi; # enum perf_sample_regs_abi
651 * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
652 *
653 * { u64 size;
654 * char data[size];
655 * u64 dyn_size; } && PERF_SAMPLE_STACK_USER
656 *
657 * { u64 weight; } && PERF_SAMPLE_WEIGHT
658 * { u64 data_src; } && PERF_SAMPLE_DATA_SRC
659 * };
660 */
661 PERF_RECORD_SAMPLE = 9,
662
663 /*
664 * The MMAP2 records are an augmented version of MMAP, they add
665 * maj, min, ino numbers to be used to uniquely identify each mapping
666 *
667 * struct {
668 * struct perf_event_header header;
669 *
670 * u32 pid, tid;
671 * u64 addr;
672 * u64 len;
673 * u64 pgoff;
674 * u32 maj;
675 * u32 min;
676 * u64 ino;
677 * u64 ino_generation;
678 * char filename[];
679 * struct sample_id sample_id;
680 * };
681 */
682 PERF_RECORD_MMAP2 = 10,
683
684 PERF_RECORD_MAX, /* non-ABI */
685};
686
687#define PERF_MAX_STACK_DEPTH 127
688
689enum perf_callchain_context {
690 PERF_CONTEXT_HV = (__u64)-32,
691 PERF_CONTEXT_KERNEL = (__u64)-128,
692 PERF_CONTEXT_USER = (__u64)-512,
693
694 PERF_CONTEXT_GUEST = (__u64)-2048,
695 PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176,
696 PERF_CONTEXT_GUEST_USER = (__u64)-2560,
697
698 PERF_CONTEXT_MAX = (__u64)-4095,
699};
700
701#define PERF_FLAG_FD_NO_GROUP (1U << 0)
702#define PERF_FLAG_FD_OUTPUT (1U << 1)
703#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */
704
705union perf_mem_data_src {
706 __u64 val;
707 struct {
708 __u64 mem_op:5, /* type of opcode */
709 mem_lvl:14, /* memory hierarchy level */
710 mem_snoop:5, /* snoop mode */
711 mem_lock:2, /* lock instr */
712 mem_dtlb:7, /* tlb access */
713 mem_rsvd:31;
714 };
715};
716
717/* type of opcode (load/store/prefetch,code) */
718#define PERF_MEM_OP_NA 0x01 /* not available */
719#define PERF_MEM_OP_LOAD 0x02 /* load instruction */
720#define PERF_MEM_OP_STORE 0x04 /* store instruction */
721#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */
722#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */
723#define PERF_MEM_OP_SHIFT 0
724
725/* memory hierarchy (memory level, hit or miss) */
726#define PERF_MEM_LVL_NA 0x01 /* not available */
727#define PERF_MEM_LVL_HIT 0x02 /* hit level */
728#define PERF_MEM_LVL_MISS 0x04 /* miss level */
729#define PERF_MEM_LVL_L1 0x08 /* L1 */
730#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */
731#define PERF_MEM_LVL_L2 0x20 /* L2 */
732#define PERF_MEM_LVL_L3 0x40 /* L3 */
733#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */
734#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */
735#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */
736#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */
737#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */
738#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */
739#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */
740#define PERF_MEM_LVL_SHIFT 5
741
742/* snoop mode */
743#define PERF_MEM_SNOOP_NA 0x01 /* not available */
744#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */
745#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */
746#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */
747#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */
748#define PERF_MEM_SNOOP_SHIFT 19
749
750/* locked instruction */
751#define PERF_MEM_LOCK_NA 0x01 /* not available */
752#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */
753#define PERF_MEM_LOCK_SHIFT 24
754
755/* TLB access */
756#define PERF_MEM_TLB_NA 0x01 /* not available */
757#define PERF_MEM_TLB_HIT 0x02 /* hit level */
758#define PERF_MEM_TLB_MISS 0x04 /* miss level */
759#define PERF_MEM_TLB_L1 0x08 /* L1 */
760#define PERF_MEM_TLB_L2 0x10 /* L2 */
761#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/
762#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */
763#define PERF_MEM_TLB_SHIFT 26
764
765#define PERF_MEM_S(a, s) \
766 (((u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT)
767
768/*
769 * single taken branch record layout:
770 *
771 * from: source instruction (may not always be a branch insn)
772 * to: branch target
773 * mispred: branch target was mispredicted
774 * predicted: branch target was predicted
775 *
776 * support for mispred, predicted is optional. In case it
777 * is not supported mispred = predicted = 0.
778 *
779 * in_tx: running in a hardware transaction
780 * abort: aborting a hardware transaction
781 */
782struct perf_branch_entry {
783 __u64 from;
784 __u64 to;
785 __u64 mispred:1, /* target mispredicted */
786 predicted:1,/* target predicted */
787 in_tx:1, /* in transaction */
788 abort:1, /* transaction abort */
789 reserved:60;
790};
791
792#endif /* _LINUX_PERF_EVENT_H */
diff --git a/daemon/k/perf_event.h b/daemon/k/perf_event.h
new file mode 120000
index 0000000..e5dff8c
--- /dev/null
+++ b/daemon/k/perf_event.h
@@ -0,0 +1 @@
perf_event.3.12.h \ No newline at end of file
diff --git a/daemon/main.cpp b/daemon/main.cpp
index bfd36b9..1275aef 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -1,32 +1,30 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2013. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <stdlib.h> 9#include <arpa/inet.h>
10#include <signal.h>
11#include <sys/wait.h>
12#include <unistd.h>
13#include <sys/syscall.h>
14#include <sys/prctl.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <sys/mount.h>
18#include <fcntl.h> 10#include <fcntl.h>
11#include <pthread.h>
19#include <sys/mman.h> 12#include <sys/mman.h>
20#include <sys/time.h> 13#include <sys/mount.h>
14#include <sys/prctl.h>
21#include <sys/resource.h> 15#include <sys/resource.h>
22#include <arpa/inet.h>
23#include <sys/socket.h> 16#include <sys/socket.h>
17#include <sys/stat.h>
18#include <sys/syscall.h>
19#include <sys/wait.h>
20#include <unistd.h>
21
24#include "Child.h" 22#include "Child.h"
25#include "SessionData.h" 23#include "KMod.h"
26#include "OlySocket.h"
27#include "Logging.h" 24#include "Logging.h"
25#include "OlySocket.h"
28#include "OlyUtility.h" 26#include "OlyUtility.h"
29#include "KMod.h" 27#include "SessionData.h"
30 28
31#define DEBUG false 29#define DEBUG false
32 30
@@ -34,7 +32,7 @@ extern Child* child;
34static int shutdownFilesystem(); 32static int shutdownFilesystem();
35static pthread_mutex_t numSessions_mutex; 33static pthread_mutex_t numSessions_mutex;
36static int numSessions = 0; 34static int numSessions = 0;
37static OlySocket* sock = NULL; 35static OlyServerSocket* sock = NULL;
38static bool driverRunningAtStart = false; 36static bool driverRunningAtStart = false;
39static bool driverMountedAtStart = false; 37static bool driverMountedAtStart = false;
40 38
@@ -157,6 +155,7 @@ typedef struct {
157static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 }; 155static const char DST_REQ[] = { 'D', 'S', 'T', '_', 'R', 'E', 'Q', ' ', 0, 0, 0, 0x64 };
158 156
159static void* answerThread(void* pVoid) { 157static void* answerThread(void* pVoid) {
158 prctl(PR_SET_NAME, (unsigned long)&"gatord-discover", 0, 0, 0);
160 const struct cmdline_t * const cmdline = (struct cmdline_t *)pVoid; 159 const struct cmdline_t * const cmdline = (struct cmdline_t *)pVoid;
161 RVIConfigureInfo dstAns; 160 RVIConfigureInfo dstAns;
162 int req = udpPort(UDP_REQ_PORT); 161 int req = udpPort(UDP_REQ_PORT);
@@ -231,16 +230,7 @@ static bool init_module (const char * const location) {
231 return ret; 230 return ret;
232} 231}
233 232
234static int setupFilesystem(char* module) { 233static bool setupFilesystem(char* module) {
235 int retval;
236
237 // Verify root permissions
238 uid_t euid = geteuid();
239 if (euid) {
240 logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
241 handleException();
242 }
243
244 if (module) { 234 if (module) {
245 // unmount and rmmod if the module was specified on the commandline, i.e. ensure that the specified module is indeed running 235 // unmount and rmmod if the module was specified on the commandline, i.e. ensure that the specified module is indeed running
246 shutdownFilesystem(); 236 shutdownFilesystem();
@@ -252,7 +242,7 @@ static int setupFilesystem(char* module) {
252 } 242 }
253 } 243 }
254 244
255 retval = mountGatorFS(); 245 const int retval = mountGatorFS();
256 if (retval == 1) { 246 if (retval == 1) {
257 logg->logMessage("Driver already running at startup"); 247 logg->logMessage("Driver already running at startup");
258 driverRunningAtStart = true; 248 driverRunningAtStart = true;
@@ -274,8 +264,8 @@ static int setupFilesystem(char* module) {
274 } 264 }
275 265
276 if (access(location, F_OK) == -1) { 266 if (access(location, F_OK) == -1) {
277 logg->logError(__FILE__, __LINE__, "Unable to locate gator.ko driver:\n >>> gator.ko should be co-located with gatord in the same directory\n >>> OR insmod gator.ko prior to launching gatord\n >>> OR specify the location of gator.ko on the command line"); 267 // The gator kernel is not already loaded and unable to locate gator.ko
278 handleException(); 268 return false;
279 } 269 }
280 270
281 // Load driver 271 // Load driver
@@ -296,7 +286,7 @@ static int setupFilesystem(char* module) {
296 } 286 }
297 } 287 }
298 288
299 return 0; 289 return true;
300} 290}
301 291
302static int shutdownFilesystem() { 292static int shutdownFilesystem() {
@@ -418,8 +408,28 @@ int main(int argc, char** argv) {
418 // Parse the command line parameters 408 // Parse the command line parameters
419 struct cmdline_t cmdline = parseCommandLine(argc, argv); 409 struct cmdline_t cmdline = parseCommandLine(argc, argv);
420 410
411 // Verify root permissions
412 uid_t euid = geteuid();
413 if (euid) {
414 logg->logError(__FILE__, __LINE__, "gatord must be launched with root privileges");
415 handleException();
416 }
417
421 // Call before setting up the SIGCHLD handler, as system() spawns child processes 418 // Call before setting up the SIGCHLD handler, as system() spawns child processes
422 setupFilesystem(cmdline.module); 419 if (!setupFilesystem(cmdline.module)) {
420 logg->logMessage("Unable to setup gatorfs, trying perf");
421 if (!gSessionData->perf.setup()) {
422 logg->logError(__FILE__, __LINE__,
423 "Unable to locate gator.ko driver:\n"
424 " >>> gator.ko should be co-located with gatord in the same directory\n"
425 " >>> OR insmod gator.ko prior to launching gatord\n"
426 " >>> OR specify the location of gator.ko on the command line\n"
427 " >>> OR run Linux 3.12 or later with perf support to collect data via userspace only");
428 handleException();
429 }
430 }
431
432 gSessionData->hwmon.setup();
423 433
424 // Handle child exit codes 434 // Handle child exit codes
425 signal(SIGCHLD, child_exit); 435 signal(SIGCHLD, child_exit);
@@ -439,11 +449,11 @@ int main(int argc, char** argv) {
439 logg->logError(__FILE__, __LINE__, "Failed to create answer thread"); 449 logg->logError(__FILE__, __LINE__, "Failed to create answer thread");
440 handleException(); 450 handleException();
441 } 451 }
442 sock = new OlySocket(cmdline.port, true); 452 sock = new OlyServerSocket(cmdline.port);
443 // Forever loop, can be exited via a signal or exception 453 // Forever loop, can be exited via a signal or exception
444 while (1) { 454 while (1) {
445 logg->logMessage("Waiting on connection..."); 455 logg->logMessage("Waiting on connection...");
446 sock->acceptConnection(); 456 OlySocket client(sock->acceptConnection());
447 457
448 int pid = fork(); 458 int pid = fork();
449 if (pid < 0) { 459 if (pid < 0) {
@@ -452,13 +462,13 @@ int main(int argc, char** argv) {
452 } else if (pid == 0) { 462 } else if (pid == 0) {
453 // Child 463 // Child
454 sock->closeServerSocket(); 464 sock->closeServerSocket();
455 child = new Child(sock, numSessions + 1); 465 child = new Child(&client, numSessions + 1);
456 child->run(); 466 child->run();
457 delete child; 467 delete child;
458 exit(0); 468 exit(0);
459 } else { 469 } else {
460 // Parent 470 // Parent
461 sock->closeSocket(); 471 client.closeSocket();
462 472
463 pthread_mutex_lock(&numSessions_mutex); 473 pthread_mutex_lock(&numSessions_mutex);
464 numSessions++; 474 numSessions++;