Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 <cstdio> | |
| 6 | |
| 7 #include "platform/utils.h" | 5 #include "platform/utils.h" |
| 8 | 6 |
| 7 #include "vm/allocation.h" | |
| 9 #include "vm/atomic.h" | 8 #include "vm/atomic.h" |
| 9 #include "vm/code_patcher.h" | |
| 10 #include "vm/isolate.h" | 10 #include "vm/isolate.h" |
| 11 #include "vm/json_stream.h" | 11 #include "vm/json_stream.h" |
| 12 #include "vm/native_symbol.h" | 12 #include "vm/native_symbol.h" |
| 13 #include "vm/object.h" | 13 #include "vm/object.h" |
| 14 #include "vm/os.h" | 14 #include "vm/os.h" |
| 15 #include "vm/profiler.h" | 15 #include "vm/profiler.h" |
| 16 #include "vm/signal_handler.h" | 16 #include "vm/signal_handler.h" |
| 17 #include "vm/simulator.h" | 17 #include "vm/simulator.h" |
| 18 | 18 |
| 19 namespace dart { | 19 namespace dart { |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 211 if ((stack_lower == 0) || (stack_upper == 0)) { | 211 if ((stack_lower == 0) || (stack_upper == 0)) { |
| 212 stack_lower = 0; | 212 stack_lower = 0; |
| 213 stack_upper = 0; | 213 stack_upper = 0; |
| 214 } | 214 } |
| 215 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, | 215 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, |
| 216 state.pc, state.fp, state.sp); | 216 state.pc, state.fp, state.sp); |
| 217 stackWalker.walk(); | 217 stackWalker.walk(); |
| 218 } | 218 } |
| 219 | 219 |
| 220 | 220 |
| 221 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream) { | 221 struct AddressEntry { |
| 222 uintptr_t pc; | |
| 223 uintptr_t ticks; | |
| 224 }; | |
| 225 | |
| 226 | |
| 227 // A region of code. Each region is a kind of code (Dart, Collected, or Native). | |
| 228 class CodeRegion : public ZoneAllocated { | |
| 229 public: | |
| 230 enum Kind { | |
| 231 kDartCode, | |
| 232 kCollectedCode, | |
| 233 kNativeCode | |
| 234 }; | |
| 235 | |
| 236 CodeRegion(Kind kind, uintptr_t start, uintptr_t end) : | |
| 237 kind_(kind), | |
| 238 start_(start), | |
| 239 end_(end), | |
| 240 inclusive_ticks_(0), | |
| 241 exclusive_ticks_(0), | |
| 242 name_(NULL), | |
| 243 address_table_(new ZoneGrowableArray<AddressEntry>()) { | |
| 244 } | |
| 245 | |
| 246 ~CodeRegion() { | |
|
Ivan Posva
2014/01/03 19:24:54
ZoneAllocated and thus CodeRegion destructors are
Cutch
2014/01/03 19:42:30
Done.
| |
| 247 if (name_ != NULL) { | |
| 248 free(const_cast<char*>(name_)); | |
| 249 name_ = NULL; | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 uintptr_t start() const { return start_; } | |
| 254 void set_start(uintptr_t start) { | |
| 255 start_ = start; | |
| 256 } | |
| 257 | |
| 258 uintptr_t end() const { return end_; } | |
| 259 void set_end(uintptr_t end) { | |
| 260 end_ = end; | |
| 261 } | |
| 262 | |
| 263 void AdjustExtent(uintptr_t start, uintptr_t end) { | |
| 264 if (start < start_) { | |
| 265 start_ = start; | |
| 266 } | |
| 267 if (end > end_) { | |
| 268 end_ = end; | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 bool contains(uintptr_t pc) const { | |
| 273 return (pc >= start_) && (pc < end_); | |
| 274 } | |
| 275 | |
| 276 intptr_t inclusive_ticks() const { return inclusive_ticks_; } | |
| 277 void set_inclusive_ticks(intptr_t inclusive_ticks) { | |
| 278 inclusive_ticks_ = inclusive_ticks; | |
| 279 } | |
| 280 | |
| 281 intptr_t exclusive_ticks() const { return exclusive_ticks_; } | |
| 282 void set_exclusive_ticks(intptr_t exclusive_ticks) { | |
| 283 exclusive_ticks_ = exclusive_ticks; | |
| 284 } | |
| 285 | |
| 286 const char* name() const { return name_; } | |
| 287 void SetName(const char* name) { | |
| 288 if (name == NULL) { | |
| 289 name_ = NULL; | |
| 290 } | |
| 291 intptr_t len = strlen(name); | |
| 292 name_ = Isolate::Current()->current_zone()->Alloc<const char>(len + 1); | |
| 293 strncpy(const_cast<char*>(name_), name, len); | |
| 294 const_cast<char*>(name_)[len] = '\0'; | |
| 295 } | |
| 296 | |
| 297 Kind kind() const { return kind_; } | |
| 298 | |
| 299 static const char* KindToCString(Kind kind) { | |
| 300 switch (kind) { | |
| 301 case kDartCode: | |
| 302 return "Dart"; | |
| 303 case kCollectedCode: | |
| 304 return "Collected"; | |
| 305 case kNativeCode: | |
| 306 return "Native"; | |
| 307 } | |
| 308 UNREACHABLE(); | |
| 309 return NULL; | |
| 310 } | |
| 311 | |
| 312 void AddTick(bool exclusive) { | |
| 313 if (exclusive) { | |
| 314 exclusive_ticks_++; | |
| 315 } else { | |
| 316 inclusive_ticks_++; | |
| 317 } | |
| 318 } | |
| 319 | |
| 320 void AddTickAtAddress(uintptr_t pc) { | |
| 321 const intptr_t length = address_table_->length(); | |
| 322 intptr_t i = 0; | |
| 323 for (; i < length; i++) { | |
| 324 AddressEntry& entry = (*address_table_)[i]; | |
| 325 if (entry.pc == pc) { | |
| 326 entry.ticks++; | |
| 327 return; | |
| 328 } | |
| 329 if (entry.pc > pc) { | |
| 330 break; | |
| 331 } | |
| 332 } | |
| 333 AddressEntry entry; | |
| 334 entry.pc = pc; | |
| 335 entry.ticks = 1; | |
| 336 if (i < length) { | |
| 337 // Insert at i. | |
| 338 address_table_->InsertAt(i, entry); | |
| 339 } else { | |
| 340 // Add to end. | |
| 341 address_table_->Add(entry); | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 | |
| 346 void PrintToJSONArray(JSONArray* events, bool full) { | |
| 347 JSONObject obj(events); | |
| 348 obj.AddProperty("type", "ProfileCode"); | |
| 349 obj.AddProperty("kind", KindToCString(kind())); | |
| 350 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); | |
| 351 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); | |
| 352 if (kind() == kDartCode) { | |
| 353 // Look up code in Dart heap. | |
| 354 Code& code = Code::Handle(Code::LookupCode(start())); | |
| 355 Function& func = Function::Handle(); | |
| 356 ASSERT(!code.IsNull()); | |
| 357 func ^= code.function(); | |
| 358 if (func.IsNull()) { | |
| 359 if (name() == NULL) { | |
| 360 GenerateAndSetSymbolName("Stub"); | |
| 361 } | |
| 362 obj.AddPropertyF("start", "%" Px "", start()); | |
| 363 obj.AddPropertyF("end", "%" Px "", end()); | |
| 364 obj.AddProperty("name", name()); | |
| 365 } else { | |
| 366 obj.AddProperty("code", code, !full); | |
| 367 } | |
| 368 } else if (kind() == kCollectedCode) { | |
| 369 if (name() == NULL) { | |
| 370 GenerateAndSetSymbolName("Collected"); | |
| 371 } | |
| 372 obj.AddPropertyF("start", "%" Px "", start()); | |
| 373 obj.AddPropertyF("end", "%" Px "", end()); | |
| 374 obj.AddProperty("name", name()); | |
| 375 } else { | |
| 376 ASSERT(kind() == kNativeCode); | |
| 377 if (name() == NULL) { | |
| 378 GenerateAndSetSymbolName("Native"); | |
| 379 } | |
| 380 obj.AddPropertyF("start", "%" Px "", start()); | |
| 381 obj.AddPropertyF("end", "%" Px "", end()); | |
| 382 obj.AddProperty("name", name()); | |
| 383 } | |
| 384 { | |
| 385 JSONArray ticks(&obj, "ticks"); | |
| 386 for (intptr_t i = 0; i < address_table_->length(); i++) { | |
| 387 const AddressEntry& entry = (*address_table_)[i]; | |
| 388 ticks.AddValueF("%" Px "", entry.pc); | |
| 389 ticks.AddValueF("%" Pd "", entry.ticks); | |
| 390 } | |
| 391 } | |
| 392 } | |
| 393 | |
| 394 private: | |
| 395 void GenerateAndSetSymbolName(const char* prefix) { | |
| 396 const intptr_t kBuffSize = 512; | |
| 397 char buff[kBuffSize]; | |
| 398 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", | |
| 399 prefix, start(), end()); | |
| 400 SetName(buff); | |
| 401 } | |
| 402 | |
| 403 Kind kind_; | |
| 404 uintptr_t start_; | |
| 405 uintptr_t end_; | |
| 406 intptr_t inclusive_ticks_; | |
| 407 intptr_t exclusive_ticks_; | |
| 408 const char* name_; | |
| 409 ZoneGrowableArray<AddressEntry>* address_table_; | |
| 410 | |
| 411 DISALLOW_COPY_AND_ASSIGN(CodeRegion); | |
| 412 }; | |
| 413 | |
| 414 | |
| 415 // All code regions. Code region tables are built on demand when a profile | |
| 416 // is requested (through the service or on isolate shutdown). | |
| 417 class ProfilerCodeRegionTable : public ValueObject { | |
| 418 public: | |
| 419 explicit ProfilerCodeRegionTable(Isolate* isolate) : | |
| 420 heap_(isolate->heap()), | |
| 421 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) { | |
| 422 } | |
| 423 | |
| 424 ~ProfilerCodeRegionTable() { | |
| 425 } | |
| 426 | |
| 427 void AddTick(uintptr_t pc, bool exclusive) { | |
| 428 intptr_t index = FindIndex(pc); | |
| 429 if (index < 0) { | |
| 430 CodeRegion* code_region = CreateCodeRegion(pc); | |
| 431 ASSERT(code_region != NULL); | |
| 432 index = InsertCodeRegion(code_region); | |
| 433 } | |
| 434 ASSERT(index >= 0); | |
| 435 ASSERT(index < code_region_table_->length()); | |
| 436 (*code_region_table_)[index]->AddTick(exclusive); | |
| 437 (*code_region_table_)[index]->AddTickAtAddress(pc); | |
|
Ivan Posva
2014/01/03 19:24:54
This will distort the exclusive ticks with too man
Cutch
2014/01/03 19:42:30
Good catch. Fixed by conditionally ticking the add
| |
| 438 } | |
| 439 | |
| 440 intptr_t Length() const { return code_region_table_->length(); } | |
| 441 | |
| 442 CodeRegion* At(intptr_t idx) { | |
| 443 return (*code_region_table_)[idx]; | |
| 444 } | |
| 445 | |
| 446 private: | |
| 447 intptr_t FindIndex(uintptr_t pc) { | |
| 448 const intptr_t length = code_region_table_->length(); | |
| 449 for (intptr_t i = 0; i < length; i++) { | |
| 450 const CodeRegion* code_region = (*code_region_table_)[i]; | |
| 451 if (code_region->contains(pc)) { | |
| 452 return i; | |
| 453 } | |
| 454 } | |
| 455 return -1; | |
| 456 } | |
| 457 | |
| 458 CodeRegion* CreateCodeRegion(uintptr_t pc) { | |
| 459 Code& code = Code::Handle(Code::LookupCode(pc)); | |
| 460 if (!code.IsNull()) { | |
| 461 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), | |
| 462 code.EntryPoint() + code.Size()); | |
| 463 } | |
| 464 if (heap_->CodeContains(pc)) { | |
| 465 const intptr_t kDartCodeAlignment = 0x10; | |
| 466 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); | |
| 467 return new CodeRegion(CodeRegion::kCollectedCode, | |
| 468 (pc & kDartCodeAlignmentMask), | |
| 469 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment); | |
| 470 } | |
| 471 uintptr_t native_start = 0; | |
| 472 char* native_name = NativeSymbolResolver::LookupSymbolName(pc, | |
| 473 &native_start); | |
| 474 if (native_name == NULL) { | |
| 475 return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1); | |
| 476 } | |
| 477 ASSERT(pc >= native_start); | |
| 478 CodeRegion* code_region = | |
| 479 new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1); | |
| 480 code_region->SetName(native_name); | |
| 481 free(native_name); | |
| 482 return code_region; | |
| 483 } | |
| 484 | |
| 485 intptr_t InsertCodeRegion(CodeRegion* code_region) { | |
| 486 const intptr_t length = code_region_table_->length(); | |
| 487 const uintptr_t start = code_region->start(); | |
| 488 const uintptr_t end = code_region->end(); | |
| 489 intptr_t i = 0; | |
| 490 for (; i < length; i++) { | |
| 491 CodeRegion* region = (*code_region_table_)[i]; | |
| 492 if (region->contains(start) || region->contains(end - 1)) { | |
| 493 // We should only see overlapping native code regions. | |
| 494 ASSERT(region->kind() == CodeRegion::kNativeCode); | |
| 495 // When code regions overlap, they should be of the same kind. | |
| 496 ASSERT(region->kind() == code_region->kind()); | |
| 497 // Overlapping code region. | |
| 498 region->AdjustExtent(start, end); | |
| 499 return i; | |
| 500 } else if (start >= region->end()) { | |
| 501 // Insert here. | |
| 502 break; | |
| 503 } | |
| 504 } | |
| 505 if (i != length) { | |
| 506 code_region_table_->InsertAt(i, code_region); | |
| 507 return i; | |
| 508 } | |
| 509 code_region_table_->Add(code_region); | |
| 510 return code_region_table_->length() - 1; | |
| 511 } | |
| 512 | |
| 513 Heap* heap_; | |
| 514 ZoneGrowableArray<CodeRegion*>* code_region_table_; | |
| 515 }; | |
| 516 | |
| 517 | |
| 518 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, | |
| 519 bool full) { | |
| 222 ASSERT(isolate == Isolate::Current()); | 520 ASSERT(isolate == Isolate::Current()); |
| 223 UNIMPLEMENTED(); | 521 // Disable profile interrupts while processing the buffer. |
| 522 EndExecution(isolate); | |
| 523 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | |
| 524 IsolateProfilerData* profiler_data = isolate->profiler_data(); | |
| 525 if (profiler_data == NULL) { | |
| 526 JSONObject error(stream); | |
| 527 error.AddProperty("type", "Error"); | |
| 528 error.AddProperty("text", "Isolate does not have profiling enabled."); | |
| 529 return; | |
| 530 } | |
| 531 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | |
| 532 ASSERT(sample_buffer != NULL); | |
| 533 { | |
| 534 StackZone zone(isolate); | |
| 535 { | |
| 536 // Build code region table. | |
| 537 ProfilerCodeRegionTable code_region_table(isolate); | |
| 538 intptr_t samples = | |
| 539 ProcessSamples(isolate, &code_region_table, sample_buffer); | |
| 540 { | |
| 541 // Serialize to JSON. | |
| 542 JSONObject obj(stream); | |
| 543 obj.AddProperty("type", "Profile"); | |
| 544 obj.AddProperty("samples", samples); | |
| 545 JSONArray codes(&obj, "codes"); | |
| 546 for (intptr_t i = 0; i < code_region_table.Length(); i++) { | |
| 547 CodeRegion* region = code_region_table.At(i); | |
| 548 ASSERT(region != NULL); | |
| 549 region->PrintToJSONArray(&codes, full); | |
| 550 } | |
| 551 } | |
| 552 } | |
| 553 } | |
| 554 // Enable profile interrupts. | |
| 555 BeginExecution(isolate); | |
| 224 } | 556 } |
| 225 | 557 |
| 226 | 558 |
| 227 static const char* FindSymbolName(uintptr_t pc, bool* symbol_name_allocated) { | 559 intptr_t Profiler::ProcessSamples(Isolate* isolate, |
| 228 // TODO(johnmccutchan): Differentiate between symbols which can't be found | 560 ProfilerCodeRegionTable* code_region_table, |
| 229 // and symbols which were GCed. (Heap::CodeContains). | 561 SampleBuffer* sample_buffer) { |
| 230 ASSERT(symbol_name_allocated != NULL); | 562 int64_t start = OS::GetCurrentTimeMillis(); |
| 231 const char* symbol_name = "Unknown"; | 563 intptr_t samples = 0; |
| 232 *symbol_name_allocated = false; | 564 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) { |
| 233 if (pc == 0) { | 565 Sample sample = sample_buffer->GetSample(i); |
| 234 return const_cast<char*>(Sample::kNoFrame); | 566 if (sample.isolate != isolate) { |
| 235 } | 567 continue; |
| 236 const Code& code = Code::Handle(Code::LookupCode(pc)); | 568 } |
| 237 if (!code.IsNull()) { | 569 if (sample.timestamp == 0) { |
| 238 const Function& function = Function::Handle(code.function()); | 570 continue; |
| 239 if (!function.IsNull()) { | 571 } |
| 240 const String& name = String::Handle(function.QualifiedUserVisibleName()); | 572 samples += ProcessSample(isolate, code_region_table, &sample); |
| 241 if (!name.IsNull()) { | 573 } |
| 242 symbol_name = name.ToCString(); | 574 int64_t end = OS::GetCurrentTimeMillis(); |
| 243 return symbol_name; | 575 if (FLAG_trace_profiled_isolates) { |
| 244 } | 576 int64_t delta = end - start; |
| 245 } | 577 OS::Print("Processed %" Pd " samples from %s in %" Pd64 " milliseconds.\n", |
| 246 } else { | 578 samples, |
| 247 // Possibly a native symbol. | 579 isolate->name(), |
| 248 char* native_name = NativeSymbolResolver::LookupSymbolName(pc); | 580 delta); |
| 249 if (native_name != NULL) { | 581 } |
| 250 symbol_name = native_name; | 582 return samples; |
| 251 *symbol_name_allocated = true; | |
| 252 return symbol_name; | |
| 253 } | |
| 254 } | |
| 255 const intptr_t kBucketSize = 256; | |
| 256 const intptr_t kBucketMask = ~(kBucketSize - 1); | |
| 257 // Not a Dart symbol or a native symbol. Bin into buckets by PC. | |
| 258 pc &= kBucketMask; | |
| 259 { | |
| 260 const intptr_t kBuffSize = 256; | |
| 261 char buff[kBuffSize]; | |
| 262 OS::SNPrint(&buff[0], kBuffSize-1, "Unknown [%" Px ", %" Px ")", | |
| 263 pc, pc + kBucketSize); | |
| 264 symbol_name = strdup(buff); | |
| 265 *symbol_name_allocated = true; | |
| 266 } | |
| 267 return symbol_name; | |
| 268 } | 583 } |
| 269 | 584 |
| 270 | 585 |
| 271 void Profiler::WriteTracingSample(Isolate* isolate, intptr_t pid, | 586 intptr_t Profiler::ProcessSample(Isolate* isolate, |
| 272 Sample* sample, JSONArray& events) { | 587 ProfilerCodeRegionTable* code_region_table, |
| 588 Sample* sample) { | |
| 273 Sample::SampleType type = sample->type; | 589 Sample::SampleType type = sample->type; |
| 274 intptr_t tid = Thread::ThreadIdToIntPtr(sample->tid); | 590 if (type != Sample::kIsolateSample) { |
| 275 double timestamp = static_cast<double>(sample->timestamp); | 591 return 0; |
| 276 const char* isolate_name = isolate->name(); | 592 } |
| 277 switch (type) { | 593 if (sample->pcs[0] == 0) { |
| 278 case Sample::kIsolateStart: { | 594 // No frames in this sample. |
| 279 JSONObject begin(&events); | 595 return 0; |
| 280 begin.AddProperty("ph", "B"); | 596 } |
| 281 begin.AddProperty("tid", tid); | 597 intptr_t i = 0; |
| 282 begin.AddProperty("pid", pid); | 598 // i points to the leaf (exclusive) PC sample. |
| 283 begin.AddProperty("name", isolate_name); | 599 code_region_table->AddTick(sample->pcs[i], true); |
| 284 begin.AddProperty("ts", timestamp); | 600 for (; i < Sample::kNumStackFrames; i++) { |
| 285 } | 601 if (sample->pcs[i] == 0) { |
| 286 break; | 602 break; |
| 287 case Sample::kIsolateStop: { | 603 } |
| 288 JSONObject begin(&events); | 604 code_region_table->AddTick(sample->pcs[i], false); |
|
Ivan Posva
2014/01/03 19:24:54
Double counting the exclusive ticks as inclusive t
Cutch
2014/01/03 19:42:30
Giving all code regions an inclusive tick was int
| |
| 289 begin.AddProperty("ph", "E"); | 605 } |
| 290 begin.AddProperty("tid", tid); | 606 return 1; |
| 291 begin.AddProperty("pid", pid); | |
| 292 begin.AddProperty("name", isolate_name); | |
| 293 begin.AddProperty("ts", timestamp); | |
| 294 } | |
| 295 break; | |
| 296 case Sample::kIsolateSample: | |
| 297 // Write "B" events. | |
| 298 for (int i = Sample::kNumStackFrames - 1; i >= 0; i--) { | |
| 299 bool symbol_name_allocated = false; | |
| 300 const char* symbol_name = FindSymbolName(sample->pcs[i], | |
| 301 &symbol_name_allocated); | |
| 302 { | |
| 303 JSONObject begin(&events); | |
| 304 begin.AddProperty("ph", "B"); | |
| 305 begin.AddProperty("tid", tid); | |
| 306 begin.AddProperty("pid", pid); | |
| 307 begin.AddProperty("name", symbol_name); | |
| 308 begin.AddProperty("ts", timestamp); | |
| 309 } | |
| 310 if (symbol_name_allocated) { | |
| 311 free(const_cast<char*>(symbol_name)); | |
| 312 } | |
| 313 } | |
| 314 // Write "E" events. | |
| 315 for (int i = 0; i < Sample::kNumStackFrames; i++) { | |
| 316 bool symbol_name_allocated = false; | |
| 317 const char* symbol_name = FindSymbolName(sample->pcs[i], | |
| 318 &symbol_name_allocated); | |
| 319 { | |
| 320 JSONObject begin(&events); | |
| 321 begin.AddProperty("ph", "E"); | |
| 322 begin.AddProperty("tid", tid); | |
| 323 begin.AddProperty("pid", pid); | |
| 324 begin.AddProperty("name", symbol_name); | |
| 325 begin.AddProperty("ts", timestamp); | |
| 326 } | |
| 327 if (symbol_name_allocated) { | |
| 328 free(const_cast<char*>(symbol_name)); | |
| 329 } | |
| 330 } | |
| 331 break; | |
| 332 default: | |
| 333 UNIMPLEMENTED(); | |
| 334 } | |
| 335 } | 607 } |
| 336 | 608 |
| 337 | 609 |
| 338 void Profiler::WriteTracing(Isolate* isolate) { | 610 void Profiler::WriteProfile(Isolate* isolate) { |
| 339 if (isolate == NULL) { | 611 if (isolate == NULL) { |
| 340 return; | 612 return; |
| 341 } | 613 } |
| 342 if (!FLAG_profile) { | 614 if (!FLAG_profile) { |
| 343 return; | 615 return; |
| 344 } | 616 } |
| 345 ASSERT(initialized_); | 617 ASSERT(initialized_); |
| 346 if (FLAG_profile_dir == NULL) { | 618 if (FLAG_profile_dir == NULL) { |
| 347 return; | 619 return; |
| 348 } | 620 } |
| 349 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); | 621 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); |
| 350 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); | 622 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); |
| 351 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); | 623 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); |
| 352 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) { | 624 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) { |
| 353 // Embedder has not provided necessary callbacks. | 625 // Embedder has not provided necessary callbacks. |
| 354 return; | 626 return; |
| 355 } | 627 } |
| 356 // We will be looking up code objects within the isolate. | 628 // We will be looking up code objects within the isolate. |
| 357 ASSERT(Isolate::Current() != NULL); | 629 ASSERT(Isolate::Current() == isolate); |
| 358 // We do not want to be interrupted while processing the buffer. | |
| 359 EndExecution(isolate); | |
| 360 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); | |
| 361 IsolateProfilerData* profiler_data = isolate->profiler_data(); | |
| 362 if (profiler_data == NULL) { | |
| 363 return; | |
| 364 } | |
| 365 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | |
| 366 ASSERT(sample_buffer != NULL); | |
| 367 JSONStream stream(10 * MB); | 630 JSONStream stream(10 * MB); |
| 368 intptr_t pid = OS::ProcessId(); | 631 intptr_t pid = OS::ProcessId(); |
| 369 { | 632 PrintToJSONStream(isolate, &stream, true); |
| 370 JSONArray events(&stream); | |
| 371 { | |
| 372 JSONObject process_name(&events); | |
| 373 process_name.AddProperty("name", "process_name"); | |
| 374 process_name.AddProperty("ph", "M"); | |
| 375 process_name.AddProperty("pid", pid); | |
| 376 { | |
| 377 JSONObject args(&process_name, "args"); | |
| 378 args.AddProperty("name", "Dart VM"); | |
| 379 } | |
| 380 } | |
| 381 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) { | |
| 382 Sample* sample = sample_buffer->GetSample(i); | |
| 383 if (sample->isolate != isolate) { | |
| 384 continue; | |
| 385 } | |
| 386 if (sample->timestamp == 0) { | |
| 387 continue; | |
| 388 } | |
| 389 WriteTracingSample(isolate, pid, sample, events); | |
| 390 } | |
| 391 } | |
| 392 const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json"; | 633 const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json"; |
| 393 intptr_t len = OS::SNPrint(NULL, 0, format, | 634 intptr_t len = OS::SNPrint(NULL, 0, format, |
| 394 FLAG_profile_dir, pid, isolate->main_port()); | 635 FLAG_profile_dir, pid, isolate->main_port()); |
| 395 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 636 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
| 396 OS::SNPrint(filename, len + 1, format, | 637 OS::SNPrint(filename, len + 1, format, |
| 397 FLAG_profile_dir, pid, isolate->main_port()); | 638 FLAG_profile_dir, pid, isolate->main_port()); |
| 398 void* f = file_open(filename, true); | 639 void* f = file_open(filename, true); |
| 399 if (f == NULL) { | 640 if (f == NULL) { |
| 400 // Cannot write. | 641 // Cannot write. |
| 401 return; | 642 return; |
| 402 } | 643 } |
| 403 TextBuffer* buffer = stream.buffer(); | 644 TextBuffer* buffer = stream.buffer(); |
| 404 ASSERT(buffer != NULL); | 645 ASSERT(buffer != NULL); |
| 405 file_write(buffer->buf(), buffer->length(), f); | 646 file_write(buffer->buf(), buffer->length(), f); |
| 406 file_close(f); | 647 file_close(f); |
| 407 BeginExecution(isolate); | |
| 408 } | 648 } |
| 409 | 649 |
| 410 | 650 |
| 411 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer, | 651 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer, |
| 412 bool own_sample_buffer) { | 652 bool own_sample_buffer) { |
| 413 sample_buffer_ = sample_buffer; | 653 sample_buffer_ = sample_buffer; |
| 414 own_sample_buffer_ = own_sample_buffer; | 654 own_sample_buffer_ = own_sample_buffer; |
| 415 } | 655 } |
| 416 | 656 |
| 417 | 657 |
| 418 IsolateProfilerData::~IsolateProfilerData() { | 658 IsolateProfilerData::~IsolateProfilerData() { |
| 419 if (own_sample_buffer_) { | 659 if (own_sample_buffer_) { |
| 420 delete sample_buffer_; | 660 delete sample_buffer_; |
| 421 sample_buffer_ = NULL; | 661 sample_buffer_ = NULL; |
| 422 own_sample_buffer_ = false; | 662 own_sample_buffer_ = false; |
| 423 } | 663 } |
| 424 } | 664 } |
| 425 | 665 |
| 426 | 666 |
| 427 const char* Sample::kLookupSymbol = "Symbol Not Looked Up"; | |
| 428 const char* Sample::kNoSymbol = "No Symbol Found"; | |
| 429 const char* Sample::kNoFrame = "<no frame>"; | |
| 430 | |
| 431 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp, | 667 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp, |
| 432 ThreadId tid) { | 668 ThreadId tid) { |
| 433 this->timestamp = timestamp; | 669 this->timestamp = timestamp; |
| 434 this->tid = tid; | 670 this->tid = tid; |
| 435 this->isolate = isolate; | 671 this->isolate = isolate; |
| 436 for (intptr_t i = 0; i < kNumStackFrames; i++) { | 672 for (intptr_t i = 0; i < kNumStackFrames; i++) { |
| 437 pcs[i] = 0; | 673 pcs[i] = 0; |
| 438 } | 674 } |
| 439 this->type = type; | 675 this->type = type; |
| 440 vm_tags = 0; | 676 vm_tags = 0; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 550 return false; | 786 return false; |
| 551 } | 787 } |
| 552 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); | 788 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); |
| 553 cursor += sizeof(fp); | 789 cursor += sizeof(fp); |
| 554 bool r = cursor >= lower_bound_ && cursor < stack_upper_; | 790 bool r = cursor >= lower_bound_ && cursor < stack_upper_; |
| 555 return r; | 791 return r; |
| 556 } | 792 } |
| 557 | 793 |
| 558 | 794 |
| 559 } // namespace dart | 795 } // namespace dart |
| OLD | NEW |