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

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

Issue 197803004: Add dead CodeRegionTable for tracking overwritten Dart code (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 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
« no previous file with comments | « runtime/bin/vmservice/client/lib/src/service/object.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "platform/utils.h" 5 #include "platform/utils.h"
6 6
7 #include "vm/allocation.h" 7 #include "vm/allocation.h"
8 #include "vm/atomic.h" 8 #include "vm/atomic.h"
9 #include "vm/code_patcher.h" 9 #include "vm/code_patcher.h"
10 #include "vm/isolate.h" 10 #include "vm/isolate.h"
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 return; 155 return;
156 } 156 }
157 if (!FLAG_profile) { 157 if (!FLAG_profile) {
158 return; 158 return;
159 } 159 }
160 ASSERT(initialized_); 160 ASSERT(initialized_);
161 ThreadInterrupter::Unregister(); 161 ThreadInterrupter::Unregister();
162 } 162 }
163 163
164 164
165 class ScopeStopwatch : public ValueObject {
166 public:
167 explicit ScopeStopwatch(const char* name) : name_(name) {
168 start_ = OS::GetCurrentTimeMillis();
siva 2014/03/13 17:12:38 This also should be done conditionally under the f
Cutch 2014/03/13 17:33:57 Done.
169 }
170
171 intptr_t GetElapsed() const {
172 intptr_t end = OS::GetCurrentTimeMillis();
173 ASSERT(end >= start_);
174 return end - start_;
175 }
176
177 ~ScopeStopwatch() {
178 if (FLAG_trace_profiled_isolates) {
179 intptr_t elapsed = GetElapsed();
180 OS::Print("%s took %" Pd " millis.\n", name_, elapsed);
181 }
182 }
183
184 private:
185 const char* name_;
186 intptr_t start_;
187 };
188
189
165 struct AddressEntry { 190 struct AddressEntry {
166 uword pc; 191 uword pc;
167 intptr_t exclusive_ticks; 192 intptr_t exclusive_ticks;
168 intptr_t inclusive_ticks; 193 intptr_t inclusive_ticks;
169 194
170 void tick(bool exclusive) { 195 void tick(bool exclusive) {
171 if (exclusive) { 196 if (exclusive) {
172 exclusive_ticks++; 197 exclusive_ticks++;
173 } else { 198 } else {
174 inclusive_ticks++; 199 inclusive_ticks++;
175 } 200 }
176 } 201 }
177 }; 202 };
178 203
179 struct CallEntry { 204 struct CallEntry {
180 intptr_t code_table_index; 205 intptr_t code_table_index;
181 intptr_t count; 206 intptr_t count;
182 }; 207 };
183 208
184 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end); 209 typedef bool (*RegionCompare)(uword pc, uword region_start, uword region_end);
185 210
186 // A region of code. Each region is a kind of code (Dart, Collected, or Native). 211 // A contiguous address region that holds code. Each CodeRegion has a "kind"
212 // which describes the type of code contained inside the region. Each
213 // region covers the following interval: [start, end).
187 class CodeRegion : public ZoneAllocated { 214 class CodeRegion : public ZoneAllocated {
188 public: 215 public:
189 enum Kind { 216 enum Kind {
190 kDartCode, 217 kDartCode, // Live Dart code.
191 kCollectedCode, 218 kCollectedCode, // Dead Dart code.
192 kNativeCode 219 kNativeCode, // Native code.
220 kOverwrittenCode, // Dead Dart code that has been overwritten by kDartCode.
siva 2014/03/13 17:12:38 I would call this kReusedCode as it is a region th
Cutch 2014/03/13 17:33:57 Done.
221 kTagCode, // A special kind of code representing a tag.
193 }; 222 };
194 223
195 CodeRegion(Kind kind, uword start, uword end) : 224 CodeRegion(Kind kind, uword start, uword end, int64_t timestamp) :
196 kind_(kind), 225 kind_(kind),
197 start_(start), 226 start_(start),
198 end_(end), 227 end_(end),
199 inclusive_ticks_(0), 228 inclusive_ticks_(0),
200 exclusive_ticks_(0), 229 exclusive_ticks_(0),
201 inclusive_tick_serial_(0), 230 inclusive_tick_serial_(0),
202 name_(NULL), 231 name_(NULL),
232 compile_timestamp_(timestamp),
233 creation_serial_(0),
203 address_table_(new ZoneGrowableArray<AddressEntry>()), 234 address_table_(new ZoneGrowableArray<AddressEntry>()),
204 callers_table_(new ZoneGrowableArray<CallEntry>()), 235 callers_table_(new ZoneGrowableArray<CallEntry>()),
205 callees_table_(new ZoneGrowableArray<CallEntry>()) { 236 callees_table_(new ZoneGrowableArray<CallEntry>()) {
206 ASSERT(start_ < end_); 237 ASSERT(start_ < end_);
207 } 238 }
208 239
209 ~CodeRegion() {
210 }
211 240
212 uword start() const { return start_; } 241 uword start() const { return start_; }
213 void set_start(uword start) { 242 void set_start(uword start) {
214 start_ = start; 243 start_ = start;
215 } 244 }
216 245
217 uword end() const { return end_; } 246 uword end() const { return end_; }
218 void set_end(uword end) { 247 void set_end(uword end) {
219 end_ = end; 248 end_ = end;
220 } 249 }
(...skipping 13 matching lines...) Expand all
234 } 263 }
235 264
236 bool overlaps(const CodeRegion* other) const { 265 bool overlaps(const CodeRegion* other) const {
237 ASSERT(other != NULL); 266 ASSERT(other != NULL);
238 return other->contains(start_) || 267 return other->contains(start_) ||
239 other->contains(end_ - 1) || 268 other->contains(end_ - 1) ||
240 contains(other->start()) || 269 contains(other->start()) ||
241 contains(other->end() - 1); 270 contains(other->end() - 1);
242 } 271 }
243 272
273 intptr_t creation_serial() const { return creation_serial_; }
274 void set_creation_serial(intptr_t serial) {
275 creation_serial_ = serial;
276 }
277 int64_t compile_timestamp() const { return compile_timestamp_; }
278 void set_compile_timestamp(int64_t timestamp) {
279 compile_timestamp_ = timestamp;
280 }
281
244 intptr_t inclusive_ticks() const { return inclusive_ticks_; } 282 intptr_t inclusive_ticks() const { return inclusive_ticks_; }
245 void set_inclusive_ticks(intptr_t inclusive_ticks) { 283 void set_inclusive_ticks(intptr_t inclusive_ticks) {
246 inclusive_ticks_ = inclusive_ticks; 284 inclusive_ticks_ = inclusive_ticks;
247 } 285 }
248 286
249 intptr_t exclusive_ticks() const { return exclusive_ticks_; } 287 intptr_t exclusive_ticks() const { return exclusive_ticks_; }
250 void set_exclusive_ticks(intptr_t exclusive_ticks) { 288 void set_exclusive_ticks(intptr_t exclusive_ticks) {
251 exclusive_ticks_ = exclusive_ticks; 289 exclusive_ticks_ = exclusive_ticks;
252 } 290 }
253 291
(...skipping 11 matching lines...) Expand all
265 Kind kind() const { return kind_; } 303 Kind kind() const { return kind_; }
266 304
267 static const char* KindToCString(Kind kind) { 305 static const char* KindToCString(Kind kind) {
268 switch (kind) { 306 switch (kind) {
269 case kDartCode: 307 case kDartCode:
270 return "Dart"; 308 return "Dart";
271 case kCollectedCode: 309 case kCollectedCode:
272 return "Collected"; 310 return "Collected";
273 case kNativeCode: 311 case kNativeCode:
274 return "Native"; 312 return "Native";
313 case kOverwrittenCode:
314 return "Overwritten";
315 case kTagCode:
316 return "Tag";
275 } 317 }
276 UNREACHABLE(); 318 UNREACHABLE();
277 return NULL; 319 return NULL;
278 } 320 }
279 321
280 void DebugPrint() const { 322 void DebugPrint() const {
281 printf("%s [%" Px ", %" Px ") %s\n", KindToCString(kind_), start(), end(), 323 OS::Print("%s [%" Px ", %" Px ") %"Pd" %"Pd64"\n",
282 name_); 324 KindToCString(kind_),
325 start(),
326 end(),
327 creation_serial_,
328 compile_timestamp_);
283 } 329 }
284 330
285 void AddTickAtAddress(uword pc, bool exclusive, intptr_t serial) { 331 void Tick(uword pc, bool exclusive, intptr_t serial) {
286 // Assert that exclusive ticks are never passed a valid serial number. 332 // Assert that exclusive ticks are never passed a valid serial number.
287 ASSERT((exclusive && (serial == -1)) || (!exclusive && (serial != -1))); 333 ASSERT((exclusive && (serial == -1)) || (!exclusive && (serial != -1)));
288 if (!exclusive && (inclusive_tick_serial_ == serial)) { 334 if (!exclusive && (inclusive_tick_serial_ == serial)) {
289 // We've already given this code object an inclusive tick for this sample. 335 // We've already given this code object an inclusive tick for this sample.
290 return; 336 return;
291 } 337 }
292 // Tick the code object. 338 // Tick the code object.
293 if (exclusive) { 339 if (exclusive) {
294 exclusive_ticks_++; 340 exclusive_ticks_++;
295 } else { 341 } else {
342 inclusive_ticks_++;
296 // Mark the last serial we ticked the inclusive count. 343 // Mark the last serial we ticked the inclusive count.
297 inclusive_tick_serial_ = serial; 344 inclusive_tick_serial_ = serial;
298 inclusive_ticks_++;
299 } 345 }
300 // Tick the address entry. 346 TickAddress(pc, exclusive);
301 const intptr_t length = address_table_->length();
302 intptr_t i = 0;
303 for (; i < length; i++) {
304 AddressEntry& entry = (*address_table_)[i];
305 if (entry.pc == pc) {
306 entry.tick(exclusive);
307 return;
308 }
309 if (entry.pc > pc) {
310 break;
311 }
312 }
313 AddressEntry entry;
314 entry.pc = pc;
315 entry.exclusive_ticks = 0;
316 entry.inclusive_ticks = 0;
317 entry.tick(exclusive);
318 if (i < length) {
319 // Insert at i.
320 address_table_->InsertAt(i, entry);
321 } else {
322 // Add to end.
323 address_table_->Add(entry);
324 }
325 } 347 }
326 348
327 void AddCaller(intptr_t index) { 349 void AddCaller(intptr_t index) {
328 AddCallEntry(callers_table_, index); 350 AddCallEntry(callers_table_, index);
329 } 351 }
330 352
331 void AddCallee(intptr_t index) { 353 void AddCallee(intptr_t index) {
332 AddCallEntry(callees_table_, index); 354 AddCallEntry(callees_table_, index);
333 } 355 }
334 356
335 void PrintNativeCode(JSONObject* profile_code_obj) { 357 void PrintNativeCode(JSONObject* profile_code_obj) {
336 ASSERT(kind() == kNativeCode); 358 ASSERT(kind() == kNativeCode);
337 JSONObject obj(profile_code_obj, "code"); 359 JSONObject obj(profile_code_obj, "code");
338 obj.AddProperty("type", "@Code"); 360 obj.AddProperty("type", "@Code");
339 obj.AddProperty("kind", "Native"); 361 obj.AddProperty("kind", "Native");
340 obj.AddProperty("name", name()); 362 obj.AddProperty("name", name());
341 obj.AddProperty("user_name", name()); 363 obj.AddProperty("user_name", name());
342 obj.AddPropertyF("start", "%" Px "", start()); 364 obj.AddPropertyF("start", "%" Px "", start());
343 obj.AddPropertyF("end", "%" Px "", end()); 365 obj.AddPropertyF("end", "%" Px "", end());
344 obj.AddPropertyF("id", "code/native/%" Px "", start()); 366 obj.AddPropertyF("id", "/code/native-%" Px "", start());
345 { 367 {
346 // Generate a fake function entry. 368 // Generate a fake function entry.
347 JSONObject func(&obj, "function"); 369 JSONObject func(&obj, "function");
348 func.AddProperty("type", "@Function"); 370 func.AddProperty("type", "@Function");
349 func.AddPropertyF("id", "native/functions/%" Pd "", start()); 371 func.AddPropertyF("id", "/functions/native-%" Px "", start());
350 func.AddProperty("name", name()); 372 func.AddProperty("name", name());
351 func.AddProperty("user_name", name()); 373 func.AddProperty("user_name", name());
352 func.AddProperty("kind", "Native"); 374 func.AddProperty("kind", "Native");
353 } 375 }
354 } 376 }
355 377
356 void PrintCollectedCode(JSONObject* profile_code_obj) { 378 void PrintCollectedCode(JSONObject* profile_code_obj) {
357 ASSERT(kind() == kCollectedCode); 379 ASSERT(kind() == kCollectedCode);
358 JSONObject obj(profile_code_obj, "code"); 380 JSONObject obj(profile_code_obj, "code");
359 obj.AddProperty("type", "@Code"); 381 obj.AddProperty("type", "@Code");
360 obj.AddProperty("kind", "Collected"); 382 obj.AddProperty("kind", "Collected");
361 obj.AddProperty("name", name()); 383 obj.AddProperty("name", name());
362 obj.AddProperty("user_name", name()); 384 obj.AddProperty("user_name", name());
363 obj.AddPropertyF("start", "%" Px "", start()); 385 obj.AddPropertyF("start", "%" Px "", start());
364 obj.AddPropertyF("end", "%" Px "", end()); 386 obj.AddPropertyF("end", "%" Px "", end());
365 obj.AddPropertyF("id", "code/collected/%" Px "", start()); 387 obj.AddPropertyF("id", "/code/collected-%" Px "", start());
366 { 388 {
367 // Generate a fake function entry. 389 // Generate a fake function entry.
368 JSONObject func(&obj, "function"); 390 JSONObject func(&obj, "function");
369 func.AddProperty("type", "@Function"); 391 func.AddProperty("type", "@Function");
370 func.AddPropertyF("id", "collected/functions/%" Pd "", start()); 392 obj.AddPropertyF("id", "/functions/collected-%" Px "", start());
371 func.AddProperty("name", name()); 393 func.AddProperty("name", name());
372 func.AddProperty("user_name", name()); 394 func.AddProperty("user_name", name());
373 func.AddProperty("kind", "Collected"); 395 func.AddProperty("kind", "Collected");
374 } 396 }
375 } 397 }
376 398
399 void PrintOverwrittenCode(JSONObject* profile_code_obj) {
400 ASSERT(kind() == kOverwrittenCode);
401 JSONObject obj(profile_code_obj, "code");
402 obj.AddProperty("type", "@Code");
403 obj.AddProperty("kind", "Overwritten");
404 obj.AddProperty("name", name());
405 obj.AddProperty("user_name", name());
406 obj.AddPropertyF("start", "%" Px "", start());
407 obj.AddPropertyF("end", "%" Px "", end());
408 obj.AddPropertyF("id", "/code/overwritten-%" Px "", start());
409 {
410 // Generate a fake function entry.
411 JSONObject func(&obj, "function");
412 func.AddProperty("type", "@Function");
413 obj.AddPropertyF("id", "/functions/overwritten-%" Px "", start());
414 func.AddProperty("name", name());
415 func.AddProperty("user_name", name());
416 func.AddProperty("kind", "Overwritten");
417 }
418 }
419
377 void PrintToJSONArray(Isolate* isolate, JSONArray* events, bool full) { 420 void PrintToJSONArray(Isolate* isolate, JSONArray* events, bool full) {
378 JSONObject obj(events); 421 JSONObject obj(events);
379 obj.AddProperty("type", "ProfileCode"); 422 obj.AddProperty("type", "CodeRegion");
380 obj.AddProperty("kind", KindToCString(kind())); 423 obj.AddProperty("kind", KindToCString(kind()));
381 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks()); 424 obj.AddPropertyF("inclusive_ticks", "%" Pd "", inclusive_ticks());
382 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks()); 425 obj.AddPropertyF("exclusive_ticks", "%" Pd "", exclusive_ticks());
383 if (kind() == kDartCode) { 426 if (kind() == kDartCode) {
384 // Look up code in Dart heap. 427 // Look up code in Dart heap.
385 Code& code = Code::Handle(); 428 Code& code = Code::Handle();
386 code ^= Code::LookupCode(start()); 429 code ^= Code::LookupCode(start());
387 if (code.IsNull()) { 430 if (code.IsNull()) {
388 // Code is a stub in the Vm isolate. 431 // Code is a stub in the Vm isolate.
389 code ^= Code::LookupCodeInVmIsolate(start()); 432 code ^= Code::LookupCodeInVmIsolate(start());
390 } 433 }
391 ASSERT(!code.IsNull()); 434 ASSERT(!code.IsNull());
392 obj.AddProperty("code", code, !full); 435 obj.AddProperty("code", code, !full);
393 } else if (kind() == kCollectedCode) { 436 } else if (kind() == kCollectedCode) {
394 if (name() == NULL) { 437 if (name() == NULL) {
395 // Lazily set generated name. 438 // Lazily set generated name.
396 GenerateAndSetSymbolName("Collected"); 439 GenerateAndSetSymbolName("Collected");
397 } 440 }
398 PrintCollectedCode(&obj); 441 PrintCollectedCode(&obj);
442 } else if (kind() == kOverwrittenCode) {
443 if (name() == NULL) {
444 // Lazily set generated name.
445 GenerateAndSetSymbolName("Overwritten");
446 }
447 PrintOverwrittenCode(&obj);
399 } else { 448 } else {
400 ASSERT(kind() == kNativeCode); 449 ASSERT(kind() == kNativeCode);
401 if (name() == NULL) { 450 if (name() == NULL) {
402 // Lazily set generated name. 451 // Lazily set generated name.
403 GenerateAndSetSymbolName("Native"); 452 GenerateAndSetSymbolName("Native");
404 } 453 }
405 PrintNativeCode(&obj); 454 PrintNativeCode(&obj);
406 } 455 }
407 { 456 {
408 JSONArray ticks(&obj, "ticks"); 457 JSONArray ticks(&obj, "ticks");
(...skipping 16 matching lines...) Expand all
425 JSONArray callees(&obj, "callees"); 474 JSONArray callees(&obj, "callees");
426 for (intptr_t i = 0; i < callees_table_->length(); i++) { 475 for (intptr_t i = 0; i < callees_table_->length(); i++) {
427 const CallEntry& entry = (*callees_table_)[i]; 476 const CallEntry& entry = (*callees_table_)[i];
428 callees.AddValueF("%" Pd "", entry.code_table_index); 477 callees.AddValueF("%" Pd "", entry.code_table_index);
429 callees.AddValueF("%" Pd "", entry.count); 478 callees.AddValueF("%" Pd "", entry.count);
430 } 479 }
431 } 480 }
432 } 481 }
433 482
434 private: 483 private:
484 void TickAddress(uword pc, bool exclusive) {
485 const intptr_t length = address_table_->length();
486 intptr_t i = 0;
487 for (; i < length; i++) {
488 AddressEntry& entry = (*address_table_)[i];
489 if (entry.pc == pc) {
490 // Tick the address entry.
491 entry.tick(exclusive);
492 return;
493 }
494 if (entry.pc > pc) {
495 break;
496 }
497 }
498 // New address, add entry.
499 AddressEntry entry;
500 entry.pc = pc;
501 entry.exclusive_ticks = 0;
502 entry.inclusive_ticks = 0;
503 entry.tick(exclusive);
504 if (i < length) {
505 // Insert at i.
506 address_table_->InsertAt(i, entry);
507 } else {
508 // Add to end.
509 address_table_->Add(entry);
510 }
511 }
512
513
435 void AddCallEntry(ZoneGrowableArray<CallEntry>* table, intptr_t index) { 514 void AddCallEntry(ZoneGrowableArray<CallEntry>* table, intptr_t index) {
436 const intptr_t length = table->length(); 515 const intptr_t length = table->length();
437 intptr_t i = 0; 516 intptr_t i = 0;
438 for (; i < length; i++) { 517 for (; i < length; i++) {
439 CallEntry& entry = (*table)[i]; 518 CallEntry& entry = (*table)[i];
440 if (entry.code_table_index == index) { 519 if (entry.code_table_index == index) {
441 entry.count++; 520 entry.count++;
442 return; 521 return;
443 } 522 }
444 if (entry.code_table_index > index) { 523 if (entry.code_table_index > index) {
(...skipping 11 matching lines...) Expand all
456 } 535 }
457 536
458 void GenerateAndSetSymbolName(const char* prefix) { 537 void GenerateAndSetSymbolName(const char* prefix) {
459 const intptr_t kBuffSize = 512; 538 const intptr_t kBuffSize = 512;
460 char buff[kBuffSize]; 539 char buff[kBuffSize];
461 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")", 540 OS::SNPrint(&buff[0], kBuffSize-1, "%s [%" Px ", %" Px ")",
462 prefix, start(), end()); 541 prefix, start(), end());
463 SetName(buff); 542 SetName(buff);
464 } 543 }
465 544
466 Kind kind_; 545 // CodeRegion kind.
546 const Kind kind_;
547 // CodeRegion start address.
467 uword start_; 548 uword start_;
549 // CodeRegion end address.
468 uword end_; 550 uword end_;
551 // Inclusive ticks.
469 intptr_t inclusive_ticks_; 552 intptr_t inclusive_ticks_;
553 // Exclusive ticks.
470 intptr_t exclusive_ticks_; 554 intptr_t exclusive_ticks_;
555 // Inclusive tick serial number, ensures that each CodeRegion is only given
556 // a single inclusive tick per sample.
471 intptr_t inclusive_tick_serial_; 557 intptr_t inclusive_tick_serial_;
558 // Name of code region.
472 const char* name_; 559 const char* name_;
560 // The compilation timestamp associated with this code region.
561 int64_t compile_timestamp_;
562 // Serial number at which this CodeRegion was created.
563 intptr_t creation_serial_;
473 ZoneGrowableArray<AddressEntry>* address_table_; 564 ZoneGrowableArray<AddressEntry>* address_table_;
474 ZoneGrowableArray<CallEntry>* callers_table_; 565 ZoneGrowableArray<CallEntry>* callers_table_;
475 ZoneGrowableArray<CallEntry>* callees_table_; 566 ZoneGrowableArray<CallEntry>* callees_table_;
476 DISALLOW_COPY_AND_ASSIGN(CodeRegion); 567 DISALLOW_COPY_AND_ASSIGN(CodeRegion);
477 }; 568 };
478 569
570 // A sorted table of CodeRegions. Does not allow for overlap.
571 class CodeRegionTable : public ValueObject {
572 public:
573 enum TickResult {
574 kTicked = 0, // CodeRegion found and ticked.
575 kNotFound = -1, // No CodeRegion found.
576 kNewerCode = -2, // CodeRegion found but it was compiled after sample.
577 };
479 578
480 class ScopeStopwatch : public ValueObject { 579 explicit CodeRegionTable(Isolate* isolate) :
481 public:
482 explicit ScopeStopwatch(const char* name) : name_(name) {
483 start_ = OS::GetCurrentTimeMillis();
484 }
485
486 intptr_t GetElapsed() const {
487 intptr_t end = OS::GetCurrentTimeMillis();
488 ASSERT(end >= start_);
489 return end - start_;
490 }
491
492 ~ScopeStopwatch() {
493 if (FLAG_trace_profiled_isolates) {
494 intptr_t elapsed = GetElapsed();
495 OS::Print("%s took %" Pd " millis.\n", name_, elapsed);
496 }
497 }
498
499 private:
500 const char* name_;
501 intptr_t start_;
502 };
503
504
505 // All code regions. Code region tables are built on demand when a profile
506 // is requested (through the service or on isolate shutdown).
507 class ProfilerCodeRegionTable : public ValueObject {
508 public:
509 explicit ProfilerCodeRegionTable(Isolate* isolate) :
510 heap_(isolate->heap()), 580 heap_(isolate->heap()),
511 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) { 581 code_region_table_(new ZoneGrowableArray<CodeRegion*>(64)) {
512 } 582 }
513 583
514 ~ProfilerCodeRegionTable() { 584 // Ticks the CodeRegion containing pc if it is alive at timestamp.
585 TickResult Tick(uword pc, bool exclusive, intptr_t serial,
586 int64_t timestamp) {
587 intptr_t index = FindIndex(pc);
588 if (index < 0) {
589 // Not found.
590 return kNotFound;
591 }
592 ASSERT(index < code_region_table_->length());
593 CodeRegion* region = At(index);
594 if (region->compile_timestamp() > timestamp) {
595 // Compiled after tick.
596 return kNewerCode;
597 }
598 region->Tick(pc, exclusive, serial);
599 return kTicked;
515 } 600 }
516 601
517 void AddTick(uword pc, bool exclusive, intptr_t serial) { 602 // Table length.
518 intptr_t index = FindIndex(pc); 603 intptr_t Length() const { return code_region_table_->length(); }
519 if (index < 0) {
520 CodeRegion* code_region = CreateCodeRegion(pc);
521 ASSERT(code_region != NULL);
522 index = InsertCodeRegion(code_region);
523 }
524 ASSERT(index >= 0);
525 ASSERT(index < code_region_table_->length());
526 604
527 // Update code object counters. 605 // Get the CodeRegion at index.
528 (*code_region_table_)[index]->AddTickAtAddress(pc, exclusive, serial); 606 CodeRegion* At(intptr_t index) const {
607 return (*code_region_table_)[index];
529 } 608 }
530 609
531 intptr_t Length() const { return code_region_table_->length(); } 610 // Find the table index to the CodeRegion containing pc.
532 611 // Returns < 0 if not found.
533 CodeRegion* At(intptr_t idx) {
534 return (*code_region_table_)[idx];
535 }
536
537 intptr_t FindIndex(uword pc) const { 612 intptr_t FindIndex(uword pc) const {
538 intptr_t index = FindRegionIndex(pc, &CompareLowerBound); 613 intptr_t index = FindRegionIndex(pc, &CompareLowerBound);
539 const CodeRegion* code_region = NULL; 614 const CodeRegion* code_region = NULL;
540 if (index == code_region_table_->length()) { 615 if (index == code_region_table_->length()) {
541 // Not present. 616 // Not present.
542 return -1; 617 return -1;
543 } 618 }
544 code_region = (*code_region_table_)[index]; 619 code_region = At(index);
545 if (code_region->contains(pc)) { 620 if (code_region->contains(pc)) {
546 // Found at index. 621 // Found at index.
547 return index; 622 return index;
548 } 623 }
549 return -1; 624 return -2;
550 } 625 }
551 626
552 #if defined(DEBUG) 627 // Insert code_region into the table. Returns the table index where the
553 void Verify() { 628 // CodeRegion was inserted. Will merge with an overlapping CodeRegion if
554 VerifyOrder(); 629 // one is present.
555 VerifyOverlap();
556 }
557 #endif
558
559 private:
560 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) const {
561 ASSERT(comparator != NULL);
562 intptr_t count = code_region_table_->length();
563 intptr_t first = 0;
564 while (count > 0) {
565 intptr_t it = first;
566 intptr_t step = count / 2;
567 it += step;
568 const CodeRegion* code_region = (*code_region_table_)[it];
569 if (comparator(pc, code_region->start(), code_region->end())) {
570 first = ++it;
571 count -= (step + 1);
572 } else {
573 count = step;
574 }
575 }
576 return first;
577 }
578
579 static bool CompareUpperBound(uword pc, uword start, uword end) {
580 return pc >= end;
581 }
582
583 static bool CompareLowerBound(uword pc, uword start, uword end) {
584 return end <= pc;
585 }
586
587 CodeRegion* CreateCodeRegion(uword pc) {
588 Code& code = Code::Handle();
589 code ^= Code::LookupCode(pc);
590 if (!code.IsNull()) {
591 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
592 code.EntryPoint() + code.Size());
593 }
594 code ^= Code::LookupCodeInVmIsolate(pc);
595 if (!code.IsNull()) {
596 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
597 code.EntryPoint() + code.Size());
598 }
599 if (heap_->CodeContains(pc)) {
600 const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment();
601 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
602 return new CodeRegion(CodeRegion::kCollectedCode, pc,
603 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment);
604 }
605 uintptr_t native_start = 0;
606 char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
607 &native_start);
608 if (native_name == NULL) {
609 return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1);
610 }
611 ASSERT(pc >= native_start);
612 CodeRegion* code_region =
613 new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1);
614 code_region->SetName(native_name);
615 free(native_name);
616 return code_region;
617 }
618
619 void HandleOverlap(CodeRegion* region, CodeRegion* code_region,
620 uword start, uword end) {
621 // We should never see overlapping Dart code regions.
622 ASSERT(region->kind() != CodeRegion::kDartCode);
623 // When code regions overlap, they should be of the same kind.
624 ASSERT(region->kind() == code_region->kind());
625 region->AdjustExtent(start, end);
626 }
627
628 intptr_t InsertCodeRegion(CodeRegion* code_region) { 630 intptr_t InsertCodeRegion(CodeRegion* code_region) {
629 const uword start = code_region->start(); 631 const uword start = code_region->start();
630 const uword end = code_region->end(); 632 const uword end = code_region->end();
631 const intptr_t length = code_region_table_->length(); 633 const intptr_t length = code_region_table_->length();
632 if (length == 0) { 634 if (length == 0) {
633 code_region_table_->Add(code_region); 635 code_region_table_->Add(code_region);
634 return length; 636 return length;
635 } 637 }
636 // Determine the correct place to insert or merge code_region into table. 638 // Determine the correct place to insert or merge code_region into table.
637 intptr_t lo = FindRegionIndex(start, &CompareLowerBound); 639 intptr_t lo = FindRegionIndex(start, &CompareLowerBound);
638 intptr_t hi = FindRegionIndex(end - 1, &CompareUpperBound); 640 intptr_t hi = FindRegionIndex(end - 1, &CompareUpperBound);
641 // TODO(johnmccutchan): Simplify below logic.
639 if ((lo == length) && (hi == length)) { 642 if ((lo == length) && (hi == length)) {
640 lo = length - 1; 643 lo = length - 1;
641 } 644 }
642 if (lo == length) { 645 if (lo == length) {
643 CodeRegion* region = (*code_region_table_)[hi]; 646 CodeRegion* region = At(hi);
644 if (region->overlaps(code_region)) { 647 if (region->overlaps(code_region)) {
645 HandleOverlap(region, code_region, start, end); 648 HandleOverlap(region, code_region, start, end);
646 return hi; 649 return hi;
647 } 650 }
648 code_region_table_->Add(code_region); 651 code_region_table_->Add(code_region);
649 return length; 652 return length;
650 } else if (hi == length) { 653 } else if (hi == length) {
651 CodeRegion* region = (*code_region_table_)[lo]; 654 CodeRegion* region = At(lo);
652 if (region->overlaps(code_region)) { 655 if (region->overlaps(code_region)) {
653 HandleOverlap(region, code_region, start, end); 656 HandleOverlap(region, code_region, start, end);
654 return lo; 657 return lo;
655 } 658 }
656 code_region_table_->Add(code_region); 659 code_region_table_->Add(code_region);
657 return length; 660 return length;
658 } else if (lo == hi) { 661 } else if (lo == hi) {
659 CodeRegion* region = (*code_region_table_)[lo]; 662 CodeRegion* region = At(lo);
660 if (region->overlaps(code_region)) { 663 if (region->overlaps(code_region)) {
661 HandleOverlap(region, code_region, start, end); 664 HandleOverlap(region, code_region, start, end);
662 return lo; 665 return lo;
663 } 666 }
664 code_region_table_->InsertAt(lo, code_region); 667 code_region_table_->InsertAt(lo, code_region);
665 return lo; 668 return lo;
666 } else { 669 } else {
667 CodeRegion* region = (*code_region_table_)[lo]; 670 CodeRegion* region = At(lo);
668 if (region->overlaps(code_region)) { 671 if (region->overlaps(code_region)) {
669 HandleOverlap(region, code_region, start, end); 672 HandleOverlap(region, code_region, start, end);
670 return lo; 673 return lo;
671 } 674 }
672 region = (*code_region_table_)[hi]; 675 region = At(hi);
673 if (region->overlaps(code_region)) { 676 if (region->overlaps(code_region)) {
674 HandleOverlap(region, code_region, start, end); 677 HandleOverlap(region, code_region, start, end);
675 return hi; 678 return hi;
676 } 679 }
677 code_region_table_->InsertAt(hi, code_region); 680 code_region_table_->InsertAt(hi, code_region);
678 return hi; 681 return hi;
679 } 682 }
680 UNREACHABLE(); 683 UNREACHABLE();
681 } 684 }
682 685
683 #if defined(DEBUG) 686 #if defined(DEBUG)
687 void Verify() {
688 VerifyOrder();
689 VerifyOverlap();
690 }
691 #endif
692
693 void DebugPrint() {
694 OS::Print("Dumping CodeRegionTable:\n");
695 for (intptr_t i = 0; i < code_region_table_->length(); i++) {
696 CodeRegion* region = At(i);
697 region->DebugPrint();
698 }
699 }
700
701 private:
702 intptr_t FindRegionIndex(uword pc, RegionCompare comparator) const {
703 ASSERT(comparator != NULL);
704 intptr_t count = code_region_table_->length();
705 intptr_t first = 0;
706 while (count > 0) {
707 intptr_t it = first;
708 intptr_t step = count / 2;
709 it += step;
710 const CodeRegion* code_region = At(it);
711 if (comparator(pc, code_region->start(), code_region->end())) {
712 first = ++it;
713 count -= (step + 1);
714 } else {
715 count = step;
716 }
717 }
718 return first;
719 }
720
721 static bool CompareUpperBound(uword pc, uword start, uword end) {
722 return pc >= end;
723 }
724
725 static bool CompareLowerBound(uword pc, uword start, uword end) {
726 return end <= pc;
727 }
728
729 void HandleOverlap(CodeRegion* region, CodeRegion* code_region,
730 uword start, uword end) {
731 // We should never see overlapping Dart code regions.
732 ASSERT(region->kind() != CodeRegion::kDartCode);
733 // When code regions overlap, they should be of the same kind.
734 ASSERT(region->kind() == code_region->kind());
735 region->AdjustExtent(start, end);
736 }
737
738 #if defined(DEBUG)
684 void VerifyOrder() { 739 void VerifyOrder() {
685 const intptr_t length = code_region_table_->length(); 740 const intptr_t length = code_region_table_->length();
686 if (length == 0) { 741 if (length == 0) {
687 return; 742 return;
688 } 743 }
689 uword last = (*code_region_table_)[0]->end(); 744 uword last = (*code_region_table_)[0]->end();
690 for (intptr_t i = 1; i < length; i++) { 745 for (intptr_t i = 1; i < length; i++) {
691 CodeRegion* a = (*code_region_table_)[i]; 746 CodeRegion* a = (*code_region_table_)[i];
692 ASSERT(last <= a->start()); 747 ASSERT(last <= a->start());
693 last = a->end(); 748 last = a->end();
(...skipping 16 matching lines...) Expand all
710 #endif 765 #endif
711 766
712 Heap* heap_; 767 Heap* heap_;
713 ZoneGrowableArray<CodeRegion*>* code_region_table_; 768 ZoneGrowableArray<CodeRegion*>* code_region_table_;
714 }; 769 };
715 770
716 771
717 class CodeRegionTableBuilder : public SampleVisitor { 772 class CodeRegionTableBuilder : public SampleVisitor {
718 public: 773 public:
719 CodeRegionTableBuilder(Isolate* isolate, 774 CodeRegionTableBuilder(Isolate* isolate,
720 ProfilerCodeRegionTable* code_region_table) 775 CodeRegionTable* live_code_table,
721 : SampleVisitor(isolate), code_region_table_(code_region_table) { 776 CodeRegionTable* dead_code_table)
777 : SampleVisitor(isolate),
778 live_code_table_(live_code_table),
779 dead_code_table_(dead_code_table),
780 heap_(isolate->heap()) {
siva 2014/03/13 17:12:38 Why not store the isolate as a field in this class
Cutch 2014/03/13 17:33:57 Done.
781 ASSERT(live_code_table_ != NULL);
782 ASSERT(dead_code_table_ != NULL);
722 frames_ = 0; 783 frames_ = 0;
723 min_time_ = kMaxInt64; 784 min_time_ = kMaxInt64;
724 max_time_ = 0; 785 max_time_ = 0;
786 vm_isolate_heap_ = Dart::vm_isolate()->heap();
787 ASSERT(vm_isolate_heap_ != NULL);
725 } 788 }
726 789
790 /*
791 code_region_table_->AddTick(sample->At(i), false, visited());
792 ASSERT(index >= 0);
793 ASSERT(index < code_region_table_->length());
794 if (index < 0) {
795 CodeRegion* code_region = CreateCodeRegion(pc);
796 ASSERT(code_region != NULL);
797 index = InsertCodeRegion(code_region);
798 }
799 ASSERT(index >= 0);
800 */
siva 2014/03/13 17:12:38 Why do you want to keep this commented out code ar
Cutch 2014/03/13 17:33:57 Removed.
801
727 void VisitSample(Sample* sample) { 802 void VisitSample(Sample* sample) {
728 int64_t timestamp = sample->timestamp(); 803 int64_t timestamp = sample->timestamp();
729 if (timestamp > max_time_) { 804 if (timestamp > max_time_) {
730 max_time_ = timestamp; 805 max_time_ = timestamp;
731 } 806 }
732 if (timestamp < min_time_) { 807 if (timestamp < min_time_) {
733 min_time_ = timestamp; 808 min_time_ = timestamp;
734 } 809 }
735 // Give the bottom frame an exclusive tick. 810 // Exclusive tick for bottom frame.
736 code_region_table_->AddTick(sample->At(0), true, -1); 811 Tick(sample->At(0), true, timestamp);
737 // Give all frames (including the bottom) an inclusive tick. 812 // Inclusive tick for all frames.
738 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { 813 for (intptr_t i = 0; i < FLAG_profile_depth; i++) {
739 if (sample->At(i) == 0) { 814 if (sample->At(i) == 0) {
740 break; 815 break;
741 } 816 }
742 frames_++; 817 frames_++;
743 code_region_table_->AddTick(sample->At(i), false, visited()); 818 Tick(sample->At(i), false, timestamp);
744 } 819 }
745 } 820 }
746 821
747 intptr_t frames() const { return frames_; } 822 intptr_t frames() const { return frames_; }
823
748 intptr_t TimeDeltaMicros() const { 824 intptr_t TimeDeltaMicros() const {
749 return static_cast<intptr_t>(max_time_ - min_time_); 825 return static_cast<intptr_t>(max_time_ - min_time_);
750 } 826 }
751 int64_t max_time() const { return max_time_; } 827 int64_t max_time() const { return max_time_; }
752 828
753 private: 829 private:
830 void Tick(uword pc, bool exclusive, int64_t timestamp) {
831 CodeRegionTable::TickResult r;
832 intptr_t serial = exclusive ? -1 : visited();
833 r = live_code_table_->Tick(pc, exclusive, serial, timestamp);
834 if (r == CodeRegionTable::kTicked) {
835 // Live code found and ticked.
836 return;
837 }
838 if (r == CodeRegionTable::kNewerCode) {
839 // Code has been overwritten by newer code.
840 // Update shadow table of dead code regions.
841 r = dead_code_table_->Tick(pc, exclusive, serial, timestamp);
842 ASSERT(r != CodeRegionTable::kNewerCode);
843 if (r == CodeRegionTable::kTicked) {
844 // Dead code found and ticked.
845 return;
846 }
847 ASSERT(r == CodeRegionTable::kNotFound);
848 CreateAndTickDeadCodeRegion(pc, exclusive, serial);
849 return;
850 }
851 // Create new live CodeRegion.
852 ASSERT(r == CodeRegionTable::kNotFound);
853 CodeRegion* region = CreateCodeRegion(pc);
854 region->set_creation_serial(visited());
855 intptr_t index = live_code_table_->InsertCodeRegion(region);
856 ASSERT(index >= 0);
857 region = live_code_table_->At(index);
858 if (region->compile_timestamp() <= timestamp) {
859 region->Tick(pc, exclusive, serial);
860 return;
861 }
862 // We have created a new code region but it's for a CodeRegion
863 // compiled after the sample.
864 ASSERT(region->kind() == CodeRegion::kDartCode);
865 CreateAndTickDeadCodeRegion(pc, exclusive, serial);
866 }
867
868 void CreateAndTickDeadCodeRegion(uword pc, bool exclusive, intptr_t serial) {
869 // Need to create dead code.
870 CodeRegion* region = new CodeRegion(CodeRegion::kOverwrittenCode,
871 pc,
872 pc + 1,
873 0);
874 intptr_t index = dead_code_table_->InsertCodeRegion(region);
875 region->set_creation_serial(visited());
876 ASSERT(index >= 0);
877 dead_code_table_->At(index)->Tick(pc, exclusive, serial);
878 }
879
880 CodeRegion* CreateCodeRegion(uword pc) {
881 Code& code = Code::Handle();
882 code ^= Code::LookupCode(pc);
883 if (!code.IsNull()) {
884 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
885 code.EntryPoint() + code.Size(),
886 code.compile_timestamp());
887 }
888 code ^= Code::LookupCodeInVmIsolate(pc);
889 if (!code.IsNull()) {
890 return new CodeRegion(CodeRegion::kDartCode, code.EntryPoint(),
891 code.EntryPoint() + code.Size(),
892 code.compile_timestamp());
893 }
894 if (heap_->CodeContains(pc) || vm_isolate_heap_->CodeContains(pc)) {
siva 2014/03/13 17:12:38 Wouldn't it be more efficient to do this check fir
Cutch 2014/03/13 17:33:57 Done.
895 const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment();
896 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1);
897 return new CodeRegion(CodeRegion::kCollectedCode, pc,
898 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment,
899 0);
900 }
901 uintptr_t native_start = 0;
902 char* native_name = NativeSymbolResolver::LookupSymbolName(pc,
903 &native_start);
904 if (native_name == NULL) {
905 return new CodeRegion(CodeRegion::kNativeCode, pc, pc + 1, 0);
906 }
907 ASSERT(pc >= native_start);
908 CodeRegion* code_region =
909 new CodeRegion(CodeRegion::kNativeCode, native_start, pc + 1, 0);
910 code_region->SetName(native_name);
911 free(native_name);
912 return code_region;
913 }
914
754 intptr_t frames_; 915 intptr_t frames_;
755 int64_t min_time_; 916 int64_t min_time_;
756 int64_t max_time_; 917 int64_t max_time_;
757 ProfilerCodeRegionTable* code_region_table_; 918 CodeRegionTable* live_code_table_;
919 CodeRegionTable* dead_code_table_;
920 const Heap* heap_;
921 const Heap* vm_isolate_heap_;
758 }; 922 };
759 923
760 924
761 class CodeRegionTableCallersBuilder : public SampleVisitor { 925 class CodeRegionTableCallersBuilder : public SampleVisitor {
762 public: 926 public:
763 CodeRegionTableCallersBuilder(Isolate* isolate, 927 CodeRegionTableCallersBuilder(Isolate* isolate,
764 ProfilerCodeRegionTable* code_region_table) 928 CodeRegionTable* live_code_table,
765 : SampleVisitor(isolate), code_region_table_(code_region_table) { 929 CodeRegionTable* dead_code_table)
766 ASSERT(code_region_table_ != NULL); 930 : SampleVisitor(isolate),
931 live_code_table_(live_code_table),
932 dead_code_table_(dead_code_table) {
933 ASSERT(live_code_table_ != NULL);
934 ASSERT(dead_code_table_ != NULL);
935 dead_code_table_offset_ = live_code_table_->Length();
767 } 936 }
768 937
769 void VisitSample(Sample* sample) { 938 void VisitSample(Sample* sample) {
770 intptr_t current_index = code_region_table_->FindIndex(sample->At(0)); 939 int64_t timestamp = sample->timestamp();
771 ASSERT(current_index != -1); 940 intptr_t current_index = FindFinalIndex(sample->At(0), timestamp);
772 CodeRegion* current = code_region_table_->At(current_index); 941 ASSERT(current_index >= 0);
942 CodeRegion* current = At(current_index);
773 intptr_t caller_index = -1; 943 intptr_t caller_index = -1;
774 CodeRegion* caller = NULL; 944 CodeRegion* caller = NULL;
775 intptr_t callee_index = -1; 945 intptr_t callee_index = -1;
776 CodeRegion* callee = NULL; 946 CodeRegion* callee = NULL;
777 for (intptr_t i = 1; i < FLAG_profile_depth; i++) { 947 for (intptr_t i = 1; i < FLAG_profile_depth; i++) {
778 if (sample->At(i) == 0) { 948 if (sample->At(i) == 0) {
779 break; 949 break;
780 } 950 }
781 caller_index = code_region_table_->FindIndex(sample->At(i)); 951 caller_index = FindFinalIndex(sample->At(i), timestamp);
782 ASSERT(caller_index != -1); 952 ASSERT(caller_index >= 0);
783 caller = code_region_table_->At(caller_index); 953 caller = At(caller_index);
784 current->AddCaller(caller_index); 954 current->AddCaller(caller_index);
785 if (callee != NULL) { 955 if (callee != NULL) {
786 current->AddCallee(callee_index); 956 current->AddCallee(callee_index);
787 } 957 }
788 // Move cursors. 958 // Move cursors.
789 callee_index = current_index; 959 callee_index = current_index;
790 callee = current; 960 callee = current;
791 current_index = caller_index; 961 current_index = caller_index;
792 current = caller; 962 current = caller;
793 } 963 }
794 } 964 }
795 965
796 private: 966 private:
797 ProfilerCodeRegionTable* code_region_table_; 967 intptr_t FindFinalIndex(uword pc, int64_t timestamp) {
siva 2014/03/13 17:12:38 ) const {
Cutch 2014/03/13 17:33:57 Done.
968 intptr_t index = live_code_table_->FindIndex(pc);
969 ASSERT(index >= 0);
970 CodeRegion* region = live_code_table_->At(index);
971 ASSERT(region->contains(pc));
972 if (region->compile_timestamp() > timestamp) {
973 // Overwritten code, find in dead code table.
974 index = dead_code_table_->FindIndex(pc);
975 ASSERT(index >= 0);
976 region = dead_code_table_->At(index);
977 ASSERT(region->contains(pc));
978 ASSERT(region->compile_timestamp() <= timestamp);
979 return index + dead_code_table_offset_;
980 }
981 ASSERT(region->compile_timestamp() <= timestamp);
982 return index;
983 }
984
985 CodeRegion* At(intptr_t final_index) {
986 ASSERT(final_index >= 0);
987 if (final_index < dead_code_table_offset_) {
988 return live_code_table_->At(final_index);
989 } else {
990 return dead_code_table_->At(final_index - dead_code_table_offset_);
991 }
992 }
993
994 CodeRegionTable* live_code_table_;
995 CodeRegionTable* dead_code_table_;
996 intptr_t dead_code_table_offset_;
798 }; 997 };
799 998
800 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream, 999 void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream,
801 bool full) { 1000 bool full) {
802 ASSERT(isolate == Isolate::Current()); 1001 ASSERT(isolate == Isolate::Current());
803 // Disable profile interrupts while processing the buffer. 1002 // Disable profile interrupts while processing the buffer.
804 EndExecution(isolate); 1003 EndExecution(isolate);
805 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); 1004 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
806 IsolateProfilerData* profiler_data = isolate->profiler_data(); 1005 IsolateProfilerData* profiler_data = isolate->profiler_data();
807 if (profiler_data == NULL) { 1006 if (profiler_data == NULL) {
808 JSONObject error(stream); 1007 JSONObject error(stream);
809 error.AddProperty("type", "Error"); 1008 error.AddProperty("type", "Error");
810 error.AddProperty("text", "Isolate does not have profiling enabled."); 1009 error.AddProperty("text", "Isolate does not have profiling enabled.");
811 return; 1010 return;
812 } 1011 }
813 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); 1012 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
814 ASSERT(sample_buffer != NULL); 1013 ASSERT(sample_buffer != NULL);
815 { 1014 {
816 StackZone zone(isolate); 1015 StackZone zone(isolate);
817 { 1016 {
818 // Build code region table. 1017 // Live code holds Dart, Native, and Collected CodeRegions.
819 ProfilerCodeRegionTable code_region_table(isolate); 1018 CodeRegionTable live_code_table(isolate);
820 CodeRegionTableBuilder builder(isolate, &code_region_table); 1019 // Dead code holds Overwritten CodeRegions.
821 CodeRegionTableCallersBuilder build_callers(isolate, &code_region_table); 1020 CodeRegionTable dead_code_table(isolate);
1021 CodeRegionTableBuilder builder(isolate,
1022 &live_code_table,
1023 &dead_code_table);
822 { 1024 {
1025 // Build CodeRegion tables.
823 ScopeStopwatch sw("CodeTableBuild"); 1026 ScopeStopwatch sw("CodeTableBuild");
824 sample_buffer->VisitSamples(&builder); 1027 sample_buffer->VisitSamples(&builder);
825 } 1028 }
826 #if defined(DEBUG)
827 code_region_table.Verify();
828 #endif
829 {
830 ScopeStopwatch sw("CodeTableCallersBuild");
831 sample_buffer->VisitSamples(&build_callers);
832 }
833 // Number of samples we processed.
834 intptr_t samples = builder.visited(); 1029 intptr_t samples = builder.visited();
835 intptr_t frames = builder.frames(); 1030 intptr_t frames = builder.frames();
836 if (FLAG_trace_profiled_isolates) { 1031 if (FLAG_trace_profiled_isolates) {
837 OS::Print("%" Pd " frames produced %" Pd " code objects.\n", 1032 intptr_t total_live_code_objects = live_code_table.Length();
838 frames, code_region_table.Length()); 1033 intptr_t total_dead_code_objects = dead_code_table.Length();
1034 OS::Print("Processed %" Pd " frames\n", frames);
1035 OS::Print("CodeTables: live=%" Pd " dead=%" Pd "\n",
1036 total_live_code_objects,
1037 total_dead_code_objects);
1038 }
1039 #if defined(DEBUG)
1040 live_code_table.Verify();
1041 dead_code_table.Verify();
1042 if (FLAG_trace_profiled_isolates) {
1043 OS::Print("CodeRegionTables verified to be ordered and not overlap.\n");
1044 }
1045 #endif
1046 CodeRegionTableCallersBuilder build_callers(isolate,
1047 &live_code_table,
1048 &dead_code_table);
1049 {
1050 // Build CodeRegion callers.
1051 ScopeStopwatch sw("CodeTableCallersBuild");
1052 sample_buffer->VisitSamples(&build_callers);
839 } 1053 }
840 { 1054 {
841 ScopeStopwatch sw("CodeTableStream"); 1055 ScopeStopwatch sw("CodeTableStream");
842 // Serialize to JSON. 1056 // Serialize to JSON.
843 JSONObject obj(stream); 1057 JSONObject obj(stream);
844 obj.AddProperty("type", "Profile"); 1058 obj.AddProperty("type", "Profile");
845 obj.AddProperty("id", "profile"); 1059 obj.AddProperty("id", "profile");
846 obj.AddProperty("samples", samples); 1060 obj.AddProperty("samples", samples);
847 obj.AddProperty("time_delta_micros", builder.TimeDeltaMicros()); 1061 obj.AddProperty("time_delta_micros", builder.TimeDeltaMicros());
848 JSONArray codes(&obj, "codes"); 1062 JSONArray codes(&obj, "codes");
849 for (intptr_t i = 0; i < code_region_table.Length(); i++) { 1063 for (intptr_t i = 0; i < live_code_table.Length(); i++) {
850 CodeRegion* region = code_region_table.At(i); 1064 CodeRegion* region = live_code_table.At(i);
851 ASSERT(region != NULL); 1065 ASSERT(region != NULL);
852 region->PrintToJSONArray(isolate, &codes, full); 1066 region->PrintToJSONArray(isolate, &codes, full);
853 } 1067 }
1068 for (intptr_t i = 0; i < dead_code_table.Length(); i++) {
1069 CodeRegion* region = dead_code_table.At(i);
1070 ASSERT(region != NULL);
1071 region->PrintToJSONArray(isolate, &codes, full);
1072 }
854 } 1073 }
855 } 1074 }
856 } 1075 }
857 // Enable profile interrupts. 1076 // Enable profile interrupts.
858 BeginExecution(isolate); 1077 BeginExecution(isolate);
859 } 1078 }
860 1079
861 1080
862 void Profiler::WriteProfile(Isolate* isolate) { 1081 void Profiler::WriteProfile(Isolate* isolate) {
863 if (isolate == NULL) { 1082 if (isolate == NULL) {
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
1070 stack_lower = 0; 1289 stack_lower = 0;
1071 stack_upper = 0; 1290 stack_upper = 0;
1072 } 1291 }
1073 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper, 1292 ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper,
1074 state.pc, state.fp, state.sp); 1293 state.pc, state.fp, state.sp);
1075 stackWalker.walk(isolate->heap()); 1294 stackWalker.walk(isolate->heap());
1076 } 1295 }
1077 1296
1078 1297
1079 } // namespace dart 1298 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/bin/vmservice/client/lib/src/service/object.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698