blob: 93557dabed9f1835910243ab7cff0802ad3d38fe [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 {
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) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010046 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
47 handleException();
48 }
49 frame();
50}
51
Jon Medhurst15ce78d2014-04-10 09:02:02 +010052Buffer::~Buffer() {
53 delete [] mBuf;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010054}
55
Jon Medhurst15ce78d2014-04-10 09:02:02 +010056void Buffer::write(Sender *const sender) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010057 if (!commitReady()) {
58 return;
59 }
60
61 // determine the size of two halves
Jon Medhurst15ce78d2014-04-10 09:02:02 +010062 int length1 = mCommitPos - mReadPos;
63 char *buffer1 = mBuf + mReadPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010064 int length2 = 0;
Jon Medhurst15ce78d2014-04-10 09:02:02 +010065 char *buffer2 = mBuf;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010066 if (length1 < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +010067 length1 = mSize - mReadPos;
68 length2 = mCommitPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010069 }
70
71 logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
72
73 // start, middle or end
74 if (length1 > 0) {
75 sender->writeData(buffer1, length1, RESPONSE_APC_DATA);
76 }
77
78 // possible wrap around
79 if (length2 > 0) {
80 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
81 }
82
Jon Medhurst15ce78d2014-04-10 09:02:02 +010083 mReadPos = mCommitPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010084}
85
Jon Medhurst15ce78d2014-04-10 09:02:02 +010086bool Buffer::commitReady() const {
87 return mCommitPos != mReadPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010088}
89
Jon Medhurst15ce78d2014-04-10 09:02:02 +010090int Buffer::bytesAvailable() const {
91 int filled = mWritePos - mReadPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010092 if (filled < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +010093 filled += mSize;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010094 }
95
Jon Medhurst15ce78d2014-04-10 09:02:02 +010096 int remaining = mSize - filled;
Jon Medhurstaaf37a32013-06-11 12:10:56 +010097
Jon Medhurst15ce78d2014-04-10 09:02:02 +010098 if (mAvailable) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010099 // Give some extra room; also allows space to insert the overflow error packet
100 remaining -= 200;
101 } else {
102 // Hysteresis, prevents multiple overflow messages
103 remaining -= 2000;
104 }
105
106 return remaining;
107}
108
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100109bool Buffer::checkSpace(const int bytes) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100110 const int remaining = bytesAvailable();
111
112 if (remaining < bytes) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100113 mAvailable = false;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100114 } else {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100115 mAvailable = true;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100116 }
117
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100118 return mAvailable;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100119}
120
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100121int 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 }
129}
130
131void Buffer::commit(const uint64_t time) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100132 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
133 const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100134 int length = mWritePos - mCommitPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100135 if (length < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100136 length += mSize;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100137 }
138 length = length - typeLength - sizeof(int32_t);
139 for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100140 mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100141 }
142
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100143 logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
144 mCommitPos = mWritePos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100145
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100146 if (gSessionData->mLiveRate > 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100147 while (time > mCommitTime) {
148 mCommitTime += gSessionData->mLiveRate;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100149 }
150 }
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100151
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100152 if (!mIsDone) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100153 frame();
154 }
155
156 // send a notification that data is ready
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100157 sem_post(mReaderSem);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100158}
159
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100160void Buffer::check(const uint64_t time) {
161 int filled = mWritePos - mCommitPos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100162 if (filled < 0) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100163 filled += mSize;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100164 }
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100165 if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100166 commit(time);
167 }
168}
169
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100170void Buffer::packInt(int32_t x) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100171 int packedBytes = 0;
172 int more = true;
173 while (more) {
174 // low order 7 bits of x
175 char b = x & 0x7f;
176 x >>= 7;
177
178 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
179 more = false;
180 } else {
181 b |= 0x80;
182 }
183
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100184 mBuf[(mWritePos + packedBytes) & mask] = b;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100185 packedBytes++;
186 }
187
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100188 mWritePos = (mWritePos + packedBytes) & mask;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100189}
190
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100191void Buffer::packInt64(int64_t x) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100192 int packedBytes = 0;
193 int more = true;
194 while (more) {
195 // low order 7 bits of x
196 char b = x & 0x7f;
197 x >>= 7;
198
199 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
200 more = false;
201 } else {
202 b |= 0x80;
203 }
204
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100205 mBuf[(mWritePos + packedBytes) & mask] = b;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100206 packedBytes++;
207 }
208
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100209 mWritePos = (mWritePos + packedBytes) & mask;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100210}
211
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100212void 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;
219}
220
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() {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100228 if (!gSessionData->mLocalCapture) {
229 packInt(RESPONSE_APC_DATA);
230 }
231 // Reserve space for the length
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100232 mWritePos += sizeof(int32_t);
233 packInt(mBufType);
234 packInt(mCore);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100235}
236
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100237void 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) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100260 bool retval = false;
261 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
262 packInt(0); // key of zero indicates a timestamp
263 packInt64(curr_time);
264 retval = true;
265 }
266
267 return retval;
268}
269
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100270bool Buffer::eventTid(const int tid) {
Jon Medhurst34d97692013-12-19 09:23:06 +0000271 bool retval = false;
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100272 if (checkSpace(2 * MAXSIZE_PACK32)) {
Jon Medhurst34d97692013-12-19 09:23:06 +0000273 packInt(1); // key of 1 indicates a tid
274 packInt(tid);
275 retval = true;
276 }
277
278 return retval;
279}
280
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100281void Buffer::event(const int32_t key, const int32_t value) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100282 if (checkSpace(2 * MAXSIZE_PACK32)) {
283 packInt(key);
284 packInt(value);
285 }
286}
287
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100288void Buffer::event64(const int64_t key, const int64_t value) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100289 if (checkSpace(2 * MAXSIZE_PACK64)) {
290 packInt64(key);
291 packInt64(value);
292 }
293}
294
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100295void Buffer::pea(const struct perf_event_attr *const pea, int key) {
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;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100366 commit(0);
367}
368
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100369bool Buffer::isDone() const {
370 return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100371}