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)
26 // Summary Frame Messages
29 MESSAGE_CORE_NAME = 3,
32 // From gator_marshaling.c
33 #define NEWLINE_CANARY \
42 /* Add another character so the length isn't 0x0a bytes */ \
45 Buffer::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) {
47 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
57 void Buffer::write(Sender *const sender) {
62 // determine the size of two halves
63 int length1 = mCommitPos - mReadPos;
64 char *buffer1 = mBuf + mReadPos;
68 length1 = mSize - mReadPos;
72 logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
74 // start, middle or end
76 sender->writeData(buffer1, length1, RESPONSE_APC_DATA);
79 // possible wrap around
81 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
84 mReadPos = mCommitPos;
87 bool Buffer::commitReady() const {
88 return mCommitPos != mReadPos;
91 int Buffer::bytesAvailable() const {
92 int filled = mWritePos - mReadPos;
97 int remaining = mSize - filled;
100 // Give some extra room; also allows space to insert the overflow error packet
103 // Hysteresis, prevents multiple overflow messages
110 bool Buffer::checkSpace(const int bytes) {
111 const int remaining = bytesAvailable();
113 if (remaining < bytes) {
122 int Buffer::contiguousSpaceAvailable() const {
123 int remaining = bytesAvailable();
124 int contiguous = mSize - mWritePos;
125 if (remaining < contiguous) {
132 void Buffer::commit(const uint64_t time) {
133 // 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;
135 int length = mWritePos - mCommitPos;
139 length = length - typeLength - sizeof(int32_t);
140 for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
141 mBuf[(mCommitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
144 logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
145 mCommitPos = mWritePos;
147 if (gSessionData->mLiveRate > 0) {
148 while (time > mCommitTime) {
149 mCommitTime += gSessionData->mLiveRate;
157 // send a notification that data is ready
158 sem_post(mReaderSem);
161 void Buffer::check(const uint64_t time) {
162 int filled = mWritePos - mCommitPos;
166 if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
171 void Buffer::packInt(char *const buf, const int size, int &writePos, int32_t x) {
175 // low order 7 bits of x
179 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
185 buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b;
189 writePos = (writePos + packedBytes) & /*mask*/(size - 1);
192 void Buffer::packInt(int32_t x) {
193 packInt(mBuf, mSize, mWritePos, x);
196 void Buffer::packInt64(int64_t x) {
200 // low order 7 bits of x
204 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
210 mBuf[(mWritePos + packedBytes) & mask] = b;
214 mWritePos = (mWritePos + packedBytes) & mask;
217 void Buffer::writeBytes(const void *const data, size_t count) {
219 for (i = 0; i < count; ++i) {
220 mBuf[(mWritePos + i) & mask] = static_cast<const char *>(data)[i];
223 mWritePos = (mWritePos + i) & mask;
226 void Buffer::writeString(const char *const str) {
227 const int len = strlen(str);
229 writeBytes(str, len);
232 void Buffer::frame() {
233 if (!gSessionData->mLocalCapture) {
234 packInt(RESPONSE_APC_DATA);
236 // Reserve space for the length
237 mWritePos += sizeof(int32_t);
242 void 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);
247 packInt64(monotonicDelta);
248 writeString("uname");
254 void Buffer::coreName(const int core, const int cpuid, const char *const name) {
255 if (checkSpace(3 * MAXSIZE_PACK32 + 0x100)) {
256 packInt(MESSAGE_CORE_NAME);
264 bool Buffer::eventHeader(const uint64_t curr_time) {
266 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
267 packInt(0); // key of zero indicates a timestamp
268 packInt64(curr_time);
275 bool Buffer::eventTid(const int tid) {
277 if (checkSpace(2 * MAXSIZE_PACK32)) {
278 packInt(1); // key of 1 indicates a tid
286 void Buffer::event(const int32_t key, const int32_t value) {
287 if (checkSpace(2 * MAXSIZE_PACK32)) {
293 void Buffer::event64(const int64_t key, const int64_t value) {
294 if (checkSpace(2 * MAXSIZE_PACK64)) {
300 void Buffer::pea(const struct perf_event_attr *const pea, int key) {
301 if (checkSpace(2 * MAXSIZE_PACK32 + pea->size)) {
303 writeBytes(pea, pea->size);
306 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
309 // Don't know the real perf time so use 1 as it will work for now
313 void Buffer::keys(const int count, const __u64 *const ids, const int *const keys) {
314 if (checkSpace(2 * MAXSIZE_PACK32 + count * (MAXSIZE_PACK32 + MAXSIZE_PACK64))) {
317 for (int i = 0; i < count; ++i) {
322 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
328 void 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);
332 for (int i = 0; i < keyCount; ++i) {
335 writeBytes(buf, bytes);
337 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
343 void 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);
348 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
354 void 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)) {
360 writeBytes(maps, mapsLen);
362 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
368 void 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)) {
375 writeBytes(image, imageLen);
376 writeBytes(comm, commLen);
378 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
384 void Buffer::setDone() {
389 bool Buffer::isDone() const {
390 return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;