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() { |
| 247 } |
| 248 |
| 249 uintptr_t start() const { return start_; } |
| 250 void set_start(uintptr_t start) { |
| 251 start_ = start; |
| 252 } |
| 253 |
| 254 uintptr_t end() const { return end_; } |
| 255 void set_end(uintptr_t end) { |
| 256 end_ = end; |
| 257 } |
| 258 |
| 259 void AdjustExtent(uintptr_t start, uintptr_t end) { |
| 260 if (start < start_) { |
| 261 start_ = start; |
| 262 } |
| 263 if (end > end_) { |
| 264 end_ = end; |
| 265 } |
| 266 } |
| 267 |
| 268 bool contains(uintptr_t pc) const { |
| 269 return (pc >= start_) && (pc < end_); |
| 270 } |
| 271 |
| 272 intptr_t inclusive_ticks() const { return inclusive_ticks_; } |
| 273 void set_inclusive_ticks(intptr_t inclusive_ticks) { |
| 274 inclusive_ticks_ = inclusive_ticks; |
| 275 } |
| 276 |
| 277 intptr_t exclusive_ticks() const { return exclusive_ticks_; } |
| 278 void set_exclusive_ticks(intptr_t exclusive_ticks) { |
| 279 exclusive_ticks_ = exclusive_ticks; |
| 280 } |
| 281 |
| 282 const char* name() const { return name_; } |
| 283 void SetName(const char* name) { |
| 284 if (name == NULL) { |
| 285 name_ = NULL; |
| 286 } |
| 287 intptr_t len = strlen(name); |
| 288 name_ = Isolate::Current()->current_zone()->Alloc<const char>(len + 1); |
| 289 strncpy(const_cast<char*>(name_), name, len); |
| 290 const_cast<char*>(name_)[len] = '\0'; |
| 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 GenerateAndSetSymbolName("Stub"); |
| 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 GenerateAndSetSymbolName("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 GenerateAndSetSymbolName("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 void GenerateAndSetSymbolName(const char* prefix) { |
| 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 SetName(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 } |
| 422 |
| 423 void AddTick(uintptr_t pc, bool exclusive, bool tick_address) { |
| 424 intptr_t index = FindIndex(pc); |
| 425 if (index < 0) { |
| 426 CodeRegion* code_region = CreateCodeRegion(pc); |
| 427 ASSERT(code_region != NULL); |
| 428 index = InsertCodeRegion(code_region); |
| 429 } |
| 430 ASSERT(index >= 0); |
| 431 ASSERT(index < code_region_table_->length()); |
| 432 (*code_region_table_)[index]->AddTick(exclusive); |
| 433 if (tick_address) { |
| 434 (*code_region_table_)[index]->AddTickAtAddress(pc); |
| 435 } |
| 436 } |
| 437 |
| 438 intptr_t Length() const { return code_region_table_->length(); } |
| 439 |
| 440 CodeRegion* At(intptr_t idx) { |
| 441 return (*code_region_table_)[idx]; |
| 442 } |
| 443 |
| 444 private: |
| 445 intptr_t FindIndex(uintptr_t pc) { |
| 446 const intptr_t length = code_region_table_->length(); |
| 447 for (intptr_t i = 0; i < length; i++) { |
| 448 const CodeRegion* code_region = (*code_region_table_)[i]; |
| 449 if (code_region->contains(pc)) { |
| 450 return i; |
| 451 } |
| 452 } |
| 453 return -1; |
| 454 } |
| 455 |
| 456 CodeRegion* CreateCodeRegion(uintptr_t pc) { |
| 457 Code& code = Code::Handle(Code::LookupCode(pc)); |
| 458 if (!code.IsNull()) { |
| 459 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(), |
| 460 code.EntryPoint() + code.Size()); |
| 461 } |
| 462 if (heap_->CodeContains(pc)) { |
| 463 const intptr_t kDartCodeAlignment = 0x10; |
| 464 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); |
| 465 return new CodeRegion(CodeRegion::kCollectedCode, |
| 466 (pc & kDartCodeAlignmentMask), |
| 467 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment); |
| 468 } |
| 469 uintptr_t native_start = 0; |
| 470 char* native_name = NativeSymbolResolver::LookupSymbolName(pc, |
| 471 &native_start); |
| 472 if (native_name == NULL) { |
| 473 return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1); |
| 474 } |
| 475 ASSERT(pc >= native_start); |
| 476 CodeRegion* code_region = |
| 477 new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1); |
| 478 code_region->SetName(native_name); |
| 479 free(native_name); |
| 480 return code_region; |
| 481 } |
| 482 |
| 483 intptr_t InsertCodeRegion(CodeRegion* code_region) { |
| 484 const intptr_t length = code_region_table_->length(); |
| 485 const uintptr_t start = code_region->start(); |
| 486 const uintptr_t end = code_region->end(); |
| 487 intptr_t i = 0; |
| 488 for (; i < length; i++) { |
| 489 CodeRegion* region = (*code_region_table_)[i]; |
| 490 if (region->contains(start) || region->contains(end - 1)) { |
| 491 // We should only see overlapping native code regions. |
| 492 ASSERT(region->kind() == CodeRegion::kNativeCode); |
| 493 // When code regions overlap, they should be of the same kind. |
| 494 ASSERT(region->kind() == code_region->kind()); |
| 495 // Overlapping code region. |
| 496 region->AdjustExtent(start, end); |
| 497 return i; |
| 498 } else if (start >= region->end()) { |
| 499 // Insert here. |
| 500 break; |
| 501 } |
| 502 } |
| 503 if (i != length) { |
| 504 code_region_table_->InsertAt(i, code_region); |
| 505 return i; |
| 506 } |
| 507 code_region_table_->Add(code_region); |
| 508 return code_region_table_->length() - 1; |
| 509 } |
| 510 |
| 511 Heap* heap_; |
| 512 ZoneGrowableArray<CodeRegion*>* code_region_table_; |
| 513 }; |
| 514 |
| 515 |
| 516 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, |
| 517 bool full) { |
222 ASSERT(isolate == Isolate::Current()); | 518 ASSERT(isolate == Isolate::Current()); |
223 UNIMPLEMENTED(); | 519 // Disable profile interrupts while processing the buffer. |
| 520 EndExecution(isolate); |
| 521 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); |
| 522 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 523 if (profiler_data == NULL) { |
| 524 JSONObject error(stream); |
| 525 error.AddProperty("type", "Error"); |
| 526 error.AddProperty("text", "Isolate does not have profiling enabled."); |
| 527 return; |
| 528 } |
| 529 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| 530 ASSERT(sample_buffer != NULL); |
| 531 { |
| 532 StackZone zone(isolate); |
| 533 { |
| 534 // Build code region table. |
| 535 ProfilerCodeRegionTable code_region_table(isolate); |
| 536 intptr_t samples = |
| 537 ProcessSamples(isolate, &code_region_table, sample_buffer); |
| 538 { |
| 539 // Serialize to JSON. |
| 540 JSONObject obj(stream); |
| 541 obj.AddProperty("type", "Profile"); |
| 542 obj.AddProperty("samples", samples); |
| 543 JSONArray codes(&obj, "codes"); |
| 544 for (intptr_t i = 0; i < code_region_table.Length(); i++) { |
| 545 CodeRegion* region = code_region_table.At(i); |
| 546 ASSERT(region != NULL); |
| 547 region->PrintToJSONArray(&codes, full); |
| 548 } |
| 549 } |
| 550 } |
| 551 } |
| 552 // Enable profile interrupts. |
| 553 BeginExecution(isolate); |
224 } | 554 } |
225 | 555 |
226 | 556 |
227 static const char* FindSymbolName(uintptr_t pc, bool* symbol_name_allocated) { | 557 intptr_t Profiler::ProcessSamples(Isolate* isolate, |
228 // TODO(johnmccutchan): Differentiate between symbols which can't be found | 558 ProfilerCodeRegionTable* code_region_table, |
229 // and symbols which were GCed. (Heap::CodeContains). | 559 SampleBuffer* sample_buffer) { |
230 ASSERT(symbol_name_allocated != NULL); | 560 int64_t start = OS::GetCurrentTimeMillis(); |
231 const char* symbol_name = "Unknown"; | 561 intptr_t samples = 0; |
232 *symbol_name_allocated = false; | 562 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) { |
233 if (pc == 0) { | 563 Sample sample = sample_buffer->GetSample(i); |
234 return const_cast<char*>(Sample::kNoFrame); | 564 if (sample.isolate != isolate) { |
235 } | 565 continue; |
236 const Code& code = Code::Handle(Code::LookupCode(pc)); | 566 } |
237 if (!code.IsNull()) { | 567 if (sample.timestamp == 0) { |
238 const Function& function = Function::Handle(code.function()); | 568 continue; |
239 if (!function.IsNull()) { | 569 } |
240 const String& name = String::Handle(function.QualifiedUserVisibleName()); | 570 samples += ProcessSample(isolate, code_region_table, &sample); |
241 if (!name.IsNull()) { | 571 } |
242 symbol_name = name.ToCString(); | 572 int64_t end = OS::GetCurrentTimeMillis(); |
243 return symbol_name; | 573 if (FLAG_trace_profiled_isolates) { |
244 } | 574 int64_t delta = end - start; |
245 } | 575 OS::Print("Processed %" Pd " samples from %s in %" Pd64 " milliseconds.\n", |
246 } else { | 576 samples, |
247 // Possibly a native symbol. | 577 isolate->name(), |
248 char* native_name = NativeSymbolResolver::LookupSymbolName(pc); | 578 delta); |
249 if (native_name != NULL) { | 579 } |
250 symbol_name = native_name; | 580 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 } | 581 } |
269 | 582 |
270 | 583 |
271 void Profiler::WriteTracingSample(Isolate* isolate, intptr_t pid, | 584 intptr_t Profiler::ProcessSample(Isolate* isolate, |
272 Sample* sample, JSONArray& events) { | 585 ProfilerCodeRegionTable* code_region_table, |
| 586 Sample* sample) { |
273 Sample::SampleType type = sample->type; | 587 Sample::SampleType type = sample->type; |
274 intptr_t tid = Thread::ThreadIdToIntPtr(sample->tid); | 588 if (type != Sample::kIsolateSample) { |
275 double timestamp = static_cast<double>(sample->timestamp); | 589 return 0; |
276 const char* isolate_name = isolate->name(); | 590 } |
277 switch (type) { | 591 if (sample->pcs[0] == 0) { |
278 case Sample::kIsolateStart: { | 592 // No frames in this sample. |
279 JSONObject begin(&events); | 593 return 0; |
280 begin.AddProperty("ph", "B"); | 594 } |
281 begin.AddProperty("tid", tid); | 595 intptr_t i = 0; |
282 begin.AddProperty("pid", pid); | 596 // i points to the leaf (exclusive) PC sample. Do not tick the address. |
283 begin.AddProperty("name", isolate_name); | 597 code_region_table->AddTick(sample->pcs[i], true, false); |
284 begin.AddProperty("ts", timestamp); | 598 // Give all frames an inclusive tick and tick the address. |
285 } | 599 for (; i < Sample::kNumStackFrames; i++) { |
286 break; | 600 if (sample->pcs[i] == 0) { |
287 case Sample::kIsolateStop: { | 601 break; |
288 JSONObject begin(&events); | 602 } |
289 begin.AddProperty("ph", "E"); | 603 code_region_table->AddTick(sample->pcs[i], false, true); |
290 begin.AddProperty("tid", tid); | 604 } |
291 begin.AddProperty("pid", pid); | 605 return 1; |
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 } | 606 } |
336 | 607 |
337 | 608 |
338 void Profiler::WriteTracing(Isolate* isolate) { | 609 void Profiler::WriteProfile(Isolate* isolate) { |
339 if (isolate == NULL) { | 610 if (isolate == NULL) { |
340 return; | 611 return; |
341 } | 612 } |
342 if (!FLAG_profile) { | 613 if (!FLAG_profile) { |
343 return; | 614 return; |
344 } | 615 } |
345 ASSERT(initialized_); | 616 ASSERT(initialized_); |
346 if (FLAG_profile_dir == NULL) { | 617 if (FLAG_profile_dir == NULL) { |
347 return; | 618 return; |
348 } | 619 } |
349 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); | 620 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); |
350 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); | 621 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); |
351 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); | 622 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); |
352 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) { | 623 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) { |
353 // Embedder has not provided necessary callbacks. | 624 // Embedder has not provided necessary callbacks. |
354 return; | 625 return; |
355 } | 626 } |
356 // We will be looking up code objects within the isolate. | 627 // We will be looking up code objects within the isolate. |
357 ASSERT(Isolate::Current() != NULL); | 628 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); | 629 JSONStream stream(10 * MB); |
368 intptr_t pid = OS::ProcessId(); | 630 intptr_t pid = OS::ProcessId(); |
369 { | 631 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"; | 632 const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json"; |
393 intptr_t len = OS::SNPrint(NULL, 0, format, | 633 intptr_t len = OS::SNPrint(NULL, 0, format, |
394 FLAG_profile_dir, pid, isolate->main_port()); | 634 FLAG_profile_dir, pid, isolate->main_port()); |
395 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); | 635 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); |
396 OS::SNPrint(filename, len + 1, format, | 636 OS::SNPrint(filename, len + 1, format, |
397 FLAG_profile_dir, pid, isolate->main_port()); | 637 FLAG_profile_dir, pid, isolate->main_port()); |
398 void* f = file_open(filename, true); | 638 void* f = file_open(filename, true); |
399 if (f == NULL) { | 639 if (f == NULL) { |
400 // Cannot write. | 640 // Cannot write. |
401 return; | 641 return; |
402 } | 642 } |
403 TextBuffer* buffer = stream.buffer(); | 643 TextBuffer* buffer = stream.buffer(); |
404 ASSERT(buffer != NULL); | 644 ASSERT(buffer != NULL); |
405 file_write(buffer->buf(), buffer->length(), f); | 645 file_write(buffer->buf(), buffer->length(), f); |
406 file_close(f); | 646 file_close(f); |
407 BeginExecution(isolate); | |
408 } | 647 } |
409 | 648 |
410 | 649 |
411 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer, | 650 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer, |
412 bool own_sample_buffer) { | 651 bool own_sample_buffer) { |
413 sample_buffer_ = sample_buffer; | 652 sample_buffer_ = sample_buffer; |
414 own_sample_buffer_ = own_sample_buffer; | 653 own_sample_buffer_ = own_sample_buffer; |
415 } | 654 } |
416 | 655 |
417 | 656 |
418 IsolateProfilerData::~IsolateProfilerData() { | 657 IsolateProfilerData::~IsolateProfilerData() { |
419 if (own_sample_buffer_) { | 658 if (own_sample_buffer_) { |
420 delete sample_buffer_; | 659 delete sample_buffer_; |
421 sample_buffer_ = NULL; | 660 sample_buffer_ = NULL; |
422 own_sample_buffer_ = false; | 661 own_sample_buffer_ = false; |
423 } | 662 } |
424 } | 663 } |
425 | 664 |
426 | 665 |
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, | 666 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp, |
432 ThreadId tid) { | 667 ThreadId tid) { |
433 this->timestamp = timestamp; | 668 this->timestamp = timestamp; |
434 this->tid = tid; | 669 this->tid = tid; |
435 this->isolate = isolate; | 670 this->isolate = isolate; |
436 for (intptr_t i = 0; i < kNumStackFrames; i++) { | 671 for (intptr_t i = 0; i < kNumStackFrames; i++) { |
437 pcs[i] = 0; | 672 pcs[i] = 0; |
438 } | 673 } |
439 this->type = type; | 674 this->type = type; |
440 vm_tags = 0; | 675 vm_tags = 0; |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
550 return false; | 785 return false; |
551 } | 786 } |
552 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); | 787 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); |
553 cursor += sizeof(fp); | 788 cursor += sizeof(fp); |
554 bool r = cursor >= lower_bound_ && cursor < stack_upper_; | 789 bool r = cursor >= lower_bound_ && cursor < stack_upper_; |
555 return r; | 790 return r; |
556 } | 791 } |
557 | 792 |
558 | 793 |
559 } // namespace dart | 794 } // namespace dart |
OLD | NEW |