blob: 8fa6280150694d1b681a209d5f1eded1930a4686 [file] [log] [blame]
Jon Medhurstaaf37a32013-06-11 12:10:56 +01001/**
Jon Medhurst15ce78d2014-04-10 09:02:02 +01002 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
Jon Medhurstaaf37a32013-06-11 12:10:56 +01003 *
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 "Buffer.h"
10
11#include "Logging.h"
12#include "Sender.h"
13#include "SessionData.h"
14
Jon Medhurst15ce78d2014-04-10 09:02:02 +010015#define mask (mSize - 1)
Jon Medhurstaaf37a32013-06-11 12:10:56 +010016
Jon Medhurst15ce78d2014-04-10 09:02:02 +010017enum {
Jon Medhurst96b56152014-10-30 18:01:15 +000018 CODE_PEA = 1,
19 CODE_KEYS = 2,
20 CODE_FORMAT = 3,
21 CODE_MAPS = 4,
22 CODE_COMM = 5,
23 CODE_KEYS_OLD = 6,
24 CODE_ONLINE_CPU = 7,
25 CODE_OFFLINE_CPU = 8,
26 CODE_KALLSYMS = 9,
Jon Medhurst15ce78d2014-04-10 09:02:02 +010027};
28
29// Summary Frame Messages
30enum {
31 MESSAGE_SUMMARY = 1,
32 MESSAGE_CORE_NAME = 3,
33};
34
35// From gator_marshaling.c
36#define NEWLINE_CANARY \
37 /* Unix */ \
38 "1\n" \
39 /* Windows */ \
40 "2\r\n" \
41 /* Mac OS */ \
42 "3\r" \
43 /* RISC OS */ \
44 "4\n\r" \
45 /* Add another character so the length isn't 0x0a bytes */ \
46 "5"
47
Jon Medhurst96b56152014-10-30 18:01:15 +000048Buffer::Buffer(const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : mBuf(new char[size]), mReaderSem(readerSem), mCommitTime(gSessionData->mLiveRate), mSize(size), mReadPos(0), mWritePos(0), mCommitPos(0), mAvailable(true), mIsDone(false), mCore(core), mBufType(buftype) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +010049 if ((mSize & mask) != 0) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010050 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
51 handleException();
52 }
Jon Medhurst96b56152014-10-30 18:01:15 +000053 sem_init(&mWriterSem, 0, 0);
Jon Medhurstaaf37a32013-06-11 12:10:56 +010054 frame();
55}
56
Jon Medhurst15ce78d2014-04-10 09:02:02 +010057Buffer::~Buffer() {
58 delete [] mBuf;
Jon Medhurst96b56152014-10-30 18:01:15 +000059 sem_destroy(&mWriterSem);
Jon Medhurstaaf37a32013-06-11 12:10:56 +010060}
61
Jon Medhurst15ce78d2014-04-10 09:02:02 +010062void Buffer::write(Sender *const sender) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010063 if (!commitReady()) {
64 return;
65 }
66
Jon Medhurst96b56152014-10-30 18:01:15 +000067 // commit and read are updated by the writer, only read them once
68 int commitPos = mCommitPos;
69 int readPos = mReadPos;
70
Jon Medhurstaaf37a32013-06-11 12:10:56 +010071 // determine the size of two halves
Jon Medhurst96b56152014-10-30 18:01:15 +000072 int length1 = commitPos - readPos;
73 char *buffer1 = mBuf + readPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010074 int length2 = 0;
Jon Medhurst15ce78d2014-04-10 09:02:02 +010075 char *buffer2 = mBuf;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010076 if (length1 < 0) {
Jon Medhurst96b56152014-10-30 18:01:15 +000077 length1 = mSize - readPos;
78 length2 = commitPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010079 }
80
81 logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
82
83 // start, middle or end
84 if (length1 > 0) {
85 sender->writeData(buffer1, length1, RESPONSE_APC_DATA);
86 }
87
88 // possible wrap around
89 if (length2 > 0) {
90 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
91 }
92
Jon Medhurst96b56152014-10-30 18:01:15 +000093 mReadPos = commitPos;
94
95 // send a notification that space is available
96 sem_post(&mWriterSem);
Jon Medhurstaaf37a32013-06-11 12:10:56 +010097}
98
Jon Medhurst15ce78d2014-04-10 09:02:02 +010099bool Buffer::commitReady() const {
100 return mCommitPos != mReadPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100101}
102
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100103int Buffer::bytesAvailable() const {
104 int filled = mWritePos - mReadPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100105 if (filled < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100106 filled += mSize;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100107 }
108
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100109 int remaining = mSize - filled;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100110
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100111 if (mAvailable) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100112 // Give some extra room; also allows space to insert the overflow error packet
113 remaining -= 200;
114 } else {
115 // Hysteresis, prevents multiple overflow messages
116 remaining -= 2000;
117 }
118
119 return remaining;
120}
121
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100122bool Buffer::checkSpace(const int bytes) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100123 const int remaining = bytesAvailable();
124
125 if (remaining < bytes) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100126 mAvailable = false;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100127 } else {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100128 mAvailable = true;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100129 }
130
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100131 return mAvailable;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100132}
133
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100134int Buffer::contiguousSpaceAvailable() const {
135 int remaining = bytesAvailable();
136 int contiguous = mSize - mWritePos;
137 if (remaining < contiguous) {
138 return remaining;
139 } else {
140 return contiguous;
141 }
142}
143
144void Buffer::commit(const uint64_t time) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100145 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
146 const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100147 int length = mWritePos - mCommitPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100148 if (length < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100149 length += mSize;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100150 }
151 length = length - typeLength - sizeof(int32_t);
152 for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100153 mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100154 }
155
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100156 logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
157 mCommitPos = mWritePos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100158
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100159 if (gSessionData->mLiveRate > 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100160 while (time > mCommitTime) {
161 mCommitTime += gSessionData->mLiveRate;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100162 }
163 }
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100164
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100165 if (!mIsDone) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100166 frame();
167 }
168
169 // send a notification that data is ready
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100170 sem_post(mReaderSem);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100171}
172
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100173void Buffer::check(const uint64_t time) {
174 int filled = mWritePos - mCommitPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100175 if (filled < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100176 filled += mSize;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100177 }
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100178 if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100179 commit(time);
180 }
181}
182
Jon Medhurste31266f2014-08-04 15:47:44 +0100183void Buffer::packInt(char *const buf, const int size, int &writePos, int32_t x) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100184 int packedBytes = 0;
185 int more = true;
186 while (more) {
187 // low order 7 bits of x
188 char b = x & 0x7f;
189 x >>= 7;
190
191 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
192 more = false;
193 } else {
194 b |= 0x80;
195 }
196
Jon Medhurste31266f2014-08-04 15:47:44 +0100197 buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100198 packedBytes++;
199 }
200
Jon Medhurste31266f2014-08-04 15:47:44 +0100201 writePos = (writePos + packedBytes) & /*mask*/(size - 1);
202}
203
204void Buffer::packInt(int32_t x) {
205 packInt(mBuf, mSize, mWritePos, x);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100206}
207
Jon Medhurst96b56152014-10-30 18:01:15 +0000208void Buffer::packInt64(char *const buf, const int size, int &writePos, int64_t x) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100209 int packedBytes = 0;
210 int more = true;
211 while (more) {
212 // low order 7 bits of x
213 char b = x & 0x7f;
214 x >>= 7;
215
216 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
217 more = false;
218 } else {
219 b |= 0x80;
220 }
221
Jon Medhurst96b56152014-10-30 18:01:15 +0000222 buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100223 packedBytes++;
224 }
225
Jon Medhurst96b56152014-10-30 18:01:15 +0000226 writePos = (writePos + packedBytes) & /*mask*/(size - 1);
227}
228
229void Buffer::packInt64(int64_t x) {
230 packInt64(mBuf, mSize, mWritePos, x);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100231}
232
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100233void Buffer::writeBytes(const void *const data, size_t count) {
234 size_t i;
235 for (i = 0; i < count; ++i) {
236 mBuf[(mWritePos + i) & mask] = static_cast<const char *>(data)[i];
237 }
238
239 mWritePos = (mWritePos + i) & mask;
240}
241
242void Buffer::writeString(const char *const str) {
243 const int len = strlen(str);
244 packInt(len);
245 writeBytes(str, len);
246}
247
248void Buffer::frame() {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100249 if (!gSessionData->mLocalCapture) {
250 packInt(RESPONSE_APC_DATA);
251 }
252 // Reserve space for the length
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100253 mWritePos += sizeof(int32_t);
254 packInt(mBufType);
Jon Medhurst96b56152014-10-30 18:01:15 +0000255 if ((mBufType == FRAME_BLOCK_COUNTER) || (mBufType == FRAME_PERF_ATTRS) || (mBufType == FRAME_PERF)) {
256 packInt(mCore);
257 }
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100258}
259
Jon Medhurst96b56152014-10-30 18:01:15 +0000260void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100261 packInt(MESSAGE_SUMMARY);
262 writeString(NEWLINE_CANARY);
263 packInt64(timestamp);
264 packInt64(uptime);
265 packInt64(monotonicDelta);
266 writeString("uname");
267 writeString(uname);
268 writeString("");
Jon Medhurst96b56152014-10-30 18:01:15 +0000269 check(currTime);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100270}
271
Jon Medhurst96b56152014-10-30 18:01:15 +0000272void Buffer::coreName(const uint64_t currTime, const int core, const int cpuid, const char *const name) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100273 if (checkSpace(3 * MAXSIZE_PACK32 + 0x100)) {
274 packInt(MESSAGE_CORE_NAME);
275 packInt(core);
276 packInt(cpuid);
277 writeString(name);
278 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000279 check(currTime);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100280}
281
282bool Buffer::eventHeader(const uint64_t curr_time) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100283 bool retval = false;
284 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
Jon Medhurst96b56152014-10-30 18:01:15 +0000285 // key of zero indicates a timestamp
286 packInt(0);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100287 packInt64(curr_time);
288 retval = true;
289 }
290
291 return retval;
292}
293
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100294bool Buffer::eventTid(const int tid) {
Jon Medhurst34d97692013-12-19 09:23:06 +0000295 bool retval = false;
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100296 if (checkSpace(2 * MAXSIZE_PACK32)) {
Jon Medhurst96b56152014-10-30 18:01:15 +0000297 // key of 1 indicates a tid
298 packInt(1);
Jon Medhurst34d97692013-12-19 09:23:06 +0000299 packInt(tid);
300 retval = true;
301 }
302
303 return retval;
304}
305
Jon Medhurst96b56152014-10-30 18:01:15 +0000306void Buffer::event(const int key, const int32_t value) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100307 if (checkSpace(2 * MAXSIZE_PACK32)) {
308 packInt(key);
309 packInt(value);
310 }
311}
312
Jon Medhurst96b56152014-10-30 18:01:15 +0000313void Buffer::event64(const int key, const int64_t value) {
314 if (checkSpace(MAXSIZE_PACK64 + MAXSIZE_PACK32)) {
315 packInt(key);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100316 packInt64(value);
317 }
318}
319
Jon Medhurst96b56152014-10-30 18:01:15 +0000320void Buffer::pea(const uint64_t currTime, const struct perf_event_attr *const pea, int key) {
321 while (!checkSpace(2 * MAXSIZE_PACK32 + pea->size)) {
322 sem_wait(&mWriterSem);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100323 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000324 packInt(CODE_PEA);
325 writeBytes(pea, pea->size);
326 packInt(key);
327 check(currTime);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100328}
329
Jon Medhurst96b56152014-10-30 18:01:15 +0000330void Buffer::keys(const uint64_t currTime, const int count, const __u64 *const ids, const int *const keys) {
331 while (!checkSpace(2 * MAXSIZE_PACK32 + count * (MAXSIZE_PACK32 + MAXSIZE_PACK64))) {
332 sem_wait(&mWriterSem);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100333 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000334 packInt(CODE_KEYS);
335 packInt(count);
336 for (int i = 0; i < count; ++i) {
337 packInt64(ids[i]);
338 packInt(keys[i]);
339 }
340 check(currTime);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100341}
342
Jon Medhurst96b56152014-10-30 18:01:15 +0000343void Buffer::keysOld(const uint64_t currTime, const int keyCount, const int *const keys, const int bytes, const char *const buf) {
344 while (!checkSpace((2 + keyCount) * MAXSIZE_PACK32 + bytes)) {
345 sem_wait(&mWriterSem);
Jon Medhurste31266f2014-08-04 15:47:44 +0100346 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000347 packInt(CODE_KEYS_OLD);
348 packInt(keyCount);
349 for (int i = 0; i < keyCount; ++i) {
350 packInt(keys[i]);
351 }
352 writeBytes(buf, bytes);
353 check(currTime);
Jon Medhurste31266f2014-08-04 15:47:44 +0100354}
355
Jon Medhurst96b56152014-10-30 18:01:15 +0000356void Buffer::format(const uint64_t currTime, const int length, const char *const format) {
357 while (!checkSpace(MAXSIZE_PACK32 + length + 1)) {
358 sem_wait(&mWriterSem);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100359 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000360 packInt(CODE_FORMAT);
361 writeBytes(format, length + 1);
362 check(currTime);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100363}
364
Jon Medhurst96b56152014-10-30 18:01:15 +0000365void Buffer::maps(const uint64_t currTime, const int pid, const int tid, const char *const maps) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100366 const int mapsLen = strlen(maps) + 1;
Jon Medhurst96b56152014-10-30 18:01:15 +0000367 while (!checkSpace(3 * MAXSIZE_PACK32 + mapsLen)) {
368 sem_wait(&mWriterSem);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100369 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000370 packInt(CODE_MAPS);
371 packInt(pid);
372 packInt(tid);
373 writeBytes(maps, mapsLen);
374 check(currTime);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100375}
376
Jon Medhurst96b56152014-10-30 18:01:15 +0000377void Buffer::comm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100378 const int imageLen = strlen(image) + 1;
379 const int commLen = strlen(comm) + 1;
Jon Medhurst96b56152014-10-30 18:01:15 +0000380 while (!checkSpace(3 * MAXSIZE_PACK32 + imageLen + commLen)) {
381 sem_wait(&mWriterSem);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100382 }
Jon Medhurst96b56152014-10-30 18:01:15 +0000383 packInt(CODE_COMM);
384 packInt(pid);
385 packInt(tid);
386 writeBytes(image, imageLen);
387 writeBytes(comm, commLen);
388 check(currTime);
389}
390
391void Buffer::onlineCPU(const uint64_t currTime, const uint64_t time, const int cpu) {
392 while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
393 sem_wait(&mWriterSem);
394 }
395 packInt(CODE_ONLINE_CPU);
396 packInt64(time);
397 packInt(cpu);
398 check(currTime);
399}
400
401void Buffer::offlineCPU(const uint64_t currTime, const uint64_t time, const int cpu) {
402 while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
403 sem_wait(&mWriterSem);
404 }
405 packInt(CODE_OFFLINE_CPU);
406 packInt64(time);
407 packInt(cpu);
408 check(currTime);
409}
410
411void Buffer::kallsyms(const uint64_t currTime, const char *const kallsyms) {
412 const int kallsymsLen = strlen(kallsyms) + 1;
413 while (!checkSpace(3 * MAXSIZE_PACK32 + kallsymsLen)) {
414 sem_wait(&mWriterSem);
415 }
416 packInt(CODE_KALLSYMS);
417 writeBytes(kallsyms, kallsymsLen);
418 check(currTime);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100419}
420
421void Buffer::setDone() {
422 mIsDone = true;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100423 commit(0);
424}
425
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100426bool Buffer::isDone() const {
427 return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100428}