2 * Copyright (C) ARM Limited 2013-2014. All rights reserved.
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.
13 #include "SessionData.h"
15 #define mask (mSize - 1)
29 // Summary Frame Messages
32 MESSAGE_CORE_NAME = 3,
35 // From gator_marshaling.c
36 #define NEWLINE_CANARY \
45 /* Add another character so the length isn't 0x0a bytes */ \
48 Buffer::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) {
49 if ((mSize & mask) != 0) {
50 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
53 sem_init(&mWriterSem, 0, 0);
59 sem_destroy(&mWriterSem);
62 void Buffer::write(Sender *const sender) {
67 // commit and read are updated by the writer, only read them once
68 int commitPos = mCommitPos;
69 int readPos = mReadPos;
71 // determine the size of two halves
72 int length1 = commitPos - readPos;
73 char *buffer1 = mBuf + readPos;
77 length1 = mSize - readPos;
81 logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
83 // start, middle or end
85 sender->writeData(buffer1, length1, RESPONSE_APC_DATA);
88 // possible wrap around
90 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
95 // send a notification that space is available
96 sem_post(&mWriterSem);
99 bool Buffer::commitReady() const {
100 return mCommitPos != mReadPos;
103 int Buffer::bytesAvailable() const {
104 int filled = mWritePos - mReadPos;
109 int remaining = mSize - filled;
112 // Give some extra room; also allows space to insert the overflow error packet
115 // Hysteresis, prevents multiple overflow messages
122 bool Buffer::checkSpace(const int bytes) {
123 const int remaining = bytesAvailable();
125 if (remaining < bytes) {
134 int Buffer::contiguousSpaceAvailable() const {
135 int remaining = bytesAvailable();
136 int contiguous = mSize - mWritePos;
137 if (remaining < contiguous) {
144 void Buffer::commit(const uint64_t time) {
145 // 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;
147 int length = mWritePos - mCommitPos;
151 length = length - typeLength - sizeof(int32_t);
152 for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
153 mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
156 logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
157 mCommitPos = mWritePos;
159 if (gSessionData->mLiveRate > 0) {
160 while (time > mCommitTime) {
161 mCommitTime += gSessionData->mLiveRate;
169 // send a notification that data is ready
170 sem_post(mReaderSem);
173 void Buffer::check(const uint64_t time) {
174 int filled = mWritePos - mCommitPos;
178 if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
183 void Buffer::packInt(char *const buf, const int size, int &writePos, int32_t x) {
187 // low order 7 bits of x
191 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
197 buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b;
201 writePos = (writePos + packedBytes) & /*mask*/(size - 1);
204 void Buffer::packInt(int32_t x) {
205 packInt(mBuf, mSize, mWritePos, x);
208 void Buffer::packInt64(char *const buf, const int size, int &writePos, int64_t x) {
212 // low order 7 bits of x
216 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
222 buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b;
226 writePos = (writePos + packedBytes) & /*mask*/(size - 1);
229 void Buffer::packInt64(int64_t x) {
230 packInt64(mBuf, mSize, mWritePos, x);
233 void Buffer::writeBytes(const void *const data, size_t count) {
235 for (i = 0; i < count; ++i) {
236 mBuf[(mWritePos + i) & mask] = static_cast<const char *>(data)[i];
239 mWritePos = (mWritePos + i) & mask;
242 void Buffer::writeString(const char *const str) {
243 const int len = strlen(str);
245 writeBytes(str, len);
248 void Buffer::frame() {
249 if (!gSessionData->mLocalCapture) {
250 packInt(RESPONSE_APC_DATA);
252 // Reserve space for the length
253 mWritePos += sizeof(int32_t);
255 if ((mBufType == FRAME_BLOCK_COUNTER) || (mBufType == FRAME_PERF_ATTRS) || (mBufType == FRAME_PERF)) {
260 void Buffer::summary(const uint64_t currTime, const int64_t timestamp, const int64_t uptime, const int64_t monotonicDelta, const char *const uname) {
261 packInt(MESSAGE_SUMMARY);
262 writeString(NEWLINE_CANARY);
263 packInt64(timestamp);
265 packInt64(monotonicDelta);
266 writeString("uname");
272 void Buffer::coreName(const uint64_t currTime, const int core, const int cpuid, const char *const name) {
273 if (checkSpace(3 * MAXSIZE_PACK32 + 0x100)) {
274 packInt(MESSAGE_CORE_NAME);
282 bool Buffer::eventHeader(const uint64_t curr_time) {
284 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
285 // key of zero indicates a timestamp
287 packInt64(curr_time);
294 bool Buffer::eventTid(const int tid) {
296 if (checkSpace(2 * MAXSIZE_PACK32)) {
297 // key of 1 indicates a tid
306 void Buffer::event(const int key, const int32_t value) {
307 if (checkSpace(2 * MAXSIZE_PACK32)) {
313 void Buffer::event64(const int key, const int64_t value) {
314 if (checkSpace(MAXSIZE_PACK64 + MAXSIZE_PACK32)) {
320 void 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);
325 writeBytes(pea, pea->size);
330 void 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);
336 for (int i = 0; i < count; ++i) {
343 void 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);
347 packInt(CODE_KEYS_OLD);
349 for (int i = 0; i < keyCount; ++i) {
352 writeBytes(buf, bytes);
356 void Buffer::format(const uint64_t currTime, const int length, const char *const format) {
357 while (!checkSpace(MAXSIZE_PACK32 + length + 1)) {
358 sem_wait(&mWriterSem);
360 packInt(CODE_FORMAT);
361 writeBytes(format, length + 1);
365 void Buffer::maps(const uint64_t currTime, const int pid, const int tid, const char *const maps) {
366 const int mapsLen = strlen(maps) + 1;
367 while (!checkSpace(3 * MAXSIZE_PACK32 + mapsLen)) {
368 sem_wait(&mWriterSem);
373 writeBytes(maps, mapsLen);
377 void Buffer::comm(const uint64_t currTime, const int pid, const int tid, const char *const image, const char *const comm) {
378 const int imageLen = strlen(image) + 1;
379 const int commLen = strlen(comm) + 1;
380 while (!checkSpace(3 * MAXSIZE_PACK32 + imageLen + commLen)) {
381 sem_wait(&mWriterSem);
386 writeBytes(image, imageLen);
387 writeBytes(comm, commLen);
391 void Buffer::onlineCPU(const uint64_t currTime, const uint64_t time, const int cpu) {
392 while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
393 sem_wait(&mWriterSem);
395 packInt(CODE_ONLINE_CPU);
401 void Buffer::offlineCPU(const uint64_t currTime, const uint64_t time, const int cpu) {
402 while (!checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
403 sem_wait(&mWriterSem);
405 packInt(CODE_OFFLINE_CPU);
411 void 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);
416 packInt(CODE_KALLSYMS);
417 writeBytes(kallsyms, kallsymsLen);
421 void Buffer::setDone() {
426 bool Buffer::isDone() const {
427 return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;