* This private method does most of the work for both printToLog and * getTrace. * * \param buffers * Contains one or more TimeTrace::Buffers, whose contents will be merged * in the resulting output. Note: some of the buffers may extend * farther back in time than others. The output will cover only the * time period covered by *all* of the traces, ignoring older entries
| 211 | * time trace. If NULL, the trace will be printed on the system log. |
| 212 | */ |
| 213 | void |
| 214 | TimeTrace::printInternal(std::vector<TimeTrace::Buffer*>* buffers, string* s) |
| 215 | { |
| 216 | bool printedAnything = false; |
| 217 | for (uint32_t i = 0; i < buffers->size(); i++) { |
| 218 | buffers->at(i)->activeReaders.add(1); |
| 219 | } |
| 220 | |
| 221 | // Initialize file for writing |
| 222 | FILE* output = NULL; |
| 223 | if (s == NULL) |
| 224 | output = filename ? fopen(filename, "a") : stdout; |
| 225 | |
| 226 | // Holds the index of the next event to consider from each trace. |
| 227 | std::vector<int> current; |
| 228 | |
| 229 | // Find the first (oldest) event in each trace. This will be events[0] |
| 230 | // if we never completely filled the buffer, otherwise events[nextIndex+1]. |
| 231 | // This means we don't print the entry at nextIndex; this is convenient |
| 232 | // because it simplifies boundary conditions in the code below. |
| 233 | for (uint32_t i = 0; i < buffers->size(); i++) { |
| 234 | TimeTrace::Buffer* buffer = buffers->at(i); |
| 235 | int index = (buffer->nextIndex + 1) % Buffer::BUFFER_SIZE; |
| 236 | if (buffer->events[index].format != NULL) { |
| 237 | current.push_back(index); |
| 238 | } else { |
| 239 | current.push_back(0); |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | // Decide on the time of the first event to be included in the output. |
| 244 | // This is most recent of the oldest times in all the traces (an empty |
| 245 | // trace has an "oldest time" of 0). The idea here is to make sure |
| 246 | // that there's no missing data in what we print (if trace A goes back |
| 247 | // farther than trace B, skip the older events in trace A, since there |
| 248 | // might have been related events that were once in trace B but have since |
| 249 | // been overwritten). |
| 250 | uint64_t startTime = 0; |
| 251 | for (uint32_t i = 0; i < buffers->size(); i++) { |
| 252 | Event* event = &buffers->at(i)->events[current[i]]; |
| 253 | if ((event->format != NULL) && (event->timestamp > startTime)) { |
| 254 | startTime = event->timestamp; |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | // Skip all events before the starting time. |
| 259 | for (uint32_t i = 0; i < buffers->size(); i++) { |
| 260 | TimeTrace::Buffer* buffer = buffers->at(i); |
| 261 | while ((buffer->events[current[i]].format != NULL) && |
| 262 | (buffer->events[current[i]].timestamp < startTime) && |
| 263 | (current[i] != buffer->nextIndex)) { |
| 264 | current[i] = (current[i] + 1) % Buffer::BUFFER_SIZE; |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | // Each iteration through this loop processes one event (the one with |
| 269 | // the earliest timestamp). |
| 270 | double prevTime = 0.0; |