090a71553277b6ab74073552c106a627688b2588
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / Buffer.cpp
1 /**
2  * Copyright (C) ARM Limited 2013. 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 (size - 1)
16
17 Buffer::Buffer (const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : core(core), buftype(buftype), size(size), readPos(0), writePos(0), commitPos(0), available(true), done(false), buf(new char[size]), commitTime(gSessionData->mLiveRate), readerSem(readerSem) {
18         if ((size & mask) != 0) {
19                 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
20                 handleException();
21         }
22         frame();
23 }
24
25 Buffer::~Buffer () {
26         delete [] buf;
27 }
28
29 void Buffer::write (Sender * const sender) {
30         if (!commitReady()) {
31                 return;
32         }
33
34         // determine the size of two halves
35         int length1 = commitPos - readPos;
36         char * buffer1 = buf + readPos;
37         int length2 = 0;
38         char * buffer2 = buf;
39         if (length1 < 0) {
40                 length1 = size - readPos;
41                 length2 = commitPos;
42         }
43
44         logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
45
46         // start, middle or end
47         if (length1 > 0) {
48                 sender->writeData(buffer1, length1, RESPONSE_APC_DATA);
49         }
50
51         // possible wrap around
52         if (length2 > 0) {
53                 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
54         }
55
56         readPos = commitPos;
57 }
58
59 bool Buffer::commitReady () const {
60         return commitPos != readPos;
61 }
62
63 int Buffer::bytesAvailable () const {
64         int filled = writePos - readPos;
65         if (filled < 0) {
66                 filled += size;
67         }
68
69         int remaining = size - filled;
70
71         if (available) {
72                 // Give some extra room; also allows space to insert the overflow error packet
73                 remaining -= 200;
74         } else {
75                 // Hysteresis, prevents multiple overflow messages
76                 remaining -= 2000;
77         }
78
79         return remaining;
80 }
81
82 bool Buffer::checkSpace (const int bytes) {
83         const int remaining = bytesAvailable();
84
85         if (remaining < bytes) {
86                 available = false;
87         } else {
88                 available = true;
89         }
90
91         return available;
92 }
93
94 void Buffer::commit (const uint64_t time) {
95         // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
96         const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
97         int length = writePos - commitPos;
98         if (length < 0) {
99                 length += size;
100         }
101         length = length - typeLength - sizeof(int32_t);
102         for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
103                 buf[(commitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
104         }
105
106         logg->logMessage("Committing data readPos: %i writePos: %i commitPos: %i", readPos, writePos, commitPos);
107         commitPos = writePos;
108
109         if (gSessionData->mLiveRate > 0) {
110                 while (time > commitTime) {
111                         commitTime += gSessionData->mLiveRate;
112                 }
113         }
114
115         if (!done) {
116                 frame();
117         }
118
119         // send a notification that data is ready
120         sem_post(readerSem);
121 }
122
123 void Buffer::check (const uint64_t time) {
124         int filled = writePos - commitPos;
125         if (filled < 0) {
126                 filled += size;
127         }
128         if (filled >= ((size * 3) / 4) || (gSessionData->mLiveRate > 0 && time >= commitTime)) {
129                 commit(time);
130         }
131 }
132
133 void Buffer::packInt (int32_t x) {
134         int packedBytes = 0;
135         int more = true;
136         while (more) {
137                 // low order 7 bits of x
138                 char b = x & 0x7f;
139                 x >>= 7;
140
141                 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
142                         more = false;
143                 } else {
144                         b |= 0x80;
145                 }
146
147                 buf[(writePos + packedBytes) & mask] = b;
148                 packedBytes++;
149         }
150
151         writePos = (writePos + packedBytes) & mask;
152 }
153
154 void Buffer::packInt64 (int64_t x) {
155         int packedBytes = 0;
156         int more = true;
157         while (more) {
158                 // low order 7 bits of x
159                 char b = x & 0x7f;
160                 x >>= 7;
161
162                 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
163                         more = false;
164                 } else {
165                         b |= 0x80;
166                 }
167
168                 buf[(writePos + packedBytes) & mask] = b;
169                 packedBytes++;
170         }
171
172         writePos = (writePos + packedBytes) & mask;
173 }
174
175 void Buffer::frame () {
176         if (!gSessionData->mLocalCapture) {
177                 packInt(RESPONSE_APC_DATA);
178         }
179         // Reserve space for the length
180         writePos += sizeof(int32_t);
181         packInt(buftype);
182         packInt(core);
183 }
184
185 bool Buffer::eventHeader (const uint64_t curr_time) {
186         bool retval = false;
187         if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
188                 packInt(0);     // key of zero indicates a timestamp
189                 packInt64(curr_time);
190                 retval = true;
191         }
192
193         return retval;
194 }
195
196 bool Buffer::eventTid (const int tid) {
197         bool retval = false;
198         if (checkSpace(2*MAXSIZE_PACK32)) {
199                 packInt(1);     // key of 1 indicates a tid
200                 packInt(tid);
201                 retval = true;
202         }
203
204         return retval;
205 }
206
207 void Buffer::event (const int32_t key, const int32_t value) {
208         if (checkSpace(2 * MAXSIZE_PACK32)) {
209                 packInt(key);
210                 packInt(value);
211         }
212 }
213
214 void Buffer::event64 (const int64_t key, const int64_t value) {
215         if (checkSpace(2 * MAXSIZE_PACK64)) {
216                 packInt64(key);
217                 packInt64(value);
218         }
219 }
220
221 void Buffer::setDone () {
222         done = true;
223         commit(0);
224 }
225
226 bool Buffer::isDone () const {
227         return done && readPos == commitPos && commitPos == writePos;
228 }