| Index: runtime/vm/trace_buffer.cc
|
| diff --git a/runtime/vm/trace_buffer.cc b/runtime/vm/trace_buffer.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..831e95d6abd74a5d45a79d9ff3a807a25fb9f004
|
| --- /dev/null
|
| +++ b/runtime/vm/trace_buffer.cc
|
| @@ -0,0 +1,121 @@
|
| +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +#include "vm/json_stream.h"
|
| +#include "vm/os.h"
|
| +#include "vm/trace_buffer.h"
|
| +
|
| +namespace dart {
|
| +
|
| +TraceBuffer::TraceBuffer(intptr_t capacity) : ring_capacity_(capacity) {
|
| + ring_cursor_ = 0;
|
| + Init();
|
| +}
|
| +
|
| +
|
| +TraceBuffer::~TraceBuffer() {
|
| + ASSERT(ring_ != NULL);
|
| + Clear();
|
| + free(ring_);
|
| +}
|
| +
|
| +
|
| +void TraceBuffer::Init() {
|
| + ring_ = reinterpret_cast<TraceBufferEntry*>(
|
| + calloc(ring_capacity_, sizeof(TraceBufferEntry))); // NOLINT
|
| +}
|
| +
|
| +
|
| +void TraceBuffer::Clear() {
|
| + for (intptr_t i = 0; i < ring_capacity_; i++) {
|
| + TraceBufferEntry& entry = ring_[i];
|
| + entry.micros = 0;
|
| + free(entry.message);
|
| + entry.message = NULL;
|
| + }
|
| + ring_cursor_ = 0;
|
| +}
|
| +
|
| +
|
| +void TraceBuffer::Fill(TraceBufferEntry* entry, int64_t micros, char* msg) {
|
| + if (entry->message != NULL) {
|
| + // Recycle TraceBufferEntry.
|
| + free(entry->message);
|
| + }
|
| + entry->message = msg;
|
| + entry->micros = micros;
|
| +}
|
| +
|
| +
|
| +void TraceBuffer::AppendTrace(int64_t micros, char* message) {
|
| + const intptr_t index = ring_cursor_;
|
| + TraceBufferEntry* trace_entry = &ring_[index];
|
| + Fill(trace_entry, micros, message);
|
| + ring_cursor_ = RingIndex(ring_cursor_ + 1);
|
| +}
|
| +
|
| +
|
| +void TraceBuffer::Trace(int64_t micros, const char* message) {
|
| + ASSERT(message != NULL);
|
| + char* message_copy = strdup(message);
|
| + AppendTrace(micros, message_copy);
|
| +}
|
| +
|
| +
|
| +void TraceBuffer::Trace(const char* message) {
|
| + Trace(OS::GetCurrentTimeMicros(), message);
|
| +}
|
| +
|
| +
|
| +void TraceBuffer::TraceF(const char* format, ...) {
|
| + int64_t micros = OS::GetCurrentTimeMicros();
|
| + va_list args;
|
| + va_start(args, format);
|
| + intptr_t len = OS::VSNPrint(NULL, 0, format, args);
|
| + va_end(args);
|
| + char* p = reinterpret_cast<char*>(malloc(len+1));
|
| + va_start(args, format);
|
| + intptr_t len2 = OS::VSNPrint(p, len+1, format, args);
|
| + va_end(args);
|
| + ASSERT(len == len2);
|
| + AppendTrace(micros, p);
|
| +}
|
| +
|
| +
|
| +void TraceBuffer::PrintToJSONStream(JSONStream* stream) const {
|
| + JSONObject json_trace_buffer(stream);
|
| + json_trace_buffer.AddProperty("type", "TraceBuffer");
|
| + // TODO(johnmccutchan): Send cursor position in response.
|
| + JSONArray json_trace_buffer_array(&json_trace_buffer, "members");
|
| + // Scan forward until we find the first entry which isn't empty.
|
| + // TODO(johnmccutchan): Accept cursor start position as input.
|
| + intptr_t start = -1;
|
| + for (intptr_t i = 0; i < ring_capacity_; i++) {
|
| + intptr_t index = RingIndex(i + ring_cursor_);
|
| + if (!ring_[index].empty()) {
|
| + start = index;
|
| + break;
|
| + }
|
| + }
|
| + // No messages in trace buffer.
|
| + if (start == -1) {
|
| + return;
|
| + }
|
| + for (intptr_t i = 0; i < ring_capacity_; i++) {
|
| + intptr_t index = RingIndex(start + i);
|
| + const TraceBufferEntry& entry = ring_[index];
|
| + if (entry.empty()) {
|
| + // Empty entry, stop.
|
| + break;
|
| + }
|
| + JSONObject trace_entry(&json_trace_buffer_array);
|
| + trace_entry.AddProperty("type", "TraceBufferEntry");
|
| + double seconds = static_cast<double>(entry.micros) /
|
| + static_cast<double>(kMicrosecondsPerSecond);
|
| + trace_entry.AddProperty("time", seconds);
|
| + trace_entry.AddProperty("message", entry.message);
|
| + }
|
| +}
|
| +
|
| +} // namespace dart
|
|
|