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

Side by Side Diff: runtime/observatory/lib/src/cpu_profile/cpu_profile.dart

Issue 973553005: Fix memory leak in CPU Profile page (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 part of cpu_profiler; 5 part of cpu_profiler;
6 6
7 class CodeCallTreeNode { 7 class CodeCallTreeNode {
8 final ProfileCode profileCode; 8 final ProfileCode profileCode;
9 final int count; 9 final int count;
10 double get percentage => _percentage; 10 double get percentage => _percentage;
11 double _percentage = 0.0; 11 double _percentage = 0.0;
12 final children = new List<CodeCallTreeNode>(); 12 final children;
13 final Set<String> attributes = new Set<String>(); 13 final Set<String> attributes = new Set<String>();
14 CodeCallTreeNode(this.profileCode, this.count) { 14 CodeCallTreeNode(this.profileCode, this.count, int childCount)
15 : children = new List<CodeCallTreeNode>(childCount) {
15 attributes.addAll(profileCode.attributes); 16 attributes.addAll(profileCode.attributes);
16 } 17 }
17 } 18 }
18 19
19 class CodeCallTree { 20 class CodeCallTree {
20 final bool inclusive; 21 final bool inclusive;
21 final CodeCallTreeNode root; 22 final CodeCallTreeNode root;
22 CodeCallTree(this.inclusive, this.root) { 23 CodeCallTree(this.inclusive, this.root) {
23 _setCodePercentage(null, root); 24 _setCodePercentage(null, root);
24 } 25 }
(...skipping 27 matching lines...) Expand all
52 final ProfileFunction profileFunction; 53 final ProfileFunction profileFunction;
53 final int count; 54 final int count;
54 double get percentage => _percentage; 55 double get percentage => _percentage;
55 double _percentage = 0.0; 56 double _percentage = 0.0;
56 final children = new List<FunctionCallTreeNode>(); 57 final children = new List<FunctionCallTreeNode>();
57 final Set<String> attributes = new Set<String>(); 58 final Set<String> attributes = new Set<String>();
58 final codes = new List<FunctionCallTreeNodeCode>(); 59 final codes = new List<FunctionCallTreeNodeCode>();
59 int _totalCodeTicks = 0; 60 int _totalCodeTicks = 0;
60 int get totalCodesTicks => _totalCodeTicks; 61 int get totalCodesTicks => _totalCodeTicks;
61 62
63 FunctionCallTreeNode(this.profileFunction, this.count){
64 profileFunction._addKindBasedAttributes(attributes);
65 }
66
62 // Does this function have an optimized version of itself? 67 // Does this function have an optimized version of itself?
63 bool hasOptimizedCode() { 68 bool hasOptimizedCode() {
64 for (var nodeCode in codes) { 69 for (var nodeCode in codes) {
65 var profileCode = nodeCode.code; 70 var profileCode = nodeCode.code;
66 if (!profileCode.code.isDartCode) { 71 if (!profileCode.code.isDartCode) {
67 continue; 72 continue;
68 } 73 }
69 if (profileCode.code.function != profileFunction.function) { 74 if (profileCode.code.function != profileFunction.function) {
70 continue; 75 continue;
71 } 76 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 if (hasOptimizedCode()) { 120 if (hasOptimizedCode()) {
116 attributes.add('optimized'); 121 attributes.add('optimized');
117 } 122 }
118 if (hasUnoptimizedCode()) { 123 if (hasUnoptimizedCode()) {
119 attributes.add('unoptimized'); 124 attributes.add('unoptimized');
120 } 125 }
121 if (isInlined()) { 126 if (isInlined()) {
122 attributes.add('inlined'); 127 attributes.add('inlined');
123 } 128 }
124 } 129 }
125
126 FunctionCallTreeNode(this.profileFunction, this.count) {
127 profileFunction._addKindBasedAttributes(attributes);
128 }
129 } 130 }
130 131
131 class FunctionCallTree { 132 class FunctionCallTree {
132 final bool inclusive; 133 final bool inclusive;
133 final FunctionCallTreeNode root; 134 final FunctionCallTreeNode root;
134 FunctionCallTree(this.inclusive, this.root) { 135 FunctionCallTree(this.inclusive, this.root) {
135 _setFunctionPercentage(null, root); 136 _setFunctionPercentage(null, root);
136 } 137 }
137 138
138 void _setFunctionPercentage(FunctionCallTreeNode parent, 139 void _setFunctionPercentage(FunctionCallTreeNode parent,
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 Isolate isolate; 407 Isolate isolate;
407 408
408 int sampleCount = 0; 409 int sampleCount = 0;
409 int samplePeriod = 0; 410 int samplePeriod = 0;
410 double sampleRate = 0.0; 411 double sampleRate = 0.0;
411 412
412 int stackDepth = 0; 413 int stackDepth = 0;
413 414
414 double timeSpan = 0.0; 415 double timeSpan = 0.0;
415 416
416 final Map<String, CodeCallTree> codeTrees = 417 final Map<String, List> tries = <String, List>{};
417 <String, CodeCallTree>{};
418 final Map<String, FunctionCallTree> functionTrees =
419 <String, FunctionCallTree>{};
420
421 final List<ProfileCode> codes = new List<ProfileCode>(); 418 final List<ProfileCode> codes = new List<ProfileCode>();
422 final List<ProfileFunction> functions = new List<ProfileFunction>(); 419 final List<ProfileFunction> functions = new List<ProfileFunction>();
423 420
421 CodeCallTree loadCodeTree(String name) {
422 if (name == 'inclusive') {
423 return _loadCodeTree(true, tries['inclusiveCodeTrie']);
424 } else {
425 return _loadCodeTree(false, tries['exclusiveCodeTrie']);
426 }
427 }
428
429 FunctionCallTree loadFunctionTree(String name) {
430 if (name == 'inclusive') {
431 return _loadFunctionTree(true, tries['inclusiveFunctionTrie']);
432 } else {
433 return _loadFunctionTree(false, tries['exclusiveFunctionTrie']);
434 }
435 }
436
424 void clear() { 437 void clear() {
425 sampleCount = 0; 438 sampleCount = 0;
426 samplePeriod = 0; 439 samplePeriod = 0;
427 sampleRate = 0.0; 440 sampleRate = 0.0;
428 stackDepth = 0; 441 stackDepth = 0;
429 timeSpan = 0.0; 442 timeSpan = 0.0;
430 codeTrees.clear();
431 functionTrees.clear();
432 codes.clear(); 443 codes.clear();
433 functions.clear(); 444 functions.clear();
445 tries.clear();
434 } 446 }
435 447
436 void load(Isolate isolate, ServiceMap profile) { 448 void load(Isolate isolate, ServiceMap profile) {
449 clear();
437 if ((isolate == null) || (profile == null)) { 450 if ((isolate == null) || (profile == null)) {
438 return; 451 return;
439 } 452 }
440 453
441 this.isolate = isolate; 454 this.isolate = isolate;
442 isolate.resetCachedProfileData(); 455 isolate.resetCachedProfileData();
443 456
444 clear();
445
446 sampleCount = profile['sampleCount']; 457 sampleCount = profile['sampleCount'];
447 samplePeriod = profile['samplePeriod']; 458 samplePeriod = profile['samplePeriod'];
448 sampleRate = (MICROSECONDS_PER_SECOND / samplePeriod); 459 sampleRate = (MICROSECONDS_PER_SECOND / samplePeriod);
449 stackDepth = profile['stackDepth']; 460 stackDepth = profile['stackDepth'];
450 timeSpan = profile['timeSpan']; 461 timeSpan = profile['timeSpan'];
451 462
452 // Process code table. 463 // Process code table.
453 for (var codeRegion in profile['codes']) { 464 for (var codeRegion in profile['codes']) {
454 Code code = codeRegion['code']; 465 Code code = codeRegion['code'];
455 assert(code != null); 466 assert(code != null);
456 codes.add(new ProfileCode.fromMap(this, code, codeRegion)); 467 codes.add(new ProfileCode.fromMap(this, code, codeRegion));
457 } 468 }
458 469
459 // Process function table. 470 // Process function table.
460 for (var profileFunction in profile['functions']) { 471 for (var profileFunction in profile['functions']) {
461 ServiceFunction function = profileFunction['function']; 472 ServiceFunction function = profileFunction['function'];
462 assert(function != null); 473 assert(function != null);
463 functions.add( 474 functions.add(
464 new ProfileFunction.fromMap(this, function, profileFunction)); 475 new ProfileFunction.fromMap(this, function, profileFunction));
465 } 476 }
466 477
467 // Process code trees. 478 tries['exclusiveCodeTrie'] =
468 var exclusiveCodeTrie = profile['exclusiveCodeTrie']; 479 new Uint32List.fromList(profile['exclusiveCodeTrie']);
469 if (exclusiveCodeTrie != null) { 480 tries['inclusiveCodeTrie'] =
470 codeTrees['exclusive'] = _loadCodeTree(false, exclusiveCodeTrie); 481 new Uint32List.fromList(profile['inclusiveCodeTrie']);
471 } 482 tries['exclusiveFunctionTrie'] =
472 var inclusiveCodeTrie = profile['inclusiveCodeTrie']; 483 new Uint32List.fromList(profile['exclusiveFunctionTrie']);
473 if (inclusiveCodeTrie != null) { 484 tries['inclusiveFunctionTrie'] =
474 codeTrees['inclusive'] = _loadCodeTree(true, inclusiveCodeTrie); 485 new Uint32List.fromList(profile['inclusiveFunctionTrie']);
475 }
476
477 // Process function trees.
478 var exclusiveFunctionTrie = profile['exclusiveFunctionTrie'];
479 if (exclusiveFunctionTrie != null) {
480 functionTrees['exclusive'] =
481 _loadFunctionTree(false, exclusiveFunctionTrie);
482 }
483 var inclusiveFunctionTrie = profile['inclusiveFunctionTrie'];
484 if (inclusiveFunctionTrie != null) {
485 functionTrees['inclusive'] =
486 _loadFunctionTree(true, inclusiveFunctionTrie);
487 }
488 } 486 }
489 487
490 // Data shared across calls to _read*TrieNode. 488 // Data shared across calls to _read*TrieNode.
491 int _trieDataCursor; 489 int _dataCursor = 0;
492 List<int> _trieData;
493 490
494 // The code trie is serialized as a list of integers. Each node 491 // The code trie is serialized as a list of integers. Each node
495 // is recreated by consuming some portion of the list. The format is as 492 // is recreated by consuming some portion of the list. The format is as
496 // follows: 493 // follows:
497 // [0] index into codeTable of code object. 494 // [0] index into codeTable of code object.
498 // [1] tick count (number of times this stack frame occured). 495 // [1] tick count (number of times this stack frame occured).
499 // [2] child node count 496 // [2] child node count
500 // Reading the trie is done by recursively reading the tree depth-first 497 // Reading the trie is done by recursively reading the tree depth-first
501 // pre-order. 498 // pre-order.
502 CodeCallTree _loadCodeTree(bool inclusive, List<int> data) { 499 CodeCallTree _loadCodeTree(bool inclusive, List<int> data) {
503 // Setup state shared across calls to _readTrieNode. 500 if (data == null) {
504 _trieDataCursor = 0;
505 _trieData = data;
506 if (_trieData == null) {
507 return null; 501 return null;
508 } 502 }
509 if (_trieData.length < 3) { 503 if (data.length < 3) {
504 // Not enough for root node.
505 return null;
506 }
507 // Read the tree, returns the root node.
508 var root = _readCodeTrie(data);
509 return new CodeCallTree(inclusive, root);
510 }
511
512 CodeCallTreeNode _readCodeTrieNode(List<int> data) {
513 // Lookup code object.
514 var codeIndex = data[_dataCursor++];
515 var code = codes[codeIndex];
516 // Node tick counter.
517 var count = data[_dataCursor++];
518 // Child node count.
519 var children = data[_dataCursor++];
520 // Create node.
521 var node = new CodeCallTreeNode(code, count, children);
522 return node;
523 }
524
525 CodeCallTreeNode _readCodeTrie(List<int> data) {
526 final nodeStack = new List<CodeCallTreeNode>();
527 final childIndexStack = new List<int>();
528
529 _dataCursor = 0;
530 // Read root.
531 var root = _readCodeTrieNode(data);
532
533 // Push root onto stack.
534 if (root.children.length > 0) {
535 nodeStack.add(root);
536 childIndexStack.add(0);
537 }
538
539 while (nodeStack.length > 0) {
540 var lastIndex = nodeStack.length - 1;
541 // Pop parent from stack.
542 var parent = nodeStack[lastIndex];
543 var childIndex = childIndexStack[lastIndex];
544
545 // Read child node.
546 assert(childIndex < parent.children.length);
547 var node = _readCodeTrieNode(data);
548 parent.children[childIndex++] = node;
549
550 // If parent still has children, update child index.
551 if (childIndex < parent.children.length) {
552 childIndexStack[lastIndex] = childIndex;
553 } else {
554 // Finished processing parent node.
555 nodeStack.removeLast();
556 childIndexStack.removeLast();
557 }
558
559 // If node has children, push onto stack.
560 if (node.children.length > 0) {
561 nodeStack.add(node);
562 childIndexStack.add(0);
563 }
564 }
565
566 return root;
567 }
568
569 FunctionCallTree _loadFunctionTree(bool inclusive, List<int> data) {
570 if (data == null) {
571 return null;
572 }
573 if (data.length < 3) {
510 // Not enough integers for 1 node. 574 // Not enough integers for 1 node.
511 return null; 575 return null;
512 } 576 }
513 // Read the tree, returns the root node. 577 // Read the tree, returns the root node.
514 var root = _readCodeTrieNode(); 578 var root = _readFunctionTrie(data);
515 return new CodeCallTree(inclusive, root); 579 return new FunctionCallTree(inclusive, root);
516 } 580 }
517 581
518 CodeCallTreeNode _readCodeTrieNode() { 582 FunctionCallTreeNode _readFunctionTrieNode(List<int> data) {
519 // Read index into code table. 583 // Read index into function table.
520 var index = _trieData[_trieDataCursor++]; 584 var index = data[_dataCursor++];
521 // Lookup code object. 585 // Lookup function object.
522 var code = codes[index]; 586 var function = functions[index];
523 // Frame counter. 587 // Counter.
524 var count = _trieData[_trieDataCursor++]; 588 var count = data[_dataCursor++];
525 // Create node. 589 // Create node.
526 var node = new CodeCallTreeNode(code, count); 590 var node = new FunctionCallTreeNode(function, count);
591 // Number of code index / count pairs.
592 var codeCount = data[_dataCursor++];
593 node.codes.length = codeCount;
594 var totalCodeTicks = 0;
595 for (var i = 0; i < codeCount; i++) {
596 var codeIndex = data[_dataCursor++];
597 var code = codes[codeIndex];
598 assert(code != null);
599 var codeTicks = data[_dataCursor++];
600 totalCodeTicks += codeTicks;
601 var nodeCode = new FunctionCallTreeNodeCode(code, codeTicks);
602 node.codes[i] = nodeCode;
603 }
604 node.setCodeAttributes();
605 node._totalCodeTicks = totalCodeTicks;
527 // Number of children. 606 // Number of children.
528 var children = _trieData[_trieDataCursor++]; 607 var childCount = data[_dataCursor++];
529 // Recursively read child nodes. 608 node.children.length = childCount;
530 for (var i = 0; i < children; i++) {
531 var child = _readCodeTrieNode();
532 node.children.add(child);
533 }
534 return node; 609 return node;
535 } 610 }
536 611
537 FunctionCallTree _loadFunctionTree(bool inclusive, List<int> data) { 612 FunctionCallTreeNode _readFunctionTrie(List<int> data) {
538 // Setup state shared across calls to _readTrieNode. 613 final nodeStack = new List<FunctionCallTreeNode>();
539 _trieDataCursor = 0; 614 final childIndexStack = new List<int>();
540 _trieData = data; 615
541 if (_trieData == null) { 616 _dataCursor = 0;
542 return null; 617
618 // Read root.
619 var root = _readFunctionTrieNode(data);
620
621 // Push root onto stack.
622 if (root.children.length > 0) {
623 nodeStack.add(root);
624 childIndexStack.add(0);
543 } 625 }
544 if (_trieData.length < 3) { 626
545 // Not enough integers for 1 node. 627 while (nodeStack.length > 0) {
546 return null; 628 var lastIndex = nodeStack.length - 1;
629 // Pop parent from stack.
630 var parent = nodeStack[lastIndex];
631 var childIndex = childIndexStack[lastIndex];
632
633 // Read child node.
634 assert(childIndex < parent.children.length);
635 var node = _readFunctionTrieNode(data);
636 parent.children[childIndex++] = node;
637
638 // If parent still has children, update child index.
639 if (childIndex < parent.children.length) {
640 childIndexStack[lastIndex] = childIndex;
641 } else {
642 // Finished processing parent node.
643 nodeStack.removeLast();
644 childIndexStack.removeLast();
645 }
646
647 // If node has children, push onto stack.
648 if (node.children.length > 0) {
649 nodeStack.add(node);
650 childIndexStack.add(0);
651 }
547 } 652 }
548 // Read the tree, returns the root node.
549 var root = _readFunctionTrieNode();
550 return new FunctionCallTree(inclusive, root);
551 }
552 653
553 FunctionCallTreeNode _readFunctionTrieNode() { 654 return root;
554 // Read index into function table.
555 var index = _trieData[_trieDataCursor++];
556 // Lookup function object.
557 var function = functions[index];
558 // Frame counter.
559 var count = _trieData[_trieDataCursor++];
560 // Create node.
561 var node = new FunctionCallTreeNode(function, count);
562 // Number of code index / count pairs.
563 var codeCount = _trieData[_trieDataCursor++];
564 var totalCodeTicks = 0;
565 for (var i = 0; i < codeCount; i++) {
566 var codeIndex = _trieData[_trieDataCursor++];
567 var code = codes[codeIndex];
568 var codeTicks = _trieData[_trieDataCursor++];
569 totalCodeTicks += codeTicks;
570 var nodeCode = new FunctionCallTreeNodeCode(code, codeTicks);
571 node.codes.add(nodeCode);
572 node.setCodeAttributes();
573 }
574 node._totalCodeTicks = totalCodeTicks;
575 // Number of children.
576 var children = _trieData[_trieDataCursor++];
577 // Recursively read child nodes.
578 for (var i = 0; i < children; i++) {
579 var child = _readFunctionTrieNode();
580 node.children.add(child);
581 }
582 return node;
583 } 655 }
584 656
585 int approximateMillisecondsForCount(count) { 657 int approximateMillisecondsForCount(count) {
586 var MICROSECONDS_PER_MILLISECOND = 1000.0; 658 var MICROSECONDS_PER_MILLISECOND = 1000.0;
587 return (count * samplePeriod) ~/ MICROSECONDS_PER_MILLISECOND; 659 return (count * samplePeriod) ~/ MICROSECONDS_PER_MILLISECOND;
588 } 660 }
589 661
590 double approximateSecondsForCount(count) { 662 double approximateSecondsForCount(count) {
591 var MICROSECONDS_PER_SECOND = 1000000.0; 663 var MICROSECONDS_PER_SECOND = 1000000.0;
592 return (count * samplePeriod) / MICROSECONDS_PER_SECOND; 664 return (count * samplePeriod) / MICROSECONDS_PER_SECOND;
593 } 665 }
594 } 666 }
OLDNEW
« no previous file with comments | « runtime/observatory/lib/src/app/view_model.dart ('k') | runtime/observatory/lib/src/elements/cpu_profile.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698