Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1518)

Unified Diff: runtime/vm/timeline.cc

Issue 1170503004: Initial Timeline Events (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/timeline.h ('k') | runtime/vm/timeline_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/timeline.cc
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
new file mode 100644
index 0000000000000000000000000000000000000000..51fcd71dcbb12f29393ff1591bc83b534cbd8e5d
--- /dev/null
+++ b/runtime/vm/timeline.cc
@@ -0,0 +1,443 @@
+// Copyright (c) 2015, 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 <cstdlib>
+
+#include "vm/isolate.h"
+#include "vm/json_stream.h"
+#include "vm/object.h"
+#include "vm/thread.h"
+#include "vm/timeline.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool, trace_timeline, false, "Timeline trace");
+
+TimelineEvent::TimelineEvent()
+ : timestamp0_(0),
+ timestamp1_(0),
+ arguments_(NULL),
+ arguments_length_(0),
+ state_(0),
+ label_(NULL),
+ stream_(NULL),
+ thread_(NULL) {
+}
+
+
+TimelineEvent::~TimelineEvent() {
+ Reset();
+}
+
+
+void TimelineEvent::Reset() {
+ set_event_type(kNone);
+ thread_ = NULL;
+ stream_ = NULL;
+ label_ = NULL;
+ FreeArguments();
+}
+
+
+int64_t TimelineEvent::AsyncBegin(TimelineStream* stream, const char* label) {
+ Init(kAsyncBegin, stream, label);
+ timestamp0_ = OS::GetCurrentTimeMicros();
+ int64_t async_id = stream->GetNextSeq();
+ // Overload timestamp1_ with the async_id.
+ timestamp1_ = async_id;
+ return async_id;
+}
+
+
+void TimelineEvent::AsyncInstant(TimelineStream* stream,
+ const char* label,
+ int64_t async_id) {
+ Init(kAsyncInstant, stream, label);
+ timestamp0_ = OS::GetCurrentTimeMicros();
+ // Overload timestamp1_ with the async_id.
+ timestamp1_ = async_id;
+}
+
+
+void TimelineEvent::AsyncEnd(TimelineStream* stream,
+ const char* label,
+ int64_t async_id) {
+ Init(kAsyncEnd, stream, label);
+ timestamp0_ = OS::GetCurrentTimeMicros();
+ // Overload timestamp1_ with the async_id.
+ timestamp1_ = async_id;
+}
+
+
+void TimelineEvent::DurationBegin(TimelineStream* stream, const char* label) {
+ Init(kDuration, stream, label);
+ timestamp0_ = OS::GetCurrentTimeMicros();
+}
+
+
+void TimelineEvent::DurationEnd() {
+ timestamp1_ = OS::GetCurrentTimeMicros();
+}
+
+
+void TimelineEvent::Instant(TimelineStream* stream,
+ const char* label) {
+ Init(kInstant, stream, label);
+ timestamp0_ = OS::GetCurrentTimeMicros();
+}
+
+
+void TimelineEvent::Duration(TimelineStream* stream,
+ const char* label,
+ int64_t start_micros,
+ int64_t end_micros) {
+ Init(kDuration, stream, label);
+ timestamp0_ = start_micros;
+ timestamp1_ = end_micros;
+}
+
+
+void TimelineEvent::SetNumArguments(intptr_t length) {
+ // Cannot call this twice.
+ ASSERT(arguments_ == NULL);
+ ASSERT(arguments_length_ == 0);
+ arguments_length_ = length;
+ arguments_ = reinterpret_cast<TimelineEventArgument*>(
+ calloc(sizeof(TimelineEventArgument), length));
+}
+
+
+void TimelineEvent::SetArgument(intptr_t i, const char* name, char* argument) {
+ ASSERT(i >= 0);
+ ASSERT(i < arguments_length_);
+ arguments_[i].name = name;
+ arguments_[i].value = argument;
+}
+
+
+void TimelineEvent::FormatArgument(intptr_t i, const char* name,
+ const char* fmt, ...) {
+ ASSERT(i >= 0);
+ ASSERT(i < arguments_length_);
+ va_list args;
+ va_start(args, fmt);
+ intptr_t len = OS::VSNPrint(NULL, 0, fmt, args);
+ va_end(args);
+
+ char* buffer = reinterpret_cast<char*>(malloc(len + 1));
+ va_list args2;
+ va_start(args2, fmt);
+ OS::VSNPrint(buffer, (len + 1), fmt, args2);
+ va_end(args2);
+
+ SetArgument(i, name, buffer);
+}
+
+
+void TimelineEvent::CopyArgument(intptr_t i,
+ const char* name,
+ const char* argument) {
+ SetArgument(i, name, strdup(argument));
+}
+
+
+void TimelineEvent::FreeArguments() {
+ if (arguments_ == NULL) {
+ return;
+ }
+ for (intptr_t i = 0; i < arguments_length_; i++) {
+ free(arguments_[i].value);
+ }
+ free(arguments_);
+ arguments_ = NULL;
+ arguments_length_ = 0;
+}
+
+void TimelineEvent::Init(EventType event_type,
+ TimelineStream* stream,
+ const char* label) {
+ ASSERT(stream != NULL);
+ ASSERT(label != NULL);
+ set_event_type(event_type);
+ timestamp0_ = 0;
+ timestamp1_ = 0;
+ thread_ = Thread::Current();
+ stream_ = stream;
+ label_ = label;
+ FreeArguments();
+}
+
+
+static int64_t GetPid(Isolate* isolate) {
+ // Some mapping from Isolate* to an integer process id.
+ // TODO(Cutch): Investigate if process ids can be strings.
+ return static_cast<int64_t>(reinterpret_cast<uintptr_t>(isolate));
+}
+
+
+static int64_t GetTid(Thread* thread) {
+ // Some mapping from Thread* to an integer thread id.
+ // TODO(Cutch): Investigate if process ids can be strings.
+ return static_cast<int64_t>(reinterpret_cast<uintptr_t>(thread));
+}
+
+
+void TimelineEvent::PrintJSON(JSONStream* stream) const {
+ JSONObject obj(stream);
+ int64_t pid = GetPid(Isolate::Current());
+ int64_t tid = GetTid(thread_);
+ obj.AddProperty("name", label_);
+ obj.AddProperty("cat", stream_->name());
+ obj.AddProperty64("tid", tid);
+ obj.AddProperty64("pid", pid);
+ obj.AddProperty("ts", static_cast<double>(TimeOrigin()));
+
+ switch (event_type()) {
+ case kDuration: {
+ obj.AddProperty("ph", "X");
+ obj.AddProperty("dur", static_cast<double>(TimeDuration()));
+ }
+ break;
+ case kInstant: {
+ obj.AddProperty("ph", "i");
+ obj.AddProperty("s", "p");
+ }
+ break;
+ case kAsyncBegin: {
+ obj.AddProperty("ph", "b");
+ obj.AddPropertyF("id", "%" Px64 "", AsyncId());
+ }
+ break;
+ case kAsyncInstant: {
+ obj.AddProperty("ph", "n");
+ obj.AddPropertyF("id", "%" Px64 "", AsyncId());
+ }
+ break;
+ case kAsyncEnd: {
+ obj.AddProperty("ph", "e");
+ obj.AddPropertyF("id", "%" Px64 "", AsyncId());
+ }
+ break;
+ default:
+ UNIMPLEMENTED();
+ }
+ {
+ JSONObject args(&obj, "args");
+ for (intptr_t i = 0; i < arguments_length_; i++) {
+ const TimelineEventArgument& arg = arguments_[i];
+ args.AddProperty(arg.name, arg.value);
+ }
+ }
+}
+
+
+int64_t TimelineEvent::TimeOrigin() const {
+ return timestamp0_;
+}
+
+
+int64_t TimelineEvent::AsyncId() const {
+ return timestamp1_;
+}
+
+
+int64_t TimelineEvent::TimeDuration() const {
+ if (timestamp1_ == 0) {
+ // This duration is still open, use current time as end.
+ return OS::GetCurrentTimeMicros() - timestamp0_;
+ }
+ return timestamp1_ - timestamp0_;
+}
+
+
+TimelineStream::TimelineStream()
+ : buffer_(NULL),
+ name_(NULL),
+ enabled_(false),
+ seq_(0) {
+}
+
+
+void TimelineStream::Init(const char* name, bool enabled) {
+ name_ = name;
+ enabled_ = enabled;
+}
+
+
+TimelineEvent* TimelineStream::RecordEvent(const Object& obj) {
+ if (!enabled_ || (buffer_ == NULL)) {
+ return NULL;
+ }
+ ASSERT(name_ != NULL);
+ ASSERT(buffer_ != NULL);
+ return buffer_->RecordEvent(obj);
+}
+
+
+TimelineEvent* TimelineStream::RecordEvent() {
+ if (!enabled_ || (buffer_ == NULL)) {
+ return NULL;
+ }
+ ASSERT(name_ != NULL);
+ return buffer_->RecordEvent();
+}
+
+
+int64_t TimelineStream::GetNextSeq() {
+ seq_++;
+ if (seq_ < 0) {
+ seq_ = 0;
+ }
+ return seq_;
+}
+
+
+void TimelineDurationScope::FormatArgument(intptr_t i,
+ const char* name,
+ const char* fmt, ...) {
+ if (event_ == NULL) {
+ return;
+ }
+ va_list args;
+ va_start(args, fmt);
+ intptr_t len = OS::VSNPrint(NULL, 0, fmt, args);
+ va_end(args);
+
+ char* buffer = reinterpret_cast<char*>(malloc(len + 1));
+ va_list args2;
+ va_start(args2, fmt);
+ OS::VSNPrint(buffer, (len + 1), fmt, args2);
+ va_end(args2);
+
+ event_->SetArgument(i, name, buffer);
+}
+
+
+intptr_t TimelineEventBuffer::SizeForCapacity(intptr_t capacity) {
+ return sizeof(TimelineEvent) * capacity;
+}
+
+
+TimelineEventBuffer::TimelineEventBuffer(intptr_t capacity)
+ : events_(NULL),
+ event_objects_(Array::null()),
+ cursor_(0),
+ capacity_(capacity) {
+ if (FLAG_trace_timeline) {
+ // 32-bit: 262,144 bytes per isolate.
+ // 64-bit: 393,216 bytes per isolate.
+ // NOTE: Internal isolates (vm and service) do not have a timeline
+ // event buffer.
+ OS::Print("TimelineEventBuffer is %" Pd " bytes (%" Pd " events)\n",
+ SizeForCapacity(capacity),
+ capacity);
+ }
+ events_ =
+ reinterpret_cast<TimelineEvent*>(calloc(capacity, sizeof(TimelineEvent)));
+ const Array& array = Array::Handle(Array::New(capacity, Heap::kOld));
+ event_objects_ = array.raw();
+}
+
+
+TimelineEventBuffer::~TimelineEventBuffer() {
+ for (intptr_t i = 0; i < capacity_; i++) {
+ // Clear any extra data.
+ events_[i].Reset();
+ }
+ free(events_);
+ event_objects_ = Array::null();
+}
+
+
+void TimelineEventBuffer::PrintJSONMeta(JSONArray* events) const {
+ Isolate* isolate = Isolate::Current();
+ JSONObject obj(events);
+ int64_t pid = GetPid(isolate);
+ obj.AddProperty("ph", "M");
+ obj.AddProperty64("pid", pid);
+ obj.AddProperty("name", "process_name");
+ {
+ JSONObject args(&obj, "args");
+ args.AddProperty("name", isolate->debugger_name());
+ }
+}
+
+
+void TimelineEventBuffer::PrintJSONEvents(JSONArray* events) const {
+ for (intptr_t i = 0; i < capacity_; i++) {
+ if (events_[i].IsValid()) {
+ events->AddValue(&events_[i]);
+ }
+ }
+}
+
+
+void TimelineEventBuffer::PrintJSON(JSONStream* js) const {
+ JSONObject topLevel(js);
+ topLevel.AddProperty("type", "_Timeline");
+ {
+ JSONArray events(&topLevel, "traceEvents");
+ PrintJSONMeta(&events);
+ PrintJSONEvents(&events);
+ }
+}
+
+
+void TimelineEventBuffer::WriteTo(const char* directory) {
+ Isolate* isolate = Isolate::Current();
+
+ Dart_FileOpenCallback file_open = Isolate::file_open_callback();
+ Dart_FileWriteCallback file_write = Isolate::file_write_callback();
+ Dart_FileCloseCallback file_close = Isolate::file_close_callback();
+ if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) {
+ return;
+ }
+
+ JSONStream js;
+ PrintJSON(&js);
+
+ const char* format = "%s/dart-timeline-%" Pd "-%" Pd ".json";
+ intptr_t pid = OS::ProcessId();
+ intptr_t len = OS::SNPrint(NULL, 0, format,
+ directory, pid, isolate->main_port());
+ char* filename = isolate->current_zone()->Alloc<char>(len + 1);
+ OS::SNPrint(filename, len + 1, format,
+ directory, pid, isolate->main_port());
+ void* file = (*file_open)(filename, true);
+ if (file == NULL) {
+ OS::Print("Failed to write timeline file: %s\n", filename);
+ return;
+ }
+ (*file_write)(js.buffer()->buf(), js.buffer()->length(), file);
+ (*file_close)(file);
+}
+
+
+intptr_t TimelineEventBuffer::GetNextIndex() {
+ uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_);
+ return cursor % capacity_;
+}
+
+
+void TimelineEventBuffer::VisitObjectPointers(ObjectPointerVisitor* visitor) {
+ visitor->VisitPointer(reinterpret_cast<RawObject**>(&event_objects_));
+}
+
+
+TimelineEvent* TimelineEventBuffer::RecordEvent(const Object& obj) {
+ ASSERT(events_ != NULL);
+ uintptr_t index = GetNextIndex();
+ const Array& event_objects = Array::Handle(event_objects_);
+ event_objects.SetAt(index, obj);
+ return &events_[index];
+}
+
+
+TimelineEvent* TimelineEventBuffer::RecordEvent() {
+ ASSERT(events_ != NULL);
+ uintptr_t index = GetNextIndex();
+ return &events_[index];
+}
+
+} // namespace dart
« no previous file with comments | « runtime/vm/timeline.h ('k') | runtime/vm/timeline_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698