gator: Version 5.20
[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         CODE_ONLINE_CPU  = 7,
25         CODE_OFFLINE_CPU = 8,
26         CODE_KALLSYMS    = 9,
27 };
28
29 // Summary Frame Messages
30 enum {
31         MESSAGE_SUMMARY = 1,
32         MESSAGE_CORE_NAME = 3,
33 };
34
35 // From gator_marshaling.c
36 #define NEWLINE_CANARY \
37         /* Unix */ \
38         "1\n" \
39         /* Windows */ \
40         "2\r\n" \
41         /* Mac OS */ \
42         "3\r" \
43         /* RISC OS */ \
44         "4\n\r" \
45         /* Add another character so the length isn't 0x0a bytes */ \
46         "5"
47
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");
51                 handleException();
52         }
53         sem_init(&mWriterSem, 0, 0);
54         frame();
55 }
56
57 Buffer::~Buffer() {
58         delete [] mBuf;
59         sem_destroy(&mWriterSem);
60 }
61
62 void Buffer::write(Sender *const sender) {
63         if (!commitReady()) {
64                 return;
65         }
66
67         // commit and read are updated by the writer, only read them once
68         int commitPos = mCommitPos;
69         int readPos = mReadPos;
70
71         // determine the size of two halves
72         int length1 = commitPos - readPos;
73         char *buffer1 = mBuf + readPos;
74         int length2 = 0;
75         char *buffer2 = mBuf;
76         if (length1 < 0) {
77                 length1 = mSize - readPos;
78                 length2 = commitPos;
79         }
80
81         logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
82
83         // start, middle or end
84         if (length1 > 0) {
85                 sender->writeData(buffer1, length1, RESPONSE_APC_DATA);
86         }
87
88         // possible wrap around
89         if (length2 > 0) {
90                 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
91         }
92
93         mReadPos = commitPos;
94
95         // send a notification that space is available
96         sem_post(&mWriterSem);
97 }
98
99 bool Buffer::commitReady() const {
100         return mCommitPos != mReadPos;
101 }
102
103 int Buffer::bytesAvailable() const {
104         int filled = mWritePos - mReadPos;
105         if (filled < 0) {
106                 filled += mSize;
107         }
108
109         int remaining = mSize - filled;
110
111         if (mAvailable) {
112                 // Give some extra room; also allows space to insert the overflow error packet
113                 remaining -= 200;
114         } else {
115                 // Hysteresis, prevents multiple overflow messages
116                 remaining -= 2000;
117         }
118
119         return remaining;
120 }
121
122 bool Buffer::checkSpace(const int bytes) {
123         const int remaining = bytesAvailable();
124
125         if (remaining < bytes) {
126                 mAvailable = false;
127         } else {
128                 mAvailable = true;
129         }
130
131         return mAvailable;
132 }
133
134 int Buffer::contiguousSpaceAvailable() const {
135         int remaining = bytesAvailable();
136         int contiguous = mSize - mWritePos;
137         if (remaining < contiguous) {
138                 return remaining;
139         } else {
140                 return contiguous;
141         }
142 }
143
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;
148         if (length < 0) {
149                 length += mSize;
150         }
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;
154         }
155
156         logg->logMessage("Committing data mReadPos: %i mWritePos: %i mCommitPos: %i", mReadPos, mWritePos, mCommitPos);
157         mCommitPos = mWritePos;
158
159         if (gSessionData->mLiveRate > 0) {
160                 while (time > mCommitTime) {
161                         mCommitTime += gSessionData->mLiveRate;
162                 }
163         }
164
165         if (!mIsDone) {
166                 frame();
167         }
168
169         // send a notification that data is ready
170         sem_post(mReaderSem);
171 }
172
173 void Buffer::check(const uint64_t time) {
174         int filled = mWritePos - mCommitPos;
175         if (filled < 0) {
176                 filled += mSize;
177         }
178         if (filled >= ((mSize * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= mCommitTime)) {
179                 commit(time);
180         }
181 }
182
183 void Buffer::packInt(char *const buf, const int size, int &writePos, int32_t x) {
184         int packedBytes = 0;
185         int more = true;
186         while (more) {
187                 // low order 7 bits of x
188                 char b = x & 0x7f;
189                 x >>= 7;
190
191                 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
192                         more = false;
193                 } else {
194                         b |= 0x80;
195                 }
196
197                 buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b;
198                 packedBytes++;
199         }
200
201         writePos = (writePos + packedBytes) & /*mask*/(size - 1);
202 }
203
204 void Buffer::packInt(int32_t x) {
205         packInt(mBuf, mSize, mWritePos, x);
206 }
207
208 void Buffer::packInt64(char *const buf, const int size, int &writePos, int64_t x) {
209         int packedBytes = 0;
210         int more = true;
211         while (more) {
212                 // low order 7 bits of x
213                 char b = x & 0x7f;
214                 x >>= 7;
215
216                 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
217                         more = false;
218                 } else {
219                         b |= 0x80;
220                 }
221
222                 buf[(writePos + packedBytes) & /*mask*/(size - 1)] = b;
223                 packedBytes++;
224         }
225
226         writePos = (writePos + packedBytes) & /*mask*/(size - 1);
227 }
228
229 void Buffer::packInt64(int64_t x) {
230         packInt64(mBuf, mSize, mWritePos, x);
231 }
232
233 void Buffer::writeBytes(const void *const data, size_t count) {
234         size_t i;
235         for (i = 0; i < count; ++i) {
236                 mBuf[(mWritePos + i) & mask] = static_cast<const char *>(data)[i];
237         }
238
239         mWritePos = (mWritePos + i) & mask;
240 }
241
242 void Buffer::writeString(const char *const str) {
243         const int len = strlen(str);
244         packInt(len);
245         writeBytes(str, len);
246 }
247
248 void Buffer::frame() {
249         if (!gSessionData->mLocalCapture) {
250                 packInt(RESPONSE_APC_DATA);
251         }
252         // Reserve space for the length
253         mWritePos += sizeof(int32_t);
254         packInt(mBufType);
255         if ((mBufType == FRAME_BLOCK_COUNTER) || (mBufType == FRAME_PERF_ATTRS) || (mBufType == FRAME_PERF)) {
256                 packInt(mCore);
257         }
258 }
259
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);
264         packInt64(uptime);
265         packInt64(monotonicDelta);
266         writeString("uname");
267         writeString(uname);
268         writeString("");
269         check(currTime);
270 }
271
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);
275                 packInt(core);
276                 packInt(cpuid);
277                 writeString(name);
278         }
279         check(currTime);
280 }
281
282 bool Buffer::eventHeader(const uint64_t curr_time) {
283         bool retval = false;
284         if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
285                 // key of zero indicates a timestamp
286                 packInt(0);
287                 packInt64(curr_time);
288                 retval = true;
289         }
290
291         return retval;
292 }
293
294 bool Buffer::eventTid(const int tid) {
295         bool retval = false;
296         if (checkSpace(2 * MAXSIZE_PACK32)) {
297                 // key of 1 indicates a tid
298                 packInt(1);
299                 packInt(tid);
300                 retval = true;
301         }
302
303         return retval;
304 }
305
306 void Buffer::event(const int key, const int32_t value) {
307         if (checkSpace(2 * MAXSIZE_PACK32)) {
308                 packInt(key);
309                 packInt(value);
310         }
311 }
312
313 void Buffer::event64(const int key, const int64_t value) {
314         if (checkSpace(MAXSIZE_PACK64 + MAXSIZE_PACK32)) {
315                 packInt(key);
316                 packInt64(value);
317         }
318 }
319
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);
323         }
324         packInt(CODE_PEA);
325         writeBytes(pea, pea->size);
326         packInt(key);
327         check(currTime);
328 }
329
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);
333         }
334         packInt(CODE_KEYS);
335         packInt(count);
336         for (int i = 0; i < count; ++i) {
337                 packInt64(ids[i]);
338                 packInt(keys[i]);
339         }
340         check(currTime);
341 }
342
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);
346         }
347         packInt(CODE_KEYS_OLD);
348         packInt(keyCount);
349         for (int i = 0; i < keyCount; ++i) {
350                 packInt(keys[i]);
351         }
352         writeBytes(buf, bytes);
353         check(currTime);
354 }
355
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);
359         }
360         packInt(CODE_FORMAT);
361         writeBytes(format, length + 1);
362         check(currTime);
363 }
364
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);
369         }
370         packInt(CODE_MAPS);
371         packInt(pid);
372         packInt(tid);
373         writeBytes(maps, mapsLen);
374         check(currTime);
375 }
376
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);
382         }
383         packInt(CODE_COMM);
384         packInt(pid);
385         packInt(tid);
386         writeBytes(image, imageLen);
387         writeBytes(comm, commLen);
388         check(currTime);
389 }
390
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);
394         }
395         packInt(CODE_ONLINE_CPU);
396         packInt64(time);
397         packInt(cpu);
398         check(currTime);
399 }
400
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);
404         }
405         packInt(CODE_OFFLINE_CPU);
406         packInt64(time);
407         packInt(cpu);
408         check(currTime);
409 }
410
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);
415         }
416         packInt(CODE_KALLSYMS);
417         writeBytes(kallsyms, kallsymsLen);
418         check(currTime);
419 }
420
421 void Buffer::setDone() {
422         mIsDone = true;
423         commit(0);
424 }
425
426 bool Buffer::isDone() const {
427         return mIsDone && mReadPos == mCommitPos && mCommitPos == mWritePos;
428 }