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 |