blob: dd19f7f8be76b7fb200075914b476e23554e4f2e [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 Medhurste31266f2014-08-04 15:47:44 +010018 CODE_PEA = 1,
19 CODE_KEYS = 2,
20 CODE_FORMAT = 3,
21 CODE_MAPS = 4,
22 CODE_COMM = 5,
23 CODE_KEYS_OLD = 6,
Jon Medhurst15ce78d2014-04-10 09:02:02 +010024};
25
26// Summary Frame Messages
27enum {
28 MESSAGE_SUMMARY = 1,
29 MESSAGE_CORE_NAME = 3,
30};
31
32// From gator_marshaling.c
33#define NEWLINE_CANARY \
34 /* Unix */ \
35 "1\n" \
36 /* Windows */ \
37 "2\r\n" \
38 /* Mac OS */ \
39 "3\r" \
40 /* RISC OS */ \
41 "4\n\r" \
42 /* Add another character so the length isn't 0x0a bytes */ \
43 "5"
44
45Buffer::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) {
46 if ((mSize & mask) != 0) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010047 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
48 handleException();
49 }
50 frame();
51}
52
Jon Medhurst15ce78d2014-04-10 09:02:02 +010053Buffer::~Buffer() {
54 delete [] mBuf;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010055}
56
Jon Medhurst15ce78d2014-04-10 09:02:02 +010057void Buffer::write(Sender *const sender) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010058 if (!commitReady()) {
59 return;
60 }
61
62 // determine the size of two halves
Jon Medhurst15ce78d2014-04-10 09:02:02 +010063 int length1 = mCommitPos - mReadPos;
64 char *buffer1 = mBuf + mReadPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010065 int length2 = 0;
Jon Medhurst15ce78d2014-04-10 09:02:02 +010066 char *buffer2 = mBuf;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010067 if (length1 < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +010068 length1 = mSize - mReadPos;
69 length2 = mCommitPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010070 }
71
72 logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
73
74 // start, middle or end
75 if (length1 > 0) {
76 sender->writeData(buffer1, length1, RESPONSE_APC_DATA);
77 }
78
79 // possible wrap around
80 if (length2 > 0) {
81 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
82 }
83
Jon Medhurst15ce78d2014-04-10 09:02:02 +010084 mReadPos = mCommitPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010085}
86
Jon Medhurst15ce78d2014-04-10 09:02:02 +010087bool Buffer::commitReady() const {
88 return mCommitPos != mReadPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010089}
90
Jon Medhurst15ce78d2014-04-10 09:02:02 +010091int Buffer::bytesAvailable() const {
92 int filled = mWritePos - mReadPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010093 if (filled < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +010094 filled += mSize;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010095 }
96
Jon Medhurst15ce78d2014-04-10 09:02:02 +010097 int remaining = mSize - filled;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010098
Jon Medhurst15ce78d2014-04-10 09:02:02 +010099 if (mAvailable) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100100 // Give some extra room; also allows space to insert the overflow error packet
101 remaining -= 200;
102 } else {
103 // Hysteresis, prevents multiple overflow messages
104 remaining -= 2000;
105 }
106
107 return remaining;
108}
109
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100110bool Buffer::checkSpace(const int bytes) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100111 const int remaining = bytesAvailable();
112
113 if (remaining < bytes) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100114 mAvailable = false;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100115 } else {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100116 mAvailable = true;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100117 }
118
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100119 return mAvailable;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100120}
121
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100122int Buffer::contiguousSpaceAvailable() const {
123 int remaining = bytesAvailable();
124 int contiguous = mSize - mWritePos;
125 if (remaining < contiguous) {
126 return remaining;
127 } else {
128 return contiguous;
129 }
130}
131
132void Buffer::commit(const uint64_t time) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100133 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
134 const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100135 int length = mWritePos - mCommitPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100136 if (length < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100137 length += mSize;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100138 }
139 length = length - typeLength - sizeof(int32_t);
140 for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100141 mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100142 }
143
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100144 logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
145 mCommitPos = mWritePos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100146
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100147 if (gSessionData->mLiveRate > 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100148 while (time > mCommitTime) {
149 mCommitTime += gSessionData->mLiveRate;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100150 }
151 }
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100152
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100153 if (!mIsDone) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100154 frame();
155 }
156
157 // send a notification that data is ready
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100158 sem_post(mReaderSem);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100159}
160
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100161void Buffer::check(const uint64_t time) {
162 int filled = mWritePos - mCommitPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100163 if (filled < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100164 filled += mSize;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100165 }
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100166 if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100167 commit(time);
168 }
169}
170
Jon Medhurste31266f2014-08-04 15:47:44 +0100171void Buffer::packInt(char *const buf, const int size, int &writePos, int32_t x) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100172 int packedBytes = 0;
173 int more = true;
174 while (more) {
175 // low order 7 bits of x
176 char b = x & 0x7f;
177 x >>= 7;
178
179 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
180 more = false;
181 } else {
182 b |= 0x80;
183 }
184
Jon Medhurste31266f2014-08-04 15:47:44 +0100185 buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100186 packedBytes++;
187 }
188
Jon Medhurste31266f2014-08-04 15:47:44 +0100189 writePos = (writePos + packedBytes) & /*mask*/(size - 1);
190}
191
192void Buffer::packInt(int32_t x) {
193 packInt(mBuf, mSize, mWritePos, x);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100194}
195
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100196void Buffer::packInt64(int64_t x) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100197 int packedBytes = 0;
198 int more = true;
199 while (more) {
200 // low order 7 bits of x
201 char b = x & 0x7f;
202 x >>= 7;
203
204 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
205 more = false;
206 } else {
207 b |= 0x80;
208 }
209
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100210 mBuf[(mWritePos + packedBytes) & mask] = b;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100211 packedBytes++;
212 }
213
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100214 mWritePos = (mWritePos + packedBytes) & mask;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100215}
216
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100217void Buffer::writeBytes(const void *const data, size_t count) {
218 size_t i;
219 for (i = 0; i < count; ++i) {
220 mBuf[(mWritePos + i) & mask] = static_cast<const char *>(data)[i];
221 }
222
223 mWritePos = (mWritePos + i) & mask;
224}
225
226void Buffer::writeString(const char *const str) {
227 const int len = strlen(str);
228 packInt(len);
229 writeBytes(str, len);
230}
231
232void Buffer::frame() {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100233 if (!gSessionData->mLocalCapture) {
234 packInt(RESPONSE_APC_DATA);
235 }
236 // Reserve space for the length
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100237 mWritePos += sizeof(int32_t);
238 packInt(mBufType);
239 packInt(mCore);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100240}
241
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100242void Buffer::summary(const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
243 packInt(MESSAGE_SUMMARY);
244 writeString(NEWLINE_CANARY);
245 packInt64(timestamp);
246 packInt64(uptime);
247 packInt64(monotonicDelta);
248 writeString("uname");
249 writeString(uname);
250 writeString("");
251 check(1);
252}
253
254void Buffer::coreName(const int core, const int cpuid, const char *const name) {
255 if (checkSpace(3 * MAXSIZE_PACK32 + 0x100)) {
256 packInt(MESSAGE_CORE_NAME);
257 packInt(core);
258 packInt(cpuid);
259 writeString(name);
260 }
261 check(1);
262}
263
264bool Buffer::eventHeader(const uint64_t curr_time) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100265 bool retval = false;
266 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
267 packInt(0); // key of zero indicates a timestamp
268 packInt64(curr_time);
269 retval = true;
270 }
271
272 return retval;
273}
274
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100275bool Buffer::eventTid(const int tid) {
Jon Medhurst34d97692013-12-19 09:23:06 +0000276 bool retval = false;
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100277 if (checkSpace(2 * MAXSIZE_PACK32)) {
Jon Medhurst34d97692013-12-19 09:23:06 +0000278 packInt(1); // key of 1 indicates a tid
279 packInt(tid);
280 retval = true;
281 }
282
283 return retval;
284}
285
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100286void Buffer::event(const int32_t key, const int32_t value) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100287 if (checkSpace(2 * MAXSIZE_PACK32)) {
288 packInt(key);
289 packInt(value);
290 }
291}
292
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100293void Buffer::event64(const int64_t key, const int64_t value) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100294 if (checkSpace(2 * MAXSIZE_PACK64)) {
295 packInt64(key);
296 packInt64(value);
297 }
298}
299
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100300void Buffer::pea(const struct perf_event_attr *const pea, int key) {
301 if (checkSpace(2 * MAXSIZE_PACK32 + pea->size)) {
302 packInt(CODE_PEA);
303 writeBytes(pea, pea->size);
304 packInt(key);
305 } else {
306 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
307 handleException();
308 }
309 // Don't know the real perf time so use 1 as it will work for now
310 check(1);
311}
312
313void Buffer::keys(const int count, const __u64 *const ids, const int *const keys) {
314 if (checkSpace(2 * MAXSIZE_PACK32 + count * (MAXSIZE_PACK32 + MAXSIZE_PACK64))) {
315 packInt(CODE_KEYS);
316 packInt(count);
317 for (int i = 0; i < count; ++i) {
318 packInt64(ids[i]);
319 packInt(keys[i]);
320 }
321 } else {
322 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
323 handleException();
324 }
325 check(1);
326}
327
Jon Medhurste31266f2014-08-04 15:47:44 +0100328void Buffer::keysOld(const int keyCount, const int *const keys, const int bytes, const char *const buf) {
329 if (checkSpace((2 + keyCount) * MAXSIZE_PACK32 + bytes)) {
330 packInt(CODE_KEYS_OLD);
331 packInt(keyCount);
332 for (int i = 0; i < keyCount; ++i) {
333 packInt(keys[i]);
334 }
335 writeBytes(buf, bytes);
336 } else {
337 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
338 handleException();
339 }
340 check(1);
341}
342
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100343void Buffer::format(const int length, const char *const format) {
344 if (checkSpace(MAXSIZE_PACK32 + length + 1)) {
345 packInt(CODE_FORMAT);
346 writeBytes(format, length + 1);
347 } else {
348 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
349 handleException();
350 }
351 check(1);
352}
353
354void Buffer::maps(const int pid, const int tid, const char *const maps) {
355 const int mapsLen = strlen(maps) + 1;
356 if (checkSpace(3 * MAXSIZE_PACK32 + mapsLen)) {
357 packInt(CODE_MAPS);
358 packInt(pid);
359 packInt(tid);
360 writeBytes(maps, mapsLen);
361 } else {
362 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
363 handleException();
364 }
365 check(1);
366}
367
368void Buffer::comm(const int pid, const int tid, const char *const image, const char *const comm) {
369 const int imageLen = strlen(image) + 1;
370 const int commLen = strlen(comm) + 1;
371 if (checkSpace(3 * MAXSIZE_PACK32 + imageLen + commLen)) {
372 packInt(CODE_COMM);
373 packInt(pid);
374 packInt(tid);
375 writeBytes(image, imageLen);
376 writeBytes(comm, commLen);
377 } else {
378 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
379 handleException();
380 }
381 check(1);
382}
383
384void Buffer::setDone() {
385 mIsDone = true;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100386 commit(0);
387}
388
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100389bool Buffer::isDone() const {
390 return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100391}