OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #ifndef VM_TIMELINE_H_ | 5 #ifndef VM_TIMELINE_H_ |
6 #define VM_TIMELINE_H_ | 6 #define VM_TIMELINE_H_ |
7 | 7 |
8 #include "vm/allocation.h" | 8 #include "vm/allocation.h" |
9 #include "vm/bitfield.h" | 9 #include "vm/bitfield.h" |
10 | 10 |
11 namespace dart { | 11 namespace dart { |
12 | 12 |
13 class JSONArray; | 13 class JSONArray; |
14 class JSONObject; | 14 class JSONObject; |
15 class JSONStream; | 15 class JSONStream; |
16 class Object; | 16 class Object; |
17 class ObjectPointerVisitor; | 17 class ObjectPointerVisitor; |
18 class RawArray; | 18 class RawArray; |
19 class Thread; | 19 class Thread; |
20 class TimelineEvent; | 20 class TimelineEvent; |
21 class TimelineEventBlock; | 21 class TimelineEventBlock; |
22 class TimelineEventRecorder; | 22 class TimelineEventRecorder; |
23 class TimelineStream; | 23 class TimelineStream; |
24 | 24 |
25 | |
26 class Timeline : public AllStatic { | |
27 public: | |
28 // Initialize timeline system. Not thread safe. | |
29 static void InitOnce(); | |
30 | |
31 // Shutdown timeline system. Not thread safe. | |
32 static void Shutdown(); | |
33 | |
34 // Access the global recorder. Not thread safe. | |
35 static TimelineEventRecorder* recorder(); | |
36 | |
37 static bool EnableStreamByDefault(const char* stream_name); | |
38 | |
39 static TimelineStream* GetVMStream(); | |
40 | |
41 private: | |
42 static TimelineEventRecorder* recorder_; | |
43 static TimelineStream* vm_stream_; | |
44 | |
45 friend class TimelineRecorderOverride; | |
46 }; | |
47 | |
48 | |
25 // You should get a |TimelineEvent| from a |TimelineStream|. | 49 // You should get a |TimelineEvent| from a |TimelineStream|. |
26 class TimelineEvent { | 50 class TimelineEvent { |
27 public: | 51 public: |
28 // Keep in sync with StateBits below. | 52 // Keep in sync with StateBits below. |
29 enum EventType { | 53 enum EventType { |
30 kNone, | 54 kNone, |
31 kDuration, | 55 kDuration, |
32 kInstant, | 56 kInstant, |
33 kAsyncBegin, | 57 kAsyncBegin, |
34 kAsyncInstant, | 58 kAsyncInstant, |
35 kAsyncEnd, | 59 kAsyncEnd, |
36 kNumEventTypes, | 60 kNumEventTypes, |
37 }; | 61 }; |
38 | 62 |
39 TimelineEvent(); | 63 TimelineEvent(); |
40 ~TimelineEvent(); | 64 ~TimelineEvent(); |
41 | 65 |
42 void Reset(); | 66 void Reset(); |
43 | 67 |
44 bool IsValid() const { | 68 bool IsValid() const { |
45 return (event_type() > kNone) && (event_type() < kNumEventTypes); | 69 return (event_type() > kNone) && (event_type() < kNumEventTypes); |
46 } | 70 } |
47 | 71 |
48 // Marks the beginning of an asynchronous operation. | 72 // Marks the beginning of an asynchronous operation with \async_id|. |
49 // Returns |async_id| which must be passed to |AsyncInstant| and |AsyncEnd|. | 73 void AsyncBegin(const char* label, int64_t async_id); |
50 int64_t AsyncBegin(const char* label); | |
51 // Marks an instantaneous event associated with |async_id|. | 74 // Marks an instantaneous event associated with |async_id|. |
52 void AsyncInstant(const char* label, | 75 void AsyncInstant(const char* label, |
53 int64_t async_id); | 76 int64_t async_id); |
54 // Marks the end of an asynchronous operation associated with |async_id|. | 77 // Marks the end of an asynchronous operation associated with |async_id|. |
55 void AsyncEnd(const char* label, | 78 void AsyncEnd(const char* label, |
56 int64_t async_id); | 79 int64_t async_id); |
57 | 80 |
58 void DurationBegin(const char* label); | 81 void DurationBegin(const char* label); |
59 void DurationEnd(); | 82 void DurationEnd(); |
60 void Instant(const char* label); | 83 void Instant(const char* label); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
132 const char* name; | 155 const char* name; |
133 char* value; | 156 char* value; |
134 }; | 157 }; |
135 | 158 |
136 int64_t timestamp0_; | 159 int64_t timestamp0_; |
137 int64_t timestamp1_; | 160 int64_t timestamp1_; |
138 TimelineEventArgument* arguments_; | 161 TimelineEventArgument* arguments_; |
139 intptr_t arguments_length_; | 162 intptr_t arguments_length_; |
140 uword state_; | 163 uword state_; |
141 const char* label_; | 164 const char* label_; |
142 TimelineStream* stream_; | 165 const char* category_; |
143 ThreadId thread_; | 166 ThreadId thread_; |
167 Isolate* isolate_; | |
144 | 168 |
145 void FreeArguments(); | 169 void FreeArguments(); |
146 | 170 |
147 void StreamInit(TimelineStream* stream); | 171 void StreamInit(TimelineStream* stream); |
148 void Init(EventType event_type, const char* label); | 172 void Init(EventType event_type, const char* label); |
149 | 173 |
150 void set_event_type(EventType event_type) { | 174 void set_event_type(EventType event_type) { |
151 state_ = EventTypeField::update(event_type, state_); | 175 state_ = EventTypeField::update(event_type, state_); |
152 } | 176 } |
153 | 177 |
(...skipping 24 matching lines...) Expand all Loading... | |
178 } | 202 } |
179 | 203 |
180 bool enabled() const { | 204 bool enabled() const { |
181 return enabled_; | 205 return enabled_; |
182 } | 206 } |
183 | 207 |
184 void set_enabled(bool enabled) { | 208 void set_enabled(bool enabled) { |
185 enabled_ = enabled; | 209 enabled_ = enabled; |
186 } | 210 } |
187 | 211 |
188 TimelineEventRecorder* recorder() const { | |
189 return recorder_; | |
190 } | |
191 | |
192 // TODO(johnmccutchan): Disallow setting recorder after Init? | |
193 void set_recorder(TimelineEventRecorder* recorder) { | |
194 recorder_ = recorder; | |
195 } | |
196 | |
197 // Records an event. Will return |NULL| if not enabled. The returned | 212 // Records an event. Will return |NULL| if not enabled. The returned |
198 // |TimelineEvent| is in an undefined state and must be initialized. | 213 // |TimelineEvent| is in an undefined state and must be initialized. |
199 TimelineEvent* StartEvent(); | 214 TimelineEvent* StartEvent(); |
200 | 215 |
201 void CompleteEvent(TimelineEvent* event); | |
202 | |
203 int64_t GetNextSeq(); | |
204 | |
205 private: | 216 private: |
206 TimelineEventRecorder* recorder_; | |
207 const char* name_; | 217 const char* name_; |
208 bool enabled_; | 218 bool enabled_; |
209 int64_t seq_; | |
210 }; | 219 }; |
211 | 220 |
212 | 221 |
213 // (name, enabled by default). | 222 // (name, enabled by default). |
214 #define ISOLATE_TIMELINE_STREAM_LIST(V) \ | 223 #define ISOLATE_TIMELINE_STREAM_LIST(V) \ |
215 V(API, false) \ | 224 V(API, false) \ |
216 V(Compiler, false) \ | 225 V(Compiler, false) \ |
217 V(Embedder, false) \ | 226 V(Embedder, false) \ |
218 V(GC, false) \ | 227 V(GC, false) \ |
219 V(Isolate, false) \ | 228 V(Isolate, false) \ |
220 | 229 |
221 | 230 |
222 #define TIMELINE_FUNCTION_COMPILATION_DURATION(isolate, suffix, function) \ | 231 #define TIMELINE_FUNCTION_COMPILATION_DURATION(isolate, suffix, function) \ |
223 TimelineDurationScope tds(isolate, \ | 232 TimelineDurationScope tds(isolate, \ |
224 isolate->GetCompilerStream(), \ | 233 isolate->GetCompilerStream(), \ |
225 "Compile" suffix); \ | 234 "Compile" suffix); \ |
226 if (tds.enabled()) { \ | 235 if (tds.enabled()) { \ |
227 tds.SetNumArguments(1); \ | 236 tds.SetNumArguments(1); \ |
228 tds.CopyArgument( \ | 237 tds.CopyArgument( \ |
229 0, \ | 238 0, \ |
230 "function", \ | 239 "function", \ |
231 const_cast<char*>(function.QualifiedUserVisibleNameCString())); \ | 240 const_cast<char*>(function.ToLibNamePrefixedQualifiedCString())); \ |
232 } | 241 } |
233 | 242 |
243 | |
244 // TODO(johnmccutchan): TimelineDurationScope should only allocate the | |
245 // event when complete. | |
234 class TimelineDurationScope : public StackResource { | 246 class TimelineDurationScope : public StackResource { |
235 public: | 247 public: |
236 TimelineDurationScope(Isolate* isolate, | 248 TimelineDurationScope(Isolate* isolate, |
237 TimelineStream* stream, | 249 TimelineStream* stream, |
238 const char* label) | 250 const char* label) |
239 : StackResource(isolate) { | 251 : StackResource(isolate) { |
240 Init(stream, label); | 252 Init(stream, label); |
241 } | 253 } |
242 | 254 |
243 TimelineDurationScope(Thread* thread, | 255 TimelineDurationScope(Thread* thread, |
244 TimelineStream* stream, | 256 TimelineStream* stream, |
245 const char* label) | 257 const char* label) |
246 : StackResource(thread) { | 258 : StackResource(thread) { |
247 Init(stream, label); | 259 Init(stream, label); |
248 } | 260 } |
249 | 261 |
262 TimelineDurationScope(TimelineStream* stream, | |
263 const char* label) | |
264 : StackResource(reinterpret_cast<Thread*>(NULL)) { | |
265 Init(stream, label); | |
266 } | |
267 | |
250 void Init(TimelineStream* stream, const char* label) { | 268 void Init(TimelineStream* stream, const char* label) { |
251 event_ = stream->StartEvent(); | 269 event_ = stream->StartEvent(); |
252 if (event_ == NULL) { | 270 if (event_ == NULL) { |
253 return; | 271 return; |
254 } | 272 } |
255 event_->DurationBegin(label); | 273 event_->DurationBegin(label); |
256 } | 274 } |
257 | 275 |
258 bool enabled() const { | 276 bool enabled() const { |
259 return event_ != NULL; | 277 return event_ != NULL; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
346 int64_t LowerTimeBound() const; | 364 int64_t LowerTimeBound() const; |
347 | 365 |
348 // Returns false if |this| violates any of the following invariants: | 366 // Returns false if |this| violates any of the following invariants: |
349 // - events in the block come from one thread. | 367 // - events in the block come from one thread. |
350 // - events have monotonically increasing timestamps. | 368 // - events have monotonically increasing timestamps. |
351 bool CheckBlock(); | 369 bool CheckBlock(); |
352 | 370 |
353 // Call Reset on all events and set length to 0. | 371 // Call Reset on all events and set length to 0. |
354 void Reset(); | 372 void Reset(); |
355 | 373 |
374 // Only safe to access under the recorder's lock. | |
375 bool open() const { | |
376 return open_; | |
377 } | |
378 | |
379 // Only safe to access under the recorder's lock. | |
380 Isolate* isolate() const { | |
381 return isolate_; | |
382 } | |
383 | |
356 protected: | 384 protected: |
357 TimelineEvent* StartEvent(); | 385 TimelineEvent* StartEvent(); |
358 | 386 |
359 TimelineEvent events_[kBlockSize]; | 387 TimelineEvent events_[kBlockSize]; |
360 TimelineEventBlock* next_; | 388 TimelineEventBlock* next_; |
361 intptr_t length_; | 389 intptr_t length_; |
362 intptr_t block_index_; | 390 intptr_t block_index_; |
363 | 391 |
392 // Only accessed under the recorder's lock. | |
393 Isolate* isolate_; | |
394 bool open_; | |
395 | |
396 void Open(Isolate* isolate); | |
397 void Finish(); | |
398 | |
399 friend class ThreadRegistry; | |
400 friend class TimelineEventRecorder; | |
401 friend class TimelineEventRingRecorder; | |
364 friend class TimelineEventEndlessRecorder; | 402 friend class TimelineEventEndlessRecorder; |
365 friend class TimelineEventRecorder; | |
366 friend class TimelineTestHelper; | 403 friend class TimelineTestHelper; |
367 | 404 |
368 private: | 405 private: |
369 DISALLOW_COPY_AND_ASSIGN(TimelineEventBlock); | 406 DISALLOW_COPY_AND_ASSIGN(TimelineEventBlock); |
370 }; | 407 }; |
371 | 408 |
372 | 409 |
410 class TimelineEventFilter : public ValueObject { | |
411 public: | |
412 TimelineEventFilter(); | |
413 virtual ~TimelineEventFilter(); | |
414 | |
415 virtual bool VisitBlock(TimelineEventBlock* block) { | |
rmacnak
2015/08/18 21:09:00
'IncludeBlock'? VisitBlock sounds like it is run
Cutch
2015/08/18 21:50:18
Done.
| |
416 if (block == NULL) { | |
417 return false; | |
418 } | |
419 // Not empty and not open. | |
420 return !block->IsEmpty() && !block->open(); | |
421 } | |
422 | |
423 virtual bool VisitEvent(TimelineEvent* event) { | |
rmacnak
2015/08/18 21:09:00
'IncludeEvent'?
Cutch
2015/08/18 21:50:18
Done.
| |
424 if (event == NULL) { | |
425 return false; | |
426 } | |
427 return event->IsValid(); | |
428 } | |
429 | |
430 private: | |
431 }; | |
432 | |
433 | |
434 class IsolateTimelineEventFilter : public TimelineEventFilter { | |
435 public: | |
436 explicit IsolateTimelineEventFilter(Isolate* isolate); | |
437 | |
438 bool VisitBlock(TimelineEventBlock* block) { | |
439 if (block == NULL) { | |
440 return false; | |
441 } | |
442 // Not empty, not open, and isolate match. | |
443 return !block->IsEmpty() && | |
444 !block->open() && | |
445 (block->isolate() == isolate_); | |
446 } | |
447 | |
448 private: | |
449 Isolate* isolate_; | |
450 }; | |
451 | |
452 | |
373 // Recorder of |TimelineEvent|s. | 453 // Recorder of |TimelineEvent|s. |
374 class TimelineEventRecorder { | 454 class TimelineEventRecorder { |
375 public: | 455 public: |
376 TimelineEventRecorder(); | 456 TimelineEventRecorder(); |
377 virtual ~TimelineEventRecorder() {} | 457 virtual ~TimelineEventRecorder() {} |
378 | 458 |
459 TimelineEventBlock* GetNewBlock(); | |
460 | |
379 // Interface method(s) which must be implemented. | 461 // Interface method(s) which must be implemented. |
380 virtual void PrintJSON(JSONStream* js) = 0; | 462 virtual void PrintJSON(JSONStream* js, TimelineEventFilter* filter) = 0; |
381 virtual TimelineEventBlock* GetNewBlock() = 0; | |
382 virtual TimelineEventBlock* GetHeadBlock() = 0; | |
383 | 463 |
384 void WriteTo(const char* directory); | 464 void WriteTo(const char* directory); |
385 | 465 |
466 int64_t GetNextAsyncId(); | |
467 | |
386 protected: | 468 protected: |
387 // Interface method(s) which must be implemented. | 469 // Interface method(s) which must be implemented. |
388 virtual TimelineEvent* StartEvent() = 0; | 470 virtual TimelineEvent* StartEvent() = 0; |
389 virtual void CompleteEvent(TimelineEvent* event) = 0; | 471 virtual void CompleteEvent(TimelineEvent* event) = 0; |
472 virtual TimelineEventBlock* GetHeadBlockLocked() = 0; | |
473 virtual TimelineEventBlock* GetNewBlockLocked(Isolate* isolate) = 0; | |
390 | 474 |
391 // Utility method(s). | 475 // Utility method(s). |
392 void PrintJSONMeta(JSONArray* array) const; | 476 void PrintJSONMeta(JSONArray* array) const; |
393 TimelineEvent* ThreadBlockStartEvent(); | 477 TimelineEvent* ThreadBlockStartEvent(); |
478 TimelineEvent* GlobalBlockStartEvent(); | |
394 | 479 |
395 Mutex lock_; | 480 Mutex lock_; |
481 // Only accessed under |lock_|. | |
482 TimelineEventBlock* global_block_; | |
396 | 483 |
484 uintptr_t async_id_; | |
485 | |
486 friend class ThreadRegistry; | |
487 friend class TimelineEvent; | |
397 friend class TimelineEventBlockIterator; | 488 friend class TimelineEventBlockIterator; |
398 friend class TimelineStream; | 489 friend class TimelineStream; |
399 friend class TimelineTestHelper; | 490 friend class TimelineTestHelper; |
400 friend class Isolate; | 491 friend class Isolate; |
401 | 492 |
402 private: | 493 private: |
403 DISALLOW_COPY_AND_ASSIGN(TimelineEventRecorder); | 494 DISALLOW_COPY_AND_ASSIGN(TimelineEventRecorder); |
404 }; | 495 }; |
405 | 496 |
406 | 497 |
407 // A recorder that stores events in a ring buffer of fixed capacity. | 498 // A recorder that stores events in a ring buffer of fixed capacity. |
408 class TimelineEventRingRecorder : public TimelineEventRecorder { | 499 class TimelineEventRingRecorder : public TimelineEventRecorder { |
409 public: | 500 public: |
410 static const intptr_t kDefaultCapacity = 8192; | 501 static const intptr_t kDefaultCapacity = 8192; |
411 | 502 |
412 explicit TimelineEventRingRecorder(intptr_t capacity = kDefaultCapacity); | 503 explicit TimelineEventRingRecorder(intptr_t capacity = kDefaultCapacity); |
413 ~TimelineEventRingRecorder(); | 504 ~TimelineEventRingRecorder(); |
414 | 505 |
415 void PrintJSON(JSONStream* js); | 506 void PrintJSON(JSONStream* js, TimelineEventFilter* filter); |
416 TimelineEventBlock* GetNewBlock(); | |
417 TimelineEventBlock* GetHeadBlock(); | |
418 | 507 |
419 protected: | 508 protected: |
420 TimelineEvent* StartEvent(); | 509 TimelineEvent* StartEvent(); |
421 void CompleteEvent(TimelineEvent* event); | 510 void CompleteEvent(TimelineEvent* event); |
511 TimelineEventBlock* GetHeadBlockLocked(); | |
512 intptr_t FindOldestBlockIndex() const; | |
513 TimelineEventBlock* GetNewBlockLocked(Isolate* isolate); | |
422 | 514 |
423 intptr_t FindOldestBlockIndex() const; | 515 void PrintJSONEvents(JSONArray* array, TimelineEventFilter* filter) const; |
424 TimelineEventBlock* GetNewBlockLocked(); | |
425 | |
426 void PrintJSONEvents(JSONArray* array) const; | |
427 | 516 |
428 TimelineEventBlock** blocks_; | 517 TimelineEventBlock** blocks_; |
429 RawArray* event_objects_; | |
430 intptr_t capacity_; | 518 intptr_t capacity_; |
431 intptr_t num_blocks_; | 519 intptr_t num_blocks_; |
432 intptr_t block_cursor_; | 520 intptr_t block_cursor_; |
433 }; | 521 }; |
434 | 522 |
435 | 523 |
436 // An abstract recorder that calls |StreamEvent| whenever an event is complete. | 524 // An abstract recorder that calls |StreamEvent| whenever an event is complete. |
437 class TimelineEventStreamingRecorder : public TimelineEventRecorder { | 525 class TimelineEventStreamingRecorder : public TimelineEventRecorder { |
438 public: | 526 public: |
439 TimelineEventStreamingRecorder(); | 527 TimelineEventStreamingRecorder(); |
440 ~TimelineEventStreamingRecorder(); | 528 ~TimelineEventStreamingRecorder(); |
441 | 529 |
442 void PrintJSON(JSONStream* js); | 530 void PrintJSON(JSONStream* js, TimelineEventFilter* filter); |
443 TimelineEventBlock* GetNewBlock() { | |
444 return NULL; | |
445 } | |
446 TimelineEventBlock* GetHeadBlock() { | |
447 return NULL; | |
448 } | |
449 | 531 |
450 // Called when |event| is ready to be streamed. It is unsafe to keep a | 532 // Called when |event| is ready to be streamed. It is unsafe to keep a |
451 // reference to |event| as it may be freed as soon as this function returns. | 533 // reference to |event| as it may be freed as soon as this function returns. |
452 virtual void StreamEvent(TimelineEvent* event) = 0; | 534 virtual void StreamEvent(TimelineEvent* event) = 0; |
453 | 535 |
454 protected: | 536 protected: |
537 TimelineEventBlock* GetNewBlockLocked(Isolate* isolate) { | |
538 return NULL; | |
539 } | |
540 TimelineEventBlock* GetHeadBlockLocked() { | |
541 return NULL; | |
542 } | |
455 TimelineEvent* StartEvent(); | 543 TimelineEvent* StartEvent(); |
456 void CompleteEvent(TimelineEvent* event); | 544 void CompleteEvent(TimelineEvent* event); |
457 }; | 545 }; |
458 | 546 |
459 | 547 |
460 // A recorder that stores events in chains of blocks of events. | 548 // A recorder that stores events in chains of blocks of events. |
461 // NOTE: This recorder will continue to allocate blocks until it exhausts | 549 // NOTE: This recorder will continue to allocate blocks until it exhausts |
462 // memory. | 550 // memory. |
463 class TimelineEventEndlessRecorder : public TimelineEventRecorder { | 551 class TimelineEventEndlessRecorder : public TimelineEventRecorder { |
464 public: | 552 public: |
465 TimelineEventEndlessRecorder(); | 553 TimelineEventEndlessRecorder(); |
466 | 554 |
467 // Acquire a new block of events. | |
468 // Takes a lock. | |
469 // Recorder owns the block and it should be filled by only one thread. | |
470 TimelineEventBlock* GetNewBlock(); | |
471 | |
472 TimelineEventBlock* GetHeadBlock(); | |
473 | |
474 // It is expected that this function is only called when an isolate is | |
475 // shutting itself down. | |
476 // NOTE: Calling this while threads are filling in their blocks is not safe | 555 // NOTE: Calling this while threads are filling in their blocks is not safe |
477 // and there are no checks in place to ensure that doesn't happen. | 556 // and there are no checks in place to ensure that doesn't happen. |
478 // TODO(koda): Add isolate count to |ThreadRegistry| and verify that it is 1. | 557 // TODO(koda): Add isolate count to |ThreadRegistry| and verify that it is 1. |
479 void PrintJSON(JSONStream* js); | 558 void PrintJSON(JSONStream* js, TimelineEventFilter* filter); |
480 | 559 |
481 protected: | 560 protected: |
482 TimelineEvent* StartEvent(); | 561 TimelineEvent* StartEvent(); |
483 void CompleteEvent(TimelineEvent* event); | 562 void CompleteEvent(TimelineEvent* event); |
563 TimelineEventBlock* GetNewBlockLocked(Isolate* isolate); | |
564 TimelineEventBlock* GetHeadBlockLocked(); | |
484 | 565 |
485 TimelineEventBlock* GetNewBlockLocked(); | 566 void PrintJSONEvents(JSONArray* array, TimelineEventFilter* filter) const; |
486 void PrintJSONEvents(JSONArray* array) const; | |
487 | 567 |
488 // Useful only for testing. Only works for one thread. | 568 // Useful only for testing. Only works for one thread. |
489 void Clear(); | 569 void Clear(); |
490 | 570 |
491 TimelineEventBlock* head_; | 571 TimelineEventBlock* head_; |
492 intptr_t block_index_; | 572 intptr_t block_index_; |
493 | 573 |
494 friend class TimelineTestHelper; | 574 friend class TimelineTestHelper; |
495 }; | 575 }; |
496 | 576 |
(...skipping 13 matching lines...) Expand all Loading... | |
510 TimelineEventBlock* Next(); | 590 TimelineEventBlock* Next(); |
511 | 591 |
512 private: | 592 private: |
513 TimelineEventBlock* current_; | 593 TimelineEventBlock* current_; |
514 TimelineEventRecorder* recorder_; | 594 TimelineEventRecorder* recorder_; |
515 }; | 595 }; |
516 | 596 |
517 } // namespace dart | 597 } // namespace dart |
518 | 598 |
519 #endif // VM_TIMELINE_H_ | 599 #endif // VM_TIMELINE_H_ |
OLD | NEW |