| Index: runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart | 
| diff --git a/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart b/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart | 
| index 7617a20da4ada1bc6083171d19f10695b4699cf2..3eed1fb738df1ecb8ad2a8d5cd009770bf8a05ca 100644 | 
| --- a/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart | 
| +++ b/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart | 
| @@ -29,12 +29,14 @@ class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { | 
|  | 
| M.ProfileTreeDirection _direction; | 
| ProfileTreeMode _mode; | 
| +  M.SampleProfileType _type; | 
| M.IsolateRef _isolate; | 
| M.SampleProfile _profile; | 
| Iterable<M.CallTreeNodeFilter> _filters; | 
|  | 
| M.ProfileTreeDirection get direction => _direction; | 
| ProfileTreeMode get mode => _mode; | 
| +  M.SampleProfileType get type => _type; | 
| M.IsolateRef get isolate => _isolate; | 
| M.SampleProfile get profile => _profile; | 
| Iterable<M.CallTreeNodeFilter> get filters => _filters; | 
| @@ -50,9 +52,9 @@ class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { | 
| factory CpuProfileVirtualTreeElement( | 
| M.IsolateRef isolate, M.SampleProfile profile, | 
| {ProfileTreeMode mode: ProfileTreeMode.function, | 
| +      M.SampleProfileType type: M.SampleProfileType.cpu, | 
| M.ProfileTreeDirection direction: M.ProfileTreeDirection.exclusive, | 
| RenderingQueue queue}) { | 
| -    assert(isolate != null); | 
| assert(profile != null); | 
| assert(mode != null); | 
| assert(direction != null); | 
| @@ -61,6 +63,7 @@ class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { | 
| e._isolate = isolate; | 
| e._profile = profile; | 
| e._mode = mode; | 
| +    e._type = type; | 
| e._direction = direction; | 
| return e; | 
| } | 
| @@ -84,18 +87,37 @@ class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { | 
|  | 
| void render() { | 
| var tree; | 
| +    var create; | 
| var update; | 
| -    switch (mode) { | 
| -      case ProfileTreeMode.code: | 
| -        tree = _profile.loadCodeTree(_direction); | 
| -        update = _updateCodeRow; | 
| + | 
| +    switch (type) { | 
| +      case M.SampleProfileType.cpu: | 
| +        create = _createCpuRow; | 
| +        if (mode == ProfileTreeMode.code) { | 
| +          update = _updateCpuCodeRow; | 
| +          tree = _profile.loadCodeTree(_direction); | 
| +        } else if (mode == ProfileTreeMode.function) { | 
| +          update = _updateCpuFunctionRow; | 
| +          tree = _profile.loadFunctionTree(_direction); | 
| +        } else { | 
| +          throw new Exception('Unknown ProfileTreeMode: $mode'); | 
| +        } | 
| break; | 
| -      case ProfileTreeMode.function: | 
| -        tree = _profile.loadFunctionTree(_direction); | 
| -        update = _updateFunctionRow; | 
| +      case M.SampleProfileType.memory: | 
| +        create = _createMemoryRow; | 
| +        if (mode == ProfileTreeMode.code) { | 
| +          update = _updateMemoryCodeRow; | 
| +          tree = _profile.loadCodeTree(_direction); | 
| +        } else if (mode == ProfileTreeMode.function) { | 
| +          update = _updateMemoryFunctionRow; | 
| +          tree = _profile.loadFunctionTree(_direction); | 
| +        } else { | 
| +          throw new Exception('Unknown ProfileTreeMode: $mode'); | 
| +        } | 
| break; | 
| default: | 
| -        throw new Exception('Unknown ProfileTreeMode: $mode'); | 
| +        throw new Exception('Unknown SampleProfileType: $type'); | 
| +        break; | 
| } | 
| if (filters != null) { | 
| tree = filters.fold(tree, (tree, filter) { | 
| @@ -106,7 +128,7 @@ class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { | 
| children = [new HeadingElement.h1()..text = 'No Results']; | 
| return; | 
| } | 
| -    _tree = new VirtualTreeElement(_createRow, update, _getChildren, | 
| +    _tree = new VirtualTreeElement(create, update, _getChildren, | 
| items: tree.root.children, queue: _r.queue); | 
| if (tree.root.children.length == 1) { | 
| _tree.expand(tree.root.children.first, autoExpandSingleChildNodes: true); | 
| @@ -114,7 +136,7 @@ class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { | 
| children = [_tree]; | 
| } | 
|  | 
| -  static Element _createRow(toggle) { | 
| +  static Element _createCpuRow(toggle) { | 
| return new DivElement() | 
| ..classes = ['tree-item'] | 
| ..children = [ | 
| @@ -135,9 +157,33 @@ class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { | 
| ]; | 
| } | 
|  | 
| +  static Element _createMemoryRow(toggle) { | 
| +    return new DivElement() | 
| +      ..classes = ['tree-item'] | 
| +      ..children = [ | 
| +        new SpanElement() | 
| +          ..classes = ['inclusive'] | 
| +          ..title = 'memory allocated from resulting calls: ', | 
| +        new SpanElement() | 
| +          ..classes = ['exclusive'] | 
| +          ..title = 'memory allocated during execution: ', | 
| +        new SpanElement()..classes = ['lines'], | 
| +        new ButtonElement() | 
| +          ..classes = ['expander'] | 
| +          ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)), | 
| +        new SpanElement() | 
| +          ..classes = ['percentage'] | 
| +          ..title = 'tree node %', | 
| +        new SpanElement()..classes = ['name'] | 
| +      ]; | 
| +  } | 
| + | 
| static _getChildren(M.CallTreeNode node) => node.children; | 
|  | 
| -  void _updateFunctionRow( | 
| +  static const String _expandedIcon = '▼'; | 
| +  static const String _collapsedIcon = '►'; | 
| + | 
| +  void _updateCpuFunctionRow( | 
| HtmlElement element, M.FunctionCallTreeNode item, int depth) { | 
| element.children[0].text = Utils | 
| .formatPercentNormalized(item.profileFunction.normalizedInclusiveTicks); | 
| @@ -145,7 +191,8 @@ class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { | 
| .formatPercentNormalized(item.profileFunction.normalizedExclusiveTicks); | 
| _updateLines(element.children[2].children, depth); | 
| if (item.children.isNotEmpty) { | 
| -      element.children[3].text = _tree.isExpanded(item) ? '▼' : '►'; | 
| +      element.children[3].text = | 
| +          _tree.isExpanded(item) ? _expandedIcon : _collapsedIcon; | 
| } else { | 
| element.children[3].text = ''; | 
| } | 
| @@ -155,14 +202,39 @@ class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { | 
| ..classes = ['name']; | 
| } | 
|  | 
| -  void _updateCodeRow(HtmlElement element, M.CodeCallTreeNode item, int depth) { | 
| +  void _updateMemoryFunctionRow( | 
| +      HtmlElement element, M.FunctionCallTreeNode item, int depth) { | 
| +    element.children[0].text = | 
| +        Utils.formatSize(item.inclusiveNativeAllocations); | 
| +    element.children[0].title = 'memory allocated from resulting calls: ' + | 
| +        '${item.inclusiveNativeAllocations}B'; | 
| +    element.children[1].text = | 
| +        Utils.formatSize(item.exclusiveNativeAllocations); | 
| +    element.children[1].title = 'memory allocated during execution: ' + | 
| +        '${item.exclusiveNativeAllocations}B'; | 
| +    _updateLines(element.children[2].children, depth); | 
| +    if (item.children.isNotEmpty) { | 
| +      element.children[3].text = | 
| +          _tree.isExpanded(item) ? _expandedIcon : _collapsedIcon; | 
| +    } else { | 
| +      element.children[3].text = ''; | 
| +    } | 
| +    element.children[4].text = Utils.formatPercentNormalized(item.percentage); | 
| +    element.children[5] = new FunctionRefElement( | 
| +        null, item.profileFunction.function, queue: _r.queue) | 
| +      ..classes = ['name']; | 
| +  } | 
| + | 
| +  void _updateCpuCodeRow( | 
| +      HtmlElement element, M.CodeCallTreeNode item, int depth) { | 
| element.children[0].text = Utils | 
| .formatPercentNormalized(item.profileCode.normalizedInclusiveTicks); | 
| element.children[1].text = Utils | 
| .formatPercentNormalized(item.profileCode.normalizedExclusiveTicks); | 
| _updateLines(element.children[2].children, depth); | 
| if (item.children.isNotEmpty) { | 
| -      element.children[3].text = _tree.isExpanded(item) ? '▼' : '►'; | 
| +      element.children[3].text = | 
| +          _tree.isExpanded(item) ? _expandedIcon : _collapsedIcon; | 
| } else { | 
| element.children[3].text = ''; | 
| } | 
| @@ -171,6 +243,28 @@ class CpuProfileVirtualTreeElement extends HtmlElement implements Renderable { | 
| queue: _r.queue)..classes = ['name']; | 
| } | 
|  | 
| +  void _updateMemoryCodeRow( | 
| +      HtmlElement element, M.CodeCallTreeNode item, int depth) { | 
| +    element.children[0].text = | 
| +        Utils.formatSize(item.inclusiveNativeAllocations); | 
| +    element.children[0].title = 'memory allocated from resulting calls: ' + | 
| +        '${item.inclusiveNativeAllocations}B'; | 
| +    element.children[1].text = | 
| +        Utils.formatSize(item.exclusiveNativeAllocations); | 
| +    element.children[1].title = 'memory allocated during execution: ' + | 
| +        '${item.exclusiveNativeAllocations}B'; | 
| +    _updateLines(element.children[2].children, depth); | 
| +    if (item.children.isNotEmpty) { | 
| +      element.children[3].text = | 
| +          _tree.isExpanded(item) ? _expandedIcon : _collapsedIcon; | 
| +    } else { | 
| +      element.children[3].text = ''; | 
| +    } | 
| +    element.children[4].text = Utils.formatPercentNormalized(item.percentage); | 
| +    element.children[5] = new CodeRefElement(null, item.profileCode.code, | 
| +        queue: _r.queue)..classes = ['name']; | 
| +  } | 
| + | 
| static _updateLines(List<Element> lines, int n) { | 
| n = Math.max(0, n); | 
| while (lines.length > n) { | 
|  |