gator: Version 5.19
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / Buffer.cpp
1 /**
2  * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3  *
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
15 #define mask (mSize - 1)
16
17 enum {
18         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 };
25
26 // Summary Frame Messages
27 enum {
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
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");
48                 handleException();
49         }
50         frame();
51 }
52
53 Buffer::~Buffer() {
54         delete [] mBuf;
55 }
56
57 void Buffer::write(Sender *const sender) {
58         if (!commitReady()) {
59                 return;
60         }
61
62         // determine the size of two halves
63         int length1 = mCommitPos - mReadPos;
64         char *buffer1 = mBuf + mReadPos;
65         int length2 = 0;
66         char *buffer2 = mBuf;
67         if (length1 < 0) {
68                 length1 = mSize - mReadPos;
69                 length2 = mCommitPos;
70         }
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
84         mReadPos = mCommitPos;
85 }
86
87 bool Buffer::commitReady() const {
88         return mCommitPos != mReadPos;
89 }
90
91 int Buffer::bytesAvailable() const {
92         int filled = mWritePos - mReadPos;
93         if (filled < 0) {
94                 filled += mSize;
95         }
96
97         int remaining = mSize - filled;
98
99         if (mAvailable) {
100                 // 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
110 bool Buffer::checkSpace(const int bytes) {
111         const int remaining = bytesAvailable();
112
113         if (remaining < bytes) {
114                 mAvailable = false;
115         } else {
116                 mAvailable = true;
117         }
118
119         return mAvailable;
120 }
121
122 int 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
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;
136         if (length < 0) {
137                 length += mSize;
138         }
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;
142         }
143
144         logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
145         mCommitPos = mWritePos;
146
147         if (gSessionData->mLiveRate > 0) {
148                 while (time > mCommitTime) {
149                         mCommitTime += gSessionData->mLiveRate;
150                 }
151         }
152
153         if (!mIsDone) {
154                 frame();
155         }
156
157         // send a notification that data is ready
158         sem_post(mReaderSem);
159 }
160
161 void Buffer::check(const uint64_t time) {
162         int filled = mWritePos - mCommitPos;
163         if (filled < 0) {
164                 filled += mSize;
165         }
166         if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
167                 commit(time);
168         }
169 }
170
171 void Buffer::packInt(char *const buf, const int size, int &writePos, int32_t x) {
172         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
185                 buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b;
186                 packedBytes++;
187         }
188
189         writePos = (writePos + packedBytes) & /*mask*/(size - 1);
190 }
191
192 void Buffer::packInt(int32_t x) {
193         packInt(mBuf, mSize, mWritePos, x);
194 }
195
196 void Buffer::packInt64(int64_t x) {
197         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
210                 mBuf[(mWritePos + packedBytes) & mask] = b;
211                 packedBytes++;
212         }
213
214         mWritePos = (mWritePos + packedBytes) & mask;
215 }
216
217 void 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
226 void Buffer::writeString(const char *const str) {
227         const int len = strlen(str);
228         packInt(len);
229         writeBytes(str, len);
230 }
231
232 void Buffer::frame() {
233         if (!gSessionData->mLocalCapture) {
234                 packInt(RESPONSE_APC_DATA);
235         }
236         // Reserve space for the length
237         mWritePos += sizeof(int32_t);
238         packInt(mBufType);
239         packInt(mCore);
240 }
241
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);
246         packInt64(uptime);
247         packInt64(monotonicDelta);
248         writeString("uname");
249         writeString(uname);
250         writeString("");
251         check(1);
252 }
253
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);
257                 packInt(core);
258                 packInt(cpuid);
259                 writeString(name);
260         }
261         check(1);
262 }
263
264 bool Buffer::eventHeader(const uint64_t curr_time) {
265         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
275 bool Buffer::eventTid(const int tid) {
276         bool retval = false;
277         if (checkSpace(2 * MAXSIZE_PACK32)) {
278                 packInt(1);     // key of 1 indicates a tid
279                 packInt(tid);
280                 retval = true;
281         }
282
283         return retval;
284 }
285
286 void Buffer::event(const int32_t key, const int32_t value) {
287         if (checkSpace(2 * MAXSIZE_PACK32)) {
288                 packInt(key);
289                 packInt(value);
290         }
291 }
292
293 void Buffer::event64(const int64_t key, const int64_t value) {
294         if (checkSpace(2 * MAXSIZE_PACK64)) {
295                 packInt64(key);
296                 packInt64(value);
297         }
298 }
299
300 void 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
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))) {
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
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);
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
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);
347         } else {
348                 logg->logError(__FILE__, __LINE__, "Ran out of buffer space for perf attrs");
349                 handleException();
350         }
351         check(1);
352 }
353
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)) {
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
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)) {
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
384 void Buffer::setDone() {
385         mIsDone = true;
386         commit(0);
387 }
388
389 bool Buffer::isDone() const {
390         return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;
391 }