| 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 #include <cstdlib> | 5 #include <cstdlib> |
| 6 | 6 |
| 7 #include "vm/atomic.h" |
| 7 #include "vm/isolate.h" | 8 #include "vm/isolate.h" |
| 8 #include "vm/json_stream.h" | 9 #include "vm/json_stream.h" |
| 9 #include "vm/lockers.h" | 10 #include "vm/lockers.h" |
| 10 #include "vm/object.h" | 11 #include "vm/object.h" |
| 11 #include "vm/thread.h" | 12 #include "vm/thread.h" |
| 12 #include "vm/timeline.h" | 13 #include "vm/timeline.h" |
| 13 | 14 |
| 14 namespace dart { | 15 namespace dart { |
| 15 | 16 |
| 16 DEFINE_FLAG(bool, trace_timeline, false, "Trace timeline backend"); | 17 DEFINE_FLAG(bool, trace_timeline, false, "Trace timeline backend"); |
| 17 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); | 18 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); |
| 18 | 19 |
| 20 DEFINE_FLAG(charp, timeline_dir, NULL, |
| 21 "Enable all timeline trace streams and output VM global trace " |
| 22 "into specified directory."); |
| 23 |
| 24 void Timeline::InitOnce() { |
| 25 ASSERT(recorder_ == NULL); |
| 26 // Default to ring recorder being enabled. |
| 27 const bool use_ring_recorder = true; |
| 28 // Some flags require that we use the endless recorder. |
| 29 const bool use_endless_recorder = (FLAG_timeline_dir != NULL); |
| 30 if (use_endless_recorder) { |
| 31 recorder_ = new TimelineEventEndlessRecorder(); |
| 32 } else if (use_ring_recorder) { |
| 33 recorder_ = new TimelineEventRingRecorder(); |
| 34 } |
| 35 vm_stream_ = new TimelineStream(); |
| 36 vm_stream_->Init("VM", EnableStreamByDefault("VM")); |
| 37 } |
| 38 |
| 39 |
| 40 void Timeline::Shutdown() { |
| 41 ASSERT(recorder_ != NULL); |
| 42 if (FLAG_timeline_dir != NULL) { |
| 43 recorder_->WriteTo(FLAG_timeline_dir); |
| 44 } |
| 45 delete recorder_; |
| 46 recorder_ = NULL; |
| 47 delete vm_stream_; |
| 48 vm_stream_ = NULL; |
| 49 } |
| 50 |
| 51 |
| 52 TimelineEventRecorder* Timeline::recorder() { |
| 53 return recorder_; |
| 54 } |
| 55 |
| 56 |
| 57 bool Timeline::EnableStreamByDefault(const char* stream_name) { |
| 58 // TODO(johnmccutchan): Allow for command line control over streams. |
| 59 return FLAG_timeline_dir != NULL; |
| 60 } |
| 61 |
| 62 |
| 63 TimelineStream* Timeline::GetVMStream() { |
| 64 ASSERT(vm_stream_ != NULL); |
| 65 return vm_stream_; |
| 66 } |
| 67 |
| 68 |
| 69 TimelineEventRecorder* Timeline::recorder_ = NULL; |
| 70 TimelineStream* Timeline::vm_stream_ = NULL; |
| 71 |
| 19 TimelineEvent::TimelineEvent() | 72 TimelineEvent::TimelineEvent() |
| 20 : timestamp0_(0), | 73 : timestamp0_(0), |
| 21 timestamp1_(0), | 74 timestamp1_(0), |
| 22 arguments_(NULL), | 75 arguments_(NULL), |
| 23 arguments_length_(0), | 76 arguments_length_(0), |
| 24 state_(0), | 77 state_(0), |
| 25 label_(NULL), | 78 label_(NULL), |
| 26 stream_(NULL), | 79 category_(""), |
| 27 thread_(OSThread::kInvalidThreadId) { | 80 thread_(OSThread::kInvalidThreadId) { |
| 28 } | 81 } |
| 29 | 82 |
| 30 | 83 |
| 31 TimelineEvent::~TimelineEvent() { | 84 TimelineEvent::~TimelineEvent() { |
| 32 Reset(); | 85 Reset(); |
| 33 } | 86 } |
| 34 | 87 |
| 35 | 88 |
| 36 void TimelineEvent::Reset() { | 89 void TimelineEvent::Reset() { |
| 37 set_event_type(kNone); | 90 set_event_type(kNone); |
| 38 thread_ = OSThread::kInvalidThreadId; | 91 thread_ = OSThread::kInvalidThreadId; |
| 39 stream_ = NULL; | 92 isolate_ = NULL; |
| 93 category_ = ""; |
| 40 label_ = NULL; | 94 label_ = NULL; |
| 41 FreeArguments(); | 95 FreeArguments(); |
| 42 } | 96 } |
| 43 | 97 |
| 44 | 98 |
| 45 int64_t TimelineEvent::AsyncBegin(const char* label) { | 99 void TimelineEvent::AsyncBegin(const char* label, int64_t async_id) { |
| 46 Init(kAsyncBegin, label); | 100 Init(kAsyncBegin, label); |
| 47 timestamp0_ = OS::GetCurrentTimeMicros(); | 101 timestamp0_ = OS::GetCurrentTimeMicros(); |
| 48 ASSERT(stream_ != NULL); | |
| 49 int64_t async_id = stream_->GetNextSeq(); | |
| 50 // Overload timestamp1_ with the async_id. | 102 // Overload timestamp1_ with the async_id. |
| 51 timestamp1_ = async_id; | 103 timestamp1_ = async_id; |
| 52 return async_id; | |
| 53 } | 104 } |
| 54 | 105 |
| 55 | 106 |
| 56 void TimelineEvent::AsyncInstant(const char* label, | 107 void TimelineEvent::AsyncInstant(const char* label, |
| 57 int64_t async_id) { | 108 int64_t async_id) { |
| 58 Init(kAsyncInstant, label); | 109 Init(kAsyncInstant, label); |
| 59 timestamp0_ = OS::GetCurrentTimeMicros(); | 110 timestamp0_ = OS::GetCurrentTimeMicros(); |
| 60 // Overload timestamp1_ with the async_id. | 111 // Overload timestamp1_ with the async_id. |
| 61 timestamp1_ = async_id; | 112 timestamp1_ = async_id; |
| 62 } | 113 } |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 | 186 |
| 136 | 187 |
| 137 void TimelineEvent::CopyArgument(intptr_t i, | 188 void TimelineEvent::CopyArgument(intptr_t i, |
| 138 const char* name, | 189 const char* name, |
| 139 const char* argument) { | 190 const char* argument) { |
| 140 SetArgument(i, name, strdup(argument)); | 191 SetArgument(i, name, strdup(argument)); |
| 141 } | 192 } |
| 142 | 193 |
| 143 | 194 |
| 144 void TimelineEvent::Complete() { | 195 void TimelineEvent::Complete() { |
| 145 stream_->CompleteEvent(this); | 196 TimelineEventRecorder* recorder = Timeline::recorder(); |
| 197 if (recorder != NULL) { |
| 198 recorder->CompleteEvent(this); |
| 199 } |
| 146 } | 200 } |
| 147 | 201 |
| 148 | 202 |
| 149 void TimelineEvent::FreeArguments() { | 203 void TimelineEvent::FreeArguments() { |
| 150 if (arguments_ == NULL) { | 204 if (arguments_ == NULL) { |
| 151 return; | 205 return; |
| 152 } | 206 } |
| 153 for (intptr_t i = 0; i < arguments_length_; i++) { | 207 for (intptr_t i = 0; i < arguments_length_; i++) { |
| 154 free(arguments_[i].value); | 208 free(arguments_[i].value); |
| 155 } | 209 } |
| 156 free(arguments_); | 210 free(arguments_); |
| 157 arguments_ = NULL; | 211 arguments_ = NULL; |
| 158 arguments_length_ = 0; | 212 arguments_length_ = 0; |
| 159 } | 213 } |
| 160 | 214 |
| 161 | 215 |
| 162 void TimelineEvent::StreamInit(TimelineStream* stream) { | 216 void TimelineEvent::StreamInit(TimelineStream* stream) { |
| 163 ASSERT(stream != NULL); | 217 if (stream != NULL) { |
| 164 stream_ = stream; | 218 category_ = stream->name(); |
| 219 } else { |
| 220 category_ = ""; |
| 221 } |
| 165 } | 222 } |
| 166 | 223 |
| 167 | 224 |
| 168 void TimelineEvent::Init(EventType event_type, | 225 void TimelineEvent::Init(EventType event_type, |
| 169 const char* label) { | 226 const char* label) { |
| 170 ASSERT(label != NULL); | 227 ASSERT(label != NULL); |
| 171 set_event_type(event_type); | 228 set_event_type(event_type); |
| 172 timestamp0_ = 0; | 229 timestamp0_ = 0; |
| 173 timestamp1_ = 0; | 230 timestamp1_ = 0; |
| 174 thread_ = OSThread::GetCurrentThreadId(); | 231 thread_ = OSThread::GetCurrentThreadId(); |
| 232 isolate_ = Isolate::Current(); |
| 175 label_ = label; | 233 label_ = label; |
| 176 FreeArguments(); | 234 FreeArguments(); |
| 177 } | 235 } |
| 178 | 236 |
| 179 | 237 |
| 180 void TimelineEvent::PrintJSON(JSONStream* stream) const { | 238 void TimelineEvent::PrintJSON(JSONStream* stream) const { |
| 181 JSONObject obj(stream); | 239 JSONObject obj(stream); |
| 182 int64_t pid = OS::ProcessId(); | 240 int64_t pid = OS::ProcessId(); |
| 183 int64_t tid = OSThread::ThreadIdToIntPtr(thread_); | 241 int64_t tid = OSThread::ThreadIdToIntPtr(thread_); |
| 184 obj.AddProperty("name", label_); | 242 obj.AddProperty("name", label_); |
| 185 obj.AddProperty("cat", stream_->name()); | 243 obj.AddProperty("cat", category_); |
| 186 obj.AddProperty64("tid", tid); | 244 obj.AddProperty64("tid", tid); |
| 187 obj.AddProperty64("pid", pid); | 245 obj.AddProperty64("pid", pid); |
| 188 obj.AddPropertyTimeMillis("ts", TimeOrigin()); | 246 obj.AddPropertyTimeMillis("ts", TimeOrigin()); |
| 189 | 247 |
| 190 switch (event_type()) { | 248 switch (event_type()) { |
| 191 case kDuration: { | 249 case kDuration: { |
| 192 obj.AddProperty("ph", "X"); | 250 obj.AddProperty("ph", "X"); |
| 193 obj.AddPropertyTimeMillis("dur", TimeDuration()); | 251 obj.AddPropertyTimeMillis("dur", TimeDuration()); |
| 194 } | 252 } |
| 195 break; | 253 break; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 int64_t TimelineEvent::TimeDuration() const { | 297 int64_t TimelineEvent::TimeDuration() const { |
| 240 if (timestamp1_ == 0) { | 298 if (timestamp1_ == 0) { |
| 241 // This duration is still open, use current time as end. | 299 // This duration is still open, use current time as end. |
| 242 return OS::GetCurrentTimeMicros() - timestamp0_; | 300 return OS::GetCurrentTimeMicros() - timestamp0_; |
| 243 } | 301 } |
| 244 return timestamp1_ - timestamp0_; | 302 return timestamp1_ - timestamp0_; |
| 245 } | 303 } |
| 246 | 304 |
| 247 | 305 |
| 248 TimelineStream::TimelineStream() | 306 TimelineStream::TimelineStream() |
| 249 : recorder_(NULL), | 307 : name_(NULL), |
| 250 name_(NULL), | 308 enabled_(false) { |
| 251 enabled_(false), | |
| 252 seq_(0) { | |
| 253 } | 309 } |
| 254 | 310 |
| 255 | 311 |
| 256 void TimelineStream::Init(const char* name, bool enabled) { | 312 void TimelineStream::Init(const char* name, bool enabled) { |
| 257 name_ = name; | 313 name_ = name; |
| 258 enabled_ = enabled; | 314 enabled_ = enabled; |
| 259 } | 315 } |
| 260 | 316 |
| 261 | 317 |
| 262 TimelineEvent* TimelineStream::StartEvent() { | 318 TimelineEvent* TimelineStream::StartEvent() { |
| 263 if (!enabled_ || (recorder_ == NULL)) { | 319 TimelineEventRecorder* recorder = Timeline::recorder(); |
| 320 if (!enabled_ || (recorder == NULL)) { |
| 264 return NULL; | 321 return NULL; |
| 265 } | 322 } |
| 266 ASSERT(name_ != NULL); | 323 ASSERT(name_ != NULL); |
| 267 TimelineEvent* event = recorder_->StartEvent(); | 324 TimelineEvent* event = recorder->StartEvent(); |
| 268 if (event != NULL) { | 325 if (event != NULL) { |
| 269 event->StreamInit(this); | 326 event->StreamInit(this); |
| 270 } | 327 } |
| 271 return event; | 328 return event; |
| 272 } | 329 } |
| 273 | 330 |
| 274 | 331 |
| 275 void TimelineStream::CompleteEvent(TimelineEvent* event) { | |
| 276 if (!enabled_ || (recorder_ == NULL)) { | |
| 277 return; | |
| 278 } | |
| 279 recorder_->CompleteEvent(event); | |
| 280 } | |
| 281 | |
| 282 | |
| 283 int64_t TimelineStream::GetNextSeq() { | |
| 284 seq_++; | |
| 285 if (seq_ < 0) { | |
| 286 seq_ = 0; | |
| 287 } | |
| 288 return seq_; | |
| 289 } | |
| 290 | |
| 291 | |
| 292 void TimelineDurationScope::FormatArgument(intptr_t i, | 332 void TimelineDurationScope::FormatArgument(intptr_t i, |
| 293 const char* name, | 333 const char* name, |
| 294 const char* fmt, ...) { | 334 const char* fmt, ...) { |
| 295 if (event_ == NULL) { | 335 if (event_ == NULL) { |
| 296 return; | 336 return; |
| 297 } | 337 } |
| 298 va_list args; | 338 va_list args; |
| 299 va_start(args, fmt); | 339 va_start(args, fmt); |
| 300 intptr_t len = OS::VSNPrint(NULL, 0, fmt, args); | 340 intptr_t len = OS::VSNPrint(NULL, 0, fmt, args); |
| 301 va_end(args); | 341 va_end(args); |
| 302 | 342 |
| 303 char* buffer = reinterpret_cast<char*>(malloc(len + 1)); | 343 char* buffer = reinterpret_cast<char*>(malloc(len + 1)); |
| 304 va_list args2; | 344 va_list args2; |
| 305 va_start(args2, fmt); | 345 va_start(args2, fmt); |
| 306 OS::VSNPrint(buffer, (len + 1), fmt, args2); | 346 OS::VSNPrint(buffer, (len + 1), fmt, args2); |
| 307 va_end(args2); | 347 va_end(args2); |
| 308 | 348 |
| 309 event_->SetArgument(i, name, buffer); | 349 event_->SetArgument(i, name, buffer); |
| 310 } | 350 } |
| 311 | 351 |
| 312 | 352 |
| 313 TimelineEventRecorder::TimelineEventRecorder() { | 353 TimelineEventFilter::TimelineEventFilter() { |
| 314 } | 354 } |
| 315 | 355 |
| 316 | 356 |
| 357 TimelineEventFilter::~TimelineEventFilter() { |
| 358 } |
| 359 |
| 360 |
| 361 IsolateTimelineEventFilter::IsolateTimelineEventFilter(Isolate* isolate) |
| 362 : isolate_(isolate) { |
| 363 } |
| 364 |
| 365 |
| 366 TimelineEventRecorder::TimelineEventRecorder() |
| 367 : global_block_(NULL), |
| 368 async_id_(0) { |
| 369 } |
| 370 |
| 371 |
| 317 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const { | 372 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const { |
| 318 } | 373 } |
| 319 | 374 |
| 320 | 375 |
| 321 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() { | 376 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() { |
| 322 // Grab the thread's timeline event block. | 377 // Grab the thread's timeline event block. |
| 323 Thread* thread = Thread::Current(); | 378 Thread* thread = Thread::Current(); |
| 379 ASSERT(thread != NULL); |
| 380 |
| 381 if (thread->isolate() == NULL) { |
| 382 // Non-isolate thread case. This should be infrequent. |
| 383 return GlobalBlockStartEvent(); |
| 384 } |
| 385 |
| 324 TimelineEventBlock* thread_block = thread->timeline_block(); | 386 TimelineEventBlock* thread_block = thread->timeline_block(); |
| 325 if ((thread_block == NULL) || thread_block->IsFull()) { | 387 |
| 326 // If it is full, request a new block. | 388 if ((thread_block != NULL) && thread_block->IsFull()) { |
| 327 thread_block = GetNewBlock(); | 389 MutexLocker ml(&lock_); |
| 390 // Thread has a block and it is full: |
| 391 // 1) Mark it as finished. |
| 392 thread_block->Finish(); |
| 393 // 2) Allocate a new block. |
| 394 thread_block = GetNewBlockLocked(thread->isolate()); |
| 395 thread->set_timeline_block(thread_block); |
| 396 } else if (thread_block == NULL) { |
| 397 MutexLocker ml(&lock_); |
| 398 // Thread has no block. Attempt to allocate one. |
| 399 thread_block = GetNewBlockLocked(thread->isolate()); |
| 328 thread->set_timeline_block(thread_block); | 400 thread->set_timeline_block(thread_block); |
| 329 } | 401 } |
| 330 if (thread_block == NULL) { | 402 if (thread_block != NULL) { |
| 331 // Could not allocate block. | 403 ASSERT(!thread_block->IsFull()); |
| 332 return NULL; | 404 return thread_block->StartEvent(); |
| 333 } | 405 } |
| 334 ASSERT(thread_block != NULL); | 406 return NULL; |
| 335 ASSERT(!thread_block->IsFull()); | 407 } |
| 336 return thread_block->StartEvent(); | 408 |
| 409 |
| 410 |
| 411 TimelineEvent* TimelineEventRecorder::GlobalBlockStartEvent() { |
| 412 MutexLocker ml(&lock_); |
| 413 if ((global_block_ != NULL) && global_block_->IsFull()) { |
| 414 // Global block is full. |
| 415 global_block_->Finish(); |
| 416 global_block_ = NULL; |
| 417 } |
| 418 if (global_block_ == NULL) { |
| 419 // Allocate a new block. |
| 420 global_block_ = GetNewBlockLocked(NULL); |
| 421 } |
| 422 if (global_block_ != NULL) { |
| 423 ASSERT(!global_block_->IsFull()); |
| 424 return global_block_->StartEvent(); |
| 425 } |
| 426 return NULL; |
| 337 } | 427 } |
| 338 | 428 |
| 339 | 429 |
| 340 void TimelineEventRecorder::WriteTo(const char* directory) { | 430 void TimelineEventRecorder::WriteTo(const char* directory) { |
| 341 Isolate* isolate = Isolate::Current(); | |
| 342 | |
| 343 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); | 431 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); |
| 344 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); | 432 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); |
| 345 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); | 433 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); |
| 346 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { | 434 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { |
| 347 return; | 435 return; |
| 348 } | 436 } |
| 349 | 437 |
| 438 FinishGlobalBlock(); |
| 439 |
| 350 JSONStream js; | 440 JSONStream js; |
| 351 PrintJSON(&js); | 441 TimelineEventFilter filter; |
| 442 PrintJSON(&js, &filter); |
| 352 | 443 |
| 353 const char* format = "%s/dart-timeline-%" Pd "-%" Pd ".json"; | 444 const char* format = "%s/dart-timeline-%" Pd ".json"; |
| 354 intptr_t pid = OS::ProcessId(); | 445 intptr_t pid = OS::ProcessId(); |
| 355 intptr_t len = OS::SNPrint(NULL, 0, format, | 446 intptr_t len = OS::SNPrint(NULL, 0, format, directory, pid); |
| 356 directory, pid, isolate->main_port()); | 447 char* filename = reinterpret_cast<char*>(malloc(len + 1)); |
| 357 char* filename = Thread::Current()->zone()->Alloc<char>(len + 1); | 448 OS::SNPrint(filename, len + 1, format, directory, pid); |
| 358 OS::SNPrint(filename, len + 1, format, | |
| 359 directory, pid, isolate->main_port()); | |
| 360 void* file = (*file_open)(filename, true); | 449 void* file = (*file_open)(filename, true); |
| 361 if (file == NULL) { | 450 if (file == NULL) { |
| 362 OS::Print("Failed to write timeline file: %s\n", filename); | 451 OS::Print("Failed to write timeline file: %s\n", filename); |
| 452 free(filename); |
| 363 return; | 453 return; |
| 364 } | 454 } |
| 455 free(filename); |
| 365 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file); | 456 (*file_write)(js.buffer()->buf(), js.buffer()->length(), file); |
| 366 (*file_close)(file); | 457 (*file_close)(file); |
| 367 } | 458 } |
| 368 | 459 |
| 369 | 460 |
| 461 void TimelineEventRecorder::FinishGlobalBlock() { |
| 462 MutexLocker ml(&lock_); |
| 463 if (global_block_ != NULL) { |
| 464 global_block_->Finish(); |
| 465 global_block_ = NULL; |
| 466 } |
| 467 } |
| 468 |
| 469 |
| 470 int64_t TimelineEventRecorder::GetNextAsyncId() { |
| 471 // TODO(johnmccutchan): Gracefully handle wrap around. |
| 472 uint32_t next = static_cast<uint32_t>( |
| 473 AtomicOperations::FetchAndIncrement(&async_id_)); |
| 474 return static_cast<int64_t>(next); |
| 475 } |
| 476 |
| 477 |
| 478 TimelineEventBlock* TimelineEventRecorder::GetNewBlock() { |
| 479 MutexLocker ml(&lock_); |
| 480 return GetNewBlockLocked(Isolate::Current()); |
| 481 } |
| 482 |
| 370 | 483 |
| 371 TimelineEventRingRecorder::TimelineEventRingRecorder(intptr_t capacity) | 484 TimelineEventRingRecorder::TimelineEventRingRecorder(intptr_t capacity) |
| 372 : blocks_(NULL), | 485 : blocks_(NULL), |
| 373 event_objects_(Array::null()), | |
| 374 capacity_(capacity), | 486 capacity_(capacity), |
| 375 num_blocks_(0), | 487 num_blocks_(0), |
| 376 block_cursor_(0) { | 488 block_cursor_(0) { |
| 377 // Capacity must be a multiple of TimelineEventBlock::kBlockSize | 489 // Capacity must be a multiple of TimelineEventBlock::kBlockSize |
| 378 ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0); | 490 ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0); |
| 379 // Allocate blocks array. | 491 // Allocate blocks array. |
| 380 num_blocks_ = capacity / TimelineEventBlock::kBlockSize; | 492 num_blocks_ = capacity / TimelineEventBlock::kBlockSize; |
| 381 blocks_ = | 493 blocks_ = |
| 382 reinterpret_cast<TimelineEventBlock**>( | 494 reinterpret_cast<TimelineEventBlock**>( |
| 383 calloc(num_blocks_, sizeof(TimelineEventBlock*))); | 495 calloc(num_blocks_, sizeof(TimelineEventBlock*))); |
| 384 // Allocate each block. | 496 // Allocate each block. |
| 385 for (intptr_t i = 0; i < num_blocks_; i++) { | 497 for (intptr_t i = 0; i < num_blocks_; i++) { |
| 386 blocks_[i] = new TimelineEventBlock(i); | 498 blocks_[i] = new TimelineEventBlock(i); |
| 387 } | 499 } |
| 388 // Chain blocks together. | 500 // Chain blocks together. |
| 389 for (intptr_t i = 0; i < num_blocks_ - 1; i++) { | 501 for (intptr_t i = 0; i < num_blocks_ - 1; i++) { |
| 390 blocks_[i]->set_next(blocks_[i + 1]); | 502 blocks_[i]->set_next(blocks_[i + 1]); |
| 391 } | 503 } |
| 392 const Array& array = Array::Handle(Array::New(capacity, Heap::kOld)); | |
| 393 event_objects_ = array.raw(); | |
| 394 } | 504 } |
| 395 | 505 |
| 396 | 506 |
| 397 TimelineEventRingRecorder::~TimelineEventRingRecorder() { | 507 TimelineEventRingRecorder::~TimelineEventRingRecorder() { |
| 398 // Delete all blocks. | 508 // Delete all blocks. |
| 399 for (intptr_t i = 0; i < num_blocks_; i++) { | 509 for (intptr_t i = 0; i < num_blocks_; i++) { |
| 400 TimelineEventBlock* block = blocks_[i]; | 510 TimelineEventBlock* block = blocks_[i]; |
| 401 delete block; | 511 delete block; |
| 402 } | 512 } |
| 403 free(blocks_); | 513 free(blocks_); |
| 404 event_objects_ = Array::null(); | |
| 405 } | 514 } |
| 406 | 515 |
| 407 | 516 |
| 408 void TimelineEventRingRecorder::PrintJSONEvents(JSONArray* events) const { | 517 void TimelineEventRingRecorder::PrintJSONEvents( |
| 518 JSONArray* events, |
| 519 TimelineEventFilter* filter) const { |
| 409 intptr_t block_offset = FindOldestBlockIndex(); | 520 intptr_t block_offset = FindOldestBlockIndex(); |
| 410 if (block_offset == -1) { | 521 if (block_offset == -1) { |
| 411 // All blocks are empty. | 522 // All blocks are empty. |
| 412 return; | 523 return; |
| 413 } | 524 } |
| 414 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { | 525 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { |
| 415 TimelineEventBlock* block = | 526 TimelineEventBlock* block = |
| 416 blocks_[(block_idx + block_offset) % num_blocks_]; | 527 blocks_[(block_idx + block_offset) % num_blocks_]; |
| 417 if (block->IsEmpty()) { | 528 if (!filter->IncludeBlock(block)) { |
| 418 // Skip empty blocks. | |
| 419 continue; | 529 continue; |
| 420 } | 530 } |
| 421 for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) { | 531 for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) { |
| 422 TimelineEvent* event = block->At(event_idx); | 532 TimelineEvent* event = block->At(event_idx); |
| 423 if (event->IsValid()) { | 533 if (filter->IncludeEvent(event)) { |
| 424 events->AddValue(event); | 534 events->AddValue(event); |
| 425 } | 535 } |
| 426 } | 536 } |
| 427 } | 537 } |
| 428 } | 538 } |
| 429 | 539 |
| 430 | 540 |
| 431 void TimelineEventRingRecorder::PrintJSON(JSONStream* js) { | 541 void TimelineEventRingRecorder::PrintJSON(JSONStream* js, |
| 542 TimelineEventFilter* filter) { |
| 432 MutexLocker ml(&lock_); | 543 MutexLocker ml(&lock_); |
| 433 JSONObject topLevel(js); | 544 JSONObject topLevel(js); |
| 434 topLevel.AddProperty("type", "_Timeline"); | 545 topLevel.AddProperty("type", "_Timeline"); |
| 435 { | 546 { |
| 436 JSONArray events(&topLevel, "traceEvents"); | 547 JSONArray events(&topLevel, "traceEvents"); |
| 437 PrintJSONMeta(&events); | 548 PrintJSONMeta(&events); |
| 438 PrintJSONEvents(&events); | 549 PrintJSONEvents(&events, filter); |
| 439 } | 550 } |
| 440 } | 551 } |
| 441 | 552 |
| 442 | 553 |
| 443 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlock() { | 554 TimelineEventBlock* TimelineEventRingRecorder::GetHeadBlockLocked() { |
| 444 MutexLocker ml(&lock_); | |
| 445 return GetNewBlockLocked(); | |
| 446 } | |
| 447 | |
| 448 | |
| 449 TimelineEventBlock* TimelineEventRingRecorder::GetHeadBlock() { | |
| 450 return blocks_[0]; | 555 return blocks_[0]; |
| 451 } | 556 } |
| 452 | 557 |
| 453 | 558 |
| 454 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { | 559 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked( |
| 560 Isolate* isolate) { |
| 561 // TODO(johnmccutchan): This function should only hand out blocks |
| 562 // which have been marked as finished. |
| 455 if (block_cursor_ == num_blocks_) { | 563 if (block_cursor_ == num_blocks_) { |
| 456 block_cursor_ = 0; | 564 block_cursor_ = 0; |
| 457 } | 565 } |
| 458 TimelineEventBlock* block = blocks_[block_cursor_++]; | 566 TimelineEventBlock* block = blocks_[block_cursor_++]; |
| 459 block->Reset(); | 567 block->Reset(); |
| 568 block->Open(isolate); |
| 460 return block; | 569 return block; |
| 461 } | 570 } |
| 462 | 571 |
| 463 | 572 |
| 464 intptr_t TimelineEventRingRecorder::FindOldestBlockIndex() const { | 573 intptr_t TimelineEventRingRecorder::FindOldestBlockIndex() const { |
| 465 int64_t earliest_time = kMaxInt64; | 574 int64_t earliest_time = kMaxInt64; |
| 466 intptr_t earliest_index = -1; | 575 intptr_t earliest_index = -1; |
| 467 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { | 576 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { |
| 468 TimelineEventBlock* block = blocks_[block_idx]; | 577 TimelineEventBlock* block = blocks_[block_idx]; |
| 469 if (block->IsEmpty()) { | 578 if (block->IsEmpty()) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 490 | 599 |
| 491 | 600 |
| 492 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() { | 601 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() { |
| 493 } | 602 } |
| 494 | 603 |
| 495 | 604 |
| 496 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() { | 605 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() { |
| 497 } | 606 } |
| 498 | 607 |
| 499 | 608 |
| 500 void TimelineEventStreamingRecorder::PrintJSON(JSONStream* js) { | 609 void TimelineEventStreamingRecorder::PrintJSON(JSONStream* js, |
| 610 TimelineEventFilter* filter) { |
| 501 JSONObject topLevel(js); | 611 JSONObject topLevel(js); |
| 502 topLevel.AddProperty("type", "_Timeline"); | 612 topLevel.AddProperty("type", "_Timeline"); |
| 503 { | 613 { |
| 504 JSONArray events(&topLevel, "traceEvents"); | 614 JSONArray events(&topLevel, "traceEvents"); |
| 505 PrintJSONMeta(&events); | 615 PrintJSONMeta(&events); |
| 506 } | 616 } |
| 507 } | 617 } |
| 508 | 618 |
| 509 | 619 |
| 510 TimelineEvent* TimelineEventStreamingRecorder::StartEvent() { | 620 TimelineEvent* TimelineEventStreamingRecorder::StartEvent() { |
| 511 TimelineEvent* event = new TimelineEvent(); | 621 TimelineEvent* event = new TimelineEvent(); |
| 512 return event; | 622 return event; |
| 513 } | 623 } |
| 514 | 624 |
| 515 | 625 |
| 516 void TimelineEventStreamingRecorder::CompleteEvent(TimelineEvent* event) { | 626 void TimelineEventStreamingRecorder::CompleteEvent(TimelineEvent* event) { |
| 517 StreamEvent(event); | 627 StreamEvent(event); |
| 518 delete event; | 628 delete event; |
| 519 } | 629 } |
| 520 | 630 |
| 521 | 631 |
| 522 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder() | 632 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder() |
| 523 : head_(NULL), | 633 : head_(NULL), |
| 524 block_index_(0) { | 634 block_index_(0) { |
| 525 GetNewBlock(); | 635 GetNewBlock(); |
| 526 } | 636 } |
| 527 | 637 |
| 528 | 638 |
| 529 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js) { | 639 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js, |
| 640 TimelineEventFilter* filter) { |
| 530 MutexLocker ml(&lock_); | 641 MutexLocker ml(&lock_); |
| 531 JSONObject topLevel(js); | 642 JSONObject topLevel(js); |
| 532 topLevel.AddProperty("type", "_Timeline"); | 643 topLevel.AddProperty("type", "_Timeline"); |
| 533 { | 644 { |
| 534 JSONArray events(&topLevel, "traceEvents"); | 645 JSONArray events(&topLevel, "traceEvents"); |
| 535 PrintJSONMeta(&events); | 646 PrintJSONMeta(&events); |
| 536 PrintJSONEvents(&events); | 647 PrintJSONEvents(&events, filter); |
| 537 } | 648 } |
| 538 } | 649 } |
| 539 | 650 |
| 540 | 651 |
| 541 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlock() { | 652 TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() { |
| 542 MutexLocker ml(&lock_); | |
| 543 return GetNewBlockLocked(); | |
| 544 } | |
| 545 | |
| 546 | |
| 547 TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlock() { | |
| 548 return head_; | 653 return head_; |
| 549 } | 654 } |
| 550 | 655 |
| 551 | 656 |
| 552 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() { | 657 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() { |
| 553 return ThreadBlockStartEvent(); | 658 return ThreadBlockStartEvent(); |
| 554 } | 659 } |
| 555 | 660 |
| 556 | 661 |
| 557 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) { | 662 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) { |
| 558 // no-op. | 663 // no-op. |
| 559 } | 664 } |
| 560 | 665 |
| 561 | 666 |
| 562 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked() { | 667 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked( |
| 668 Isolate* isolate) { |
| 563 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); | 669 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); |
| 564 block->set_next(head_); | 670 block->set_next(head_); |
| 671 block->Open(isolate); |
| 565 head_ = block; | 672 head_ = block; |
| 566 return head_; | 673 return head_; |
| 567 } | 674 } |
| 568 | 675 |
| 569 | 676 |
| 570 void TimelineEventEndlessRecorder::PrintJSONEvents(JSONArray* events) const { | 677 void TimelineEventEndlessRecorder::PrintJSONEvents( |
| 678 JSONArray* events, |
| 679 TimelineEventFilter* filter) const { |
| 571 TimelineEventBlock* current = head_; | 680 TimelineEventBlock* current = head_; |
| 681 |
| 572 while (current != NULL) { | 682 while (current != NULL) { |
| 683 if (!filter->IncludeBlock(current)) { |
| 684 current = current->next(); |
| 685 continue; |
| 686 } |
| 573 intptr_t length = current->length(); | 687 intptr_t length = current->length(); |
| 574 for (intptr_t i = 0; i < length; i++) { | 688 for (intptr_t i = 0; i < length; i++) { |
| 575 TimelineEvent* event = current->At(i); | 689 TimelineEvent* event = current->At(i); |
| 576 if (!event->IsValid()) { | 690 if (!filter->IncludeEvent(event)) { |
| 577 continue; | 691 continue; |
| 578 } | 692 } |
| 579 events->AddValue(event); | 693 events->AddValue(event); |
| 580 } | 694 } |
| 581 current = current->next(); | 695 current = current->next(); |
| 582 } | 696 } |
| 583 } | 697 } |
| 584 | 698 |
| 585 | 699 |
| 586 void TimelineEventEndlessRecorder::Clear() { | 700 void TimelineEventEndlessRecorder::Clear() { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 652 return true; | 766 return true; |
| 653 } | 767 } |
| 654 | 768 |
| 655 | 769 |
| 656 void TimelineEventBlock::Reset() { | 770 void TimelineEventBlock::Reset() { |
| 657 for (intptr_t i = 0; i < kBlockSize; i++) { | 771 for (intptr_t i = 0; i < kBlockSize; i++) { |
| 658 // Clear any extra data. | 772 // Clear any extra data. |
| 659 events_[i].Reset(); | 773 events_[i].Reset(); |
| 660 } | 774 } |
| 661 length_ = 0; | 775 length_ = 0; |
| 776 isolate_ = NULL; |
| 777 open_ = false; |
| 662 } | 778 } |
| 663 | 779 |
| 664 | 780 |
| 781 void TimelineEventBlock::Open(Isolate* isolate) { |
| 782 isolate_ = isolate; |
| 783 open_ = true; |
| 784 } |
| 785 |
| 786 |
| 787 void TimelineEventBlock::Finish() { |
| 788 open_ = false; |
| 789 } |
| 790 |
| 791 |
| 665 TimelineEventBlockIterator::TimelineEventBlockIterator( | 792 TimelineEventBlockIterator::TimelineEventBlockIterator( |
| 666 TimelineEventRecorder* recorder) | 793 TimelineEventRecorder* recorder) |
| 667 : current_(NULL), | 794 : current_(NULL), |
| 668 recorder_(NULL) { | 795 recorder_(NULL) { |
| 669 Reset(recorder); | 796 Reset(recorder); |
| 670 } | 797 } |
| 671 | 798 |
| 672 | 799 |
| 673 TimelineEventBlockIterator::~TimelineEventBlockIterator() { | 800 TimelineEventBlockIterator::~TimelineEventBlockIterator() { |
| 674 Reset(NULL); | 801 Reset(NULL); |
| 675 } | 802 } |
| 676 | 803 |
| 677 | 804 |
| 678 void TimelineEventBlockIterator::Reset(TimelineEventRecorder* recorder) { | 805 void TimelineEventBlockIterator::Reset(TimelineEventRecorder* recorder) { |
| 679 // Clear current. | 806 // Clear current. |
| 680 current_ = NULL; | 807 current_ = NULL; |
| 681 if (recorder_ != NULL) { | 808 if (recorder_ != NULL) { |
| 682 // Unlock old recorder. | 809 // Unlock old recorder. |
| 683 recorder_->lock_.Unlock(); | 810 recorder_->lock_.Unlock(); |
| 684 } | 811 } |
| 685 recorder_ = recorder; | 812 recorder_ = recorder; |
| 686 if (recorder_ == NULL) { | 813 if (recorder_ == NULL) { |
| 687 return; | 814 return; |
| 688 } | 815 } |
| 689 // Lock new recorder. | 816 // Lock new recorder. |
| 690 recorder_->lock_.Lock(); | 817 recorder_->lock_.Lock(); |
| 691 // Queue up first block. | 818 // Queue up first block. |
| 692 current_ = recorder_->GetHeadBlock(); | 819 current_ = recorder_->GetHeadBlockLocked(); |
| 693 } | 820 } |
| 694 | 821 |
| 695 | 822 |
| 696 bool TimelineEventBlockIterator::HasNext() const { | 823 bool TimelineEventBlockIterator::HasNext() const { |
| 697 return current_ != NULL; | 824 return current_ != NULL; |
| 698 } | 825 } |
| 699 | 826 |
| 700 | 827 |
| 701 TimelineEventBlock* TimelineEventBlockIterator::Next() { | 828 TimelineEventBlock* TimelineEventBlockIterator::Next() { |
| 702 ASSERT(current_ != NULL); | 829 ASSERT(current_ != NULL); |
| 703 TimelineEventBlock* r = current_; | 830 TimelineEventBlock* r = current_; |
| 704 current_ = current_->next(); | 831 current_ = current_->next(); |
| 705 return r; | 832 return r; |
| 706 } | 833 } |
| 707 | 834 |
| 708 } // namespace dart | 835 } // namespace dart |
| OLD | NEW |