Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(52)

Side by Side Diff: runtime/vm/profiler.cc

Issue 100103011: Changes to support dprof and Observatory profiler UIs (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
223 class SymbolLookupCache {
224 public:
225 explicit SymbolLookupCache(const intptr_t cache_size = 32) {
226 cache_index_ = 0;
227 cache_size_ = cache_size;
228 pcs_ = reinterpret_cast<uintptr_t*>(
229 calloc(cache_size, sizeof(uintptr_t))); // NOLINT
230 names_ = reinterpret_cast<const char**>(
231 calloc(cache_size, sizeof(const char*))); // NOLINT
232 }
233
234 virtual ~SymbolLookupCache() {
235 for (intptr_t i = 0; i < cache_size_; i++) {
236 ClearCacheIndex(i);
237 }
238 free(pcs_);
239 free(names_);
240 }
241
242 const char* Lookup(uintptr_t pc) {
243 const char* symbol = LookupInCache(pc);
244 if (symbol != NULL) {
245 return symbol;
246 }
247 symbol = QuerySource(pc);
248 if (symbol != NULL) {
249 InsertIntoCache(pc, symbol);
250 }
251 return symbol;
252 }
253
254 virtual const char* QuerySource(uintptr_t pc) const = 0;
255
256 protected:
257 const char* GenerateSymbolName(const char* prefix, uintptr_t pc) const {
258 // Generate a name by binning into buckets by PC.
259 const intptr_t kBucketSize = 256;
260 const intptr_t kBucketMask = ~(kBucketSize - 1);
261 pc &= kBucketMask;
262 const intptr_t kBuffSize = 256;
263 char buff[kBuffSize];
264 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")",
265 prefix, pc, pc + kBucketSize);
266 return strdup(buff);
267 }
268
269 private:
270 const char* LookupInCache(uintptr_t pc) {
271 for (intptr_t i = 0; i < cache_size_; i++) {
272 if (pcs_[i] == pc) {
273 ASSERT(names_[i] != NULL);
274 return names_[i];
275 }
276 }
277 return NULL;
278 }
279
280 intptr_t GetCacheIndex(uintptr_t pc) {
281 cache_index_ = (cache_index_ + 1) % cache_size_;
282 return cache_index_;
283 }
284
285 void InsertIntoCache(uintptr_t pc, const char* name) {
286 intptr_t index = GetCacheIndex(pc);
287 ClearCacheIndex(index);
288 pcs_[index] = pc;
289 names_[index] = name;
290 }
291
292 void ClearCacheIndex(intptr_t index) {
293 free(const_cast<char*>(names_[index]));
294 names_[index] = NULL;
295 pcs_[index] = 0;
296 }
297
298 intptr_t cache_index_;
299 intptr_t cache_size_;
300 uintptr_t* pcs_;
301 const char** names_;
302 };
303
304
305 class NativeSymbolLookup : public SymbolLookupCache {
306 public:
307 NativeSymbolLookup() : SymbolLookupCache(32) {
308 }
309
310 const char* QuerySource(uintptr_t pc) const {
311 char* native_name = NativeSymbolResolver::LookupSymbolName(pc);
312 if (native_name == NULL) {
313 return GenerateSymbolName("Unknown", pc);
314 }
315 return native_name;
316 }
317 };
318
319
320 class DartSymbolLookup : public SymbolLookupCache {
321 public:
322 explicit DartSymbolLookup(Isolate* isolate) : SymbolLookupCache(32),
323 isolate_(isolate),
324 heap_(isolate_->heap()) {
325 }
326
327 bool InDartCodeSpace(uintptr_t pc) {
328 ASSERT(heap_ != NULL);
329 return heap_->CodeContains(pc);
330 }
331
332 const char* QuerySource(uintptr_t pc) const {
333 const Code& code = Code::Handle(isolate_, Code::LookupCode(pc));
334 if (!code.IsNull()) {
335 const Function& function = Function::Handle(isolate_, code.function());
336 if (!function.IsNull()) {
337 const String& name =
338 String::Handle(isolate_, function.QualifiedUserVisibleName());
339 if (!name.IsNull()) {
340 return strdup(name.ToCString());
341 }
342 } else {
343 return GenerateSymbolName("Detached", pc);
344 }
345 }
346 return GenerateSymbolName("Collected", pc);
347 }
348
349 private:
350 Isolate* isolate_;
351 Heap* heap_;
352 };
353
354
355 class DartCodeTable {
356 public:
357 explicit DartCodeTable(Isolate* isolate) :
358 heap_(isolate->heap()),
359 code_table_(GrowableObjectArray::Handle(isolate)) {
360 code_table_ ^= GrowableObjectArray::New();
361 ASSERT(!code_table_.IsNull());
362 }
363
364 ~DartCodeTable() {
365 }
366
367 bool Contains(const Code& code) {
368 intptr_t length = code_table_.Length();
369 Code& table_code = Code::Handle();
370 for (intptr_t i = 0; i < length; i++) {
371 table_code ^= code_table_.At(i);
372 if (table_code.IsNull()) {
373 return false;
374 }
375 ASSERT(!table_code.IsNull());
376 if (table_code.raw() == code.raw()) {
377 return true;
378 }
379 }
380 return false;
381 }
382
383 void Add(const Code& code) {
384 ASSERT(!Contains(code));
385 code_table_.Add(code);
386 }
387
388 private:
389 Heap* heap_;
390 GrowableObjectArray& code_table_;
391 };
392
393
394 class ProfilerSymbolHelper {
395 public:
396 explicit ProfilerSymbolHelper(Isolate* isolate) :
397 dart_symbol_(isolate),
398 code_table_(isolate) {
399 }
400
401 ~ProfilerSymbolHelper() {
402 }
403
404
405 const char* GetSymbol(uintptr_t pc) {
406 if (pc == 0) {
407 return "<no frame>";
408 }
409 if (dart_symbol_.InDartCodeSpace(pc)) {
Ivan Posva 2013/12/30 23:06:09 Restructuring this as discussed will avoid iterati
410 return dart_symbol_.Lookup(pc);
411 } else {
412 return native_symbol_.Lookup(pc);
413 }
414 }
415
416
417 RawCode* GetNewCode(uintptr_t pc) {
418 Code& new_code = Code::Handle();
419 new_code ^= Code::LookupCode(pc);
Ivan Posva 2013/12/30 23:06:09 Here you are walking through the heap again. Looki
420 if (!new_code.IsNull()) {
421 Function& function = Function::Handle(new_code.function());
422 if (function.IsNull()) {
423 // If code no longer has a function, ignore it.
424 new_code ^= Code::null();
425 } else if (code_table_.Contains(new_code)) {
426 // If code has been serialized, ignore it.
427 new_code ^= Code::null();
428 } else {
429 // Add code to code table.
430 code_table_.Add(new_code);
431 }
432 }
433 return new_code.raw();
434 }
435
436 private:
437 DartSymbolLookup dart_symbol_;
438 DartCodeTable code_table_;
439 NativeSymbolLookup native_symbol_;
440 };
441
442
221 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream) { 443 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream) {
222 ASSERT(isolate == Isolate::Current()); 444 ASSERT(isolate == Isolate::Current());
223 UNIMPLEMENTED(); 445 // Disable profile interrupts while processing the buffer.
446 EndExecution(isolate);
447 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
448 IsolateProfilerData* profiler_data = isolate->profiler_data();
449 if (profiler_data == NULL) {
450 return;
451 }
452 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
453 ASSERT(sample_buffer != NULL);
454 ProfilerSymbolHelper symbol_helper(isolate);
455 {
456 JSONArray events(stream);
457 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) {
458 Sample sample = sample_buffer->GetSample(i);
459 if (sample.isolate != isolate) {
460 continue;
461 }
462 if (sample.timestamp == 0) {
463 continue;
464 }
465 WriteSample(isolate, &symbol_helper, &sample, events);
466 }
467 }
468 // Enable profile interrupts.
469 BeginExecution(isolate);
224 } 470 }
225 471
226 472
227 static const char* FindSymbolName(uintptr_t pc, bool* symbol_name_allocated) { 473 void Profiler::WriteSample(Isolate* isolate,
228 // TODO(johnmccutchan): Differentiate between symbols which can't be found 474 ProfilerSymbolHelper* symbol_helper,
229 // and symbols which were GCed. (Heap::CodeContains). 475 Sample* sample, JSONArray& events) {
230 ASSERT(symbol_name_allocated != NULL); 476 StackZone zone(isolate);
231 const char* symbol_name = "Unknown"; 477 Code& new_code = Code::Handle(isolate);
232 *symbol_name_allocated = false; 478 Sample::SampleType type = sample->type;
233 if (pc == 0) { 479 if (type != Sample::kIsolateSample) {
234 return const_cast<char*>(Sample::kNoFrame); 480 return;
235 } 481 }
236 const Code& code = Code::Handle(Code::LookupCode(pc)); 482 double timestamp = static_cast<double>(sample->timestamp);
237 if (!code.IsNull()) { 483 bool any = false;
238 const Function& function = Function::Handle(code.function()); 484 for (int i = Sample::kNumStackFrames - 1; i >= 0; i--) {
239 if (!function.IsNull()) { 485 if (sample->pcs[i] == 0) {
240 const String& name = String::Handle(function.QualifiedUserVisibleName()); 486 continue;
241 if (!name.IsNull()) { 487 }
242 symbol_name = name.ToCString(); 488 any = true;
243 return symbol_name; 489 }
244 } 490 if (!any) {
245 } 491 // No frames in this sample.
246 } else { 492 return;
247 // Possibly a native symbol. 493 }
248 char* native_name = NativeSymbolResolver::LookupSymbolName(pc);
249 if (native_name != NULL) {
250 symbol_name = native_name;
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 { 494 {
260 const intptr_t kBuffSize = 256; 495 JSONObject sample_event(&events);
261 char buff[kBuffSize]; 496 sample_event.AddProperty("ts", timestamp);
262 OS::SNPrint(&buff[0], kBuffSize-1, "Unknown [%" Px ", %" Px ")", 497 {
263 pc, pc + kBucketSize); 498 JSONArray frames(&sample_event, "f");
264 symbol_name = strdup(buff); 499 for (int i = Sample::kNumStackFrames - 1; i >= 0; i--) {
265 *symbol_name_allocated = true; 500 if (sample->pcs[i] == 0) {
266 } 501 continue;
267 return symbol_name; 502 }
503 const char* symbol_name = symbol_helper->GetSymbol(sample->pcs[i]);
504 new_code ^= symbol_helper->GetNewCode(sample->pcs[i]);
505 if (!new_code.IsNull()) {
506 // Dump code.
507 frames.AddValue(new_code, false);
508 }
509 {
510 JSONObject tick(&frames);
511 tick.AddProperty("s", symbol_name);
512 tick.AddPropertyF("pc", "%" Px "", sample->pcs[i]);
513 }
514 }
515 }
516 }
268 } 517 }
269 518
270 519
271 void Profiler::WriteTracingSample(Isolate* isolate, intptr_t pid, 520 void Profiler::WriteSamples(Isolate* isolate) {
272 Sample* sample, JSONArray& events) {
273 Sample::SampleType type = sample->type;
274 intptr_t tid = Thread::ThreadIdToIntPtr(sample->tid);
275 double timestamp = static_cast<double>(sample->timestamp);
276 const char* isolate_name = isolate->name();
277 switch (type) {
278 case Sample::kIsolateStart: {
279 JSONObject begin(&events);
280 begin.AddProperty("ph", "B");
281 begin.AddProperty("tid", tid);
282 begin.AddProperty("pid", pid);
283 begin.AddProperty("name", isolate_name);
284 begin.AddProperty("ts", timestamp);
285 }
286 break;
287 case Sample::kIsolateStop: {
288 JSONObject begin(&events);
289 begin.AddProperty("ph", "E");
290 begin.AddProperty("tid", tid);
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 }
336
337
338 void Profiler::WriteTracing(Isolate* isolate) {
339 if (isolate == NULL) { 521 if (isolate == NULL) {
340 return; 522 return;
341 } 523 }
342 if (!FLAG_profile) { 524 if (!FLAG_profile) {
343 return; 525 return;
344 } 526 }
345 ASSERT(initialized_); 527 ASSERT(initialized_);
346 if (FLAG_profile_dir == NULL) { 528 if (FLAG_profile_dir == NULL) {
347 return; 529 return;
348 } 530 }
349 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); 531 Dart_FileOpenCallback file_open = Isolate::file_open_callback();
350 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); 532 Dart_FileCloseCallback file_close = Isolate::file_close_callback();
351 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); 533 Dart_FileWriteCallback file_write = Isolate::file_write_callback();
352 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) { 534 if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) {
353 // Embedder has not provided necessary callbacks. 535 // Embedder has not provided necessary callbacks.
354 return; 536 return;
355 } 537 }
356 // We will be looking up code objects within the isolate. 538 // We will be looking up code objects within the isolate.
357 ASSERT(Isolate::Current() != NULL); 539 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); 540 JSONStream stream(10 * MB);
368 intptr_t pid = OS::ProcessId(); 541 intptr_t pid = OS::ProcessId();
369 { 542 PrintToJSONStream(isolate, &stream);
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"; 543 const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json";
393 intptr_t len = OS::SNPrint(NULL, 0, format, 544 intptr_t len = OS::SNPrint(NULL, 0, format,
394 FLAG_profile_dir, pid, isolate->main_port()); 545 FLAG_profile_dir, pid, isolate->main_port());
395 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1); 546 char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
396 OS::SNPrint(filename, len + 1, format, 547 OS::SNPrint(filename, len + 1, format,
397 FLAG_profile_dir, pid, isolate->main_port()); 548 FLAG_profile_dir, pid, isolate->main_port());
398 void* f = file_open(filename, true); 549 void* f = file_open(filename, true);
399 if (f == NULL) { 550 if (f == NULL) {
400 // Cannot write. 551 // Cannot write.
401 return; 552 return;
402 } 553 }
403 TextBuffer* buffer = stream.buffer(); 554 TextBuffer* buffer = stream.buffer();
404 ASSERT(buffer != NULL); 555 ASSERT(buffer != NULL);
405 file_write(buffer->buf(), buffer->length(), f); 556 file_write(buffer->buf(), buffer->length(), f);
406 file_close(f); 557 file_close(f);
407 BeginExecution(isolate);
408 } 558 }
409 559
410 560
411 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer, 561 IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer,
412 bool own_sample_buffer) { 562 bool own_sample_buffer) {
413 sample_buffer_ = sample_buffer; 563 sample_buffer_ = sample_buffer;
414 own_sample_buffer_ = own_sample_buffer; 564 own_sample_buffer_ = own_sample_buffer;
415 } 565 }
416 566
417 567
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
550 return false; 700 return false;
551 } 701 }
552 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); 702 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp);
553 cursor += sizeof(fp); 703 cursor += sizeof(fp);
554 bool r = cursor >= lower_bound_ && cursor < stack_upper_; 704 bool r = cursor >= lower_bound_ && cursor < stack_upper_;
555 return r; 705 return r;
556 } 706 }
557 707
558 708
559 } // namespace dart 709 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698