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 |