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