OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #include <cstdlib> | |
6 | |
7 #include "vm/isolate.h" | |
8 #include "vm/json_stream.h" | |
9 #include "vm/object.h" | |
10 #include "vm/thread.h" | |
11 #include "vm/timeline.h" | |
12 | |
13 namespace dart { | |
14 | |
15 DEFINE_FLAG(bool, trace_timeline, false, "Timeline trace"); | |
16 | |
17 | |
18 void TimelineEvent::Reset() { | |
19 set_event_type(kNone); | |
20 thread_ = NULL; | |
21 stream_ = NULL; | |
22 label_ = NULL; | |
23 arg_name_ = NULL; | |
24 if (arg_value_ != NULL) { | |
25 free(const_cast<char*>(arg_value_)); | |
26 } | |
27 } | |
28 | |
29 | |
30 void TimelineEvent::DurationBegin(TimelineStream* stream, const char* label) { | |
31 Init(kDuration, stream, label); | |
32 } | |
33 | |
34 | |
35 void TimelineEvent::DurationEnd() { | |
36 timestamp1_ = OS::GetCurrentTimeMicros(); | |
37 } | |
38 | |
39 | |
40 void TimelineEvent::Instant(TimelineStream* stream, const char* label) { | |
41 Init(kInstant, stream, label); | |
42 } | |
43 | |
44 | |
45 void TimelineEvent::SetArgument(const char* name, const char* value) { | |
46 arg_name_ = name; | |
47 arg_value_ = strdup(value); | |
48 } | |
49 | |
50 void TimelineEvent::Init(EventType event_type, | |
51 TimelineStream* stream, | |
52 const char* label) { | |
53 set_event_type(event_type); | |
54 timestamp0_ = OS::GetCurrentTimeMicros(); | |
55 thread_ = Thread::Current(); | |
56 stream_ = stream; | |
57 label_ = label; | |
58 arg_name_ = NULL; | |
59 if (arg_value_ != NULL) { | |
60 free(const_cast<char*>(arg_value_)); | |
61 } | |
62 } | |
63 | |
64 | |
65 static int64_t GetPid(Isolate* isolate) { | |
66 // Some mapping from Isolate* to an integer process id. | |
67 // TODO(Cutch): Investigate if process ids can be strings. | |
68 return static_cast<int64_t>(reinterpret_cast<uintptr_t>(isolate)); | |
69 } | |
70 | |
71 | |
72 static int64_t GetTid(Thread* thread) { | |
73 // Some mapping from Thread* to an integer thread id. | |
74 // TODO(Cutch): Investigate if process ids can be strings. | |
75 return static_cast<int64_t>(reinterpret_cast<uintptr_t>(thread)); | |
76 } | |
77 | |
78 | |
79 void TimelineEvent::PrintJSON(JSONStream* stream) { | |
80 JSONObject obj(stream); | |
81 int64_t pid = GetPid(Isolate::Current()); | |
82 int64_t tid = GetTid(thread_); | |
83 obj.AddProperty("name", label_); | |
84 obj.AddProperty("cat", stream_->name()); | |
85 obj.AddProperty64("tid", tid); | |
86 obj.AddProperty64("pid", pid); | |
87 obj.AddProperty("ts", static_cast<double>(timestamp0_)); | |
88 | |
89 switch (event_type()) { | |
90 case kDuration: { | |
91 obj.AddProperty("ph", "X"); | |
rmacnak
2015/06/05 21:22:58
ph?
Cutch
2015/06/05 21:34:42
https://docs.google.com/document/d/1CvAClvFfyA5R-P
| |
92 obj.AddProperty("dur", static_cast<double>(timestamp1_ - timestamp0_)); | |
93 } | |
94 break; | |
95 case kInstant: { | |
96 UNIMPLEMENTED(); | |
97 } | |
98 break; | |
99 default: | |
100 UNIMPLEMENTED(); | |
101 } | |
102 | |
103 if (arg_name_ != NULL) { | |
104 JSONObject args(&obj, "args"); | |
105 args.AddProperty(arg_name_, arg_value_); | |
106 } | |
107 } | |
108 | |
109 | |
110 TimelineStream::TimelineStream() | |
111 : buffer_(NULL), | |
112 name_(NULL), | |
113 enabled_(false) { | |
114 } | |
115 | |
116 | |
117 void TimelineStream::Init(const char* name, bool enabled) { | |
118 name_ = name; | |
119 enabled_ = enabled; | |
120 } | |
121 | |
122 | |
123 TimelineEvent* TimelineStream::RecordEvent(const Object& obj) { | |
124 if (!enabled_ || (buffer_ == NULL)) { | |
125 return NULL; | |
126 } | |
127 ASSERT(name_ != NULL); | |
128 ASSERT(buffer_ != NULL); | |
129 return buffer_->RecordEvent(obj); | |
130 } | |
131 | |
132 | |
133 TimelineEvent* TimelineStream::RecordEvent() { | |
134 if (!enabled_ || (buffer_ == NULL)) { | |
135 return NULL; | |
136 } | |
137 ASSERT(name_ != NULL); | |
138 return buffer_->RecordEvent(); | |
139 } | |
140 | |
141 | |
142 intptr_t TimelineEventBuffer::SizeForCapacity(intptr_t capacity) { | |
143 return sizeof(TimelineEvent) * capacity; | |
144 } | |
145 | |
146 | |
147 TimelineEventBuffer::TimelineEventBuffer(intptr_t capacity) | |
148 : events_(NULL), | |
149 event_objects_(Array::null()), | |
150 cursor_(0), | |
151 capacity_(capacity) { | |
152 if (FLAG_trace_timeline) { | |
153 // 32-bit: 262,144 bytes per isolate. | |
154 // 64-bit: 393,216 bytes per isolate. | |
155 // NOTE: Internal isolates (vm and service) do not have a timeline | |
156 // event buffer. | |
157 OS::Print("TimelineEventBuffer is %" Pd " bytes (%" Pd " events)\n", | |
158 SizeForCapacity(capacity), | |
159 capacity); | |
160 } | |
161 events_ = | |
162 reinterpret_cast<TimelineEvent*>(calloc(capacity, sizeof(TimelineEvent))); | |
163 const Array& array = Array::Handle(Array::New(capacity, Heap::kOld)); | |
164 event_objects_ = array.raw(); | |
165 } | |
166 | |
167 | |
168 TimelineEventBuffer::~TimelineEventBuffer() { | |
169 for (intptr_t i = 0; i < capacity_; i++) { | |
170 // Clear any extra data. | |
171 events_[i].Reset(); | |
172 } | |
173 free(events_); | |
174 event_objects_ = Array::null(); | |
175 } | |
176 | |
177 | |
178 void TimelineEventBuffer::DumpMeta(JSONArray* events) { | |
179 Isolate* isolate = Isolate::Current(); | |
180 JSONObject obj(events); | |
181 int64_t pid = GetPid(isolate); | |
182 obj.AddProperty("ph", "M"); | |
183 obj.AddProperty64("pid", pid); | |
184 obj.AddProperty("name", "process_name"); | |
185 { | |
186 JSONObject args(&obj, "args"); | |
187 args.AddProperty("name", isolate->debugger_name()); | |
188 } | |
189 } | |
190 | |
191 | |
192 void TimelineEventBuffer::DumpEvents(JSONArray* events) { | |
193 for (intptr_t i = 0; i < capacity_; i++) { | |
194 if (events_[i].IsValid()) { | |
195 events->AddValue(&events_[i]); | |
196 } | |
197 } | |
198 } | |
199 | |
200 | |
201 void TimelineEventBuffer::Dump() { | |
202 JSONStream js; | |
203 { | |
204 JSONObject topLevel(&js); | |
205 topLevel.AddProperty("type", "Timeline"); | |
206 { | |
207 JSONArray events(&topLevel, "traceEvents"); | |
208 DumpMeta(&events); | |
209 DumpEvents(&events); | |
210 } | |
211 } | |
212 OS::Print("%s\n", js.ToCString()); | |
213 } | |
214 | |
215 | |
216 intptr_t TimelineEventBuffer::GetNextIndex() { | |
217 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); | |
218 return cursor % capacity_; | |
219 } | |
220 | |
221 | |
222 void TimelineEventBuffer::VisitObjectPointers(ObjectPointerVisitor* visitor) { | |
223 visitor->VisitPointer(reinterpret_cast<RawObject**>(&event_objects_)); | |
224 } | |
225 | |
226 | |
227 TimelineEvent* TimelineEventBuffer::RecordEvent(const Object& obj) { | |
228 ASSERT(events_ != NULL); | |
229 uintptr_t index = GetNextIndex(); | |
230 const Array& event_objects = Array::Handle(event_objects_); | |
231 event_objects.SetAt(index, obj); | |
232 return &events_[index]; | |
233 } | |
234 | |
235 | |
236 TimelineEvent* TimelineEventBuffer::RecordEvent() { | |
237 ASSERT(events_ != NULL); | |
238 uintptr_t index = GetNextIndex(); | |
239 return &events_[index]; | |
240 } | |
241 | |
242 } // namespace dart | |
OLD | NEW |