| Index: tracing/tracing/metrics/system_health/memory_metric.html | 
| diff --git a/tracing/tracing/metrics/system_health/memory_metric.html b/tracing/tracing/metrics/system_health/memory_metric.html | 
| index 1aa81e05b2b1a6e306adca5b6b0ce6d9d3029ecd..acccd77c6b37cc50f1abfaf9c04ecf8bf258752d 100644 | 
| --- a/tracing/tracing/metrics/system_health/memory_metric.html | 
| +++ b/tracing/tracing/metrics/system_health/memory_metric.html | 
| @@ -48,8 +48,10 @@ tr.exportTo('tr.metrics.sh', function() { | 
| .addBinBoundary(1024 /* 1 KiB */) | 
| .addExponentialBins(16 * 1024 * 1024 * 1024 /* 16 GiB */, 4 * 24)); | 
|  | 
| -  function memoryMetric(values, model) { | 
| -    var browserNameToGlobalDumps = splitGlobalDumpsByBrowserName(model); | 
| +  function memoryMetric(values, model, opt_options) { | 
| +    var rangeOfInterest = opt_options ? opt_options.rangeOfInterest : undefined; | 
| +    var browserNameToGlobalDumps = | 
| +        splitGlobalDumpsByBrowserName(model, rangeOfInterest); | 
| addGeneralMemoryDumpValues(browserNameToGlobalDumps, values); | 
| addDetailedMemoryDumpValues(browserNameToGlobalDumps, values); | 
| addMemoryDumpCountValues(browserNameToGlobalDumps, values); | 
| @@ -60,10 +62,12 @@ tr.exportTo('tr.metrics.sh', function() { | 
| * | 
| * @param {!tr.Model} model The trace model from which the global dumps | 
| *     should be extracted. | 
| +   * @param {!tr.b.Range=} opt_rangeOfInterest If proided, global memory dumps | 
| +   *     that do not inclusively intersect the range will be skipped. | 
| * @return {!Map<string, !Array<!tr.model.GlobalMemoryDump>} A map from | 
| *     browser names to the associated global memory dumps. | 
| */ | 
| -  function splitGlobalDumpsByBrowserName(model) { | 
| +  function splitGlobalDumpsByBrowserName(model, opt_rangeOfInterest) { | 
| var chromeModelHelper = | 
| model.getOrCreateHelper(tr.model.helpers.ChromeModelHelper); | 
| var browserNameToGlobalDumps = new Map(); | 
| @@ -77,8 +81,9 @@ tr.exportTo('tr.metrics.sh', function() { | 
| chromeModelHelper.browserHelpers.forEach(function(helper) { | 
| // Retrieve the associated global memory dumps and check that they | 
| // haven't been classified as belonging to another browser process. | 
| -        var globalDumps = helper.process.memoryDumps.map( | 
| -            d => d.globalMemoryDump); | 
| +        var globalDumps = skipDumpsThatDoNotIntersectRange( | 
| +            helper.process.memoryDumps.map(d => d.globalMemoryDump), | 
| +            opt_rangeOfInterest); | 
| globalDumps.forEach(function(globalDump) { | 
| var existingHelper = globalDumpToBrowserHelper.get(globalDump); | 
| if (existingHelper !== undefined) { | 
| @@ -96,8 +101,9 @@ tr.exportTo('tr.metrics.sh', function() { | 
| // 2. If any global memory dump does not have any associated browser | 
| // process for some reason, associate it with an 'unknown_browser' browser | 
| // so that we don't lose the data. | 
| -    var unclassifiedGlobalDumps = | 
| -        model.globalMemoryDumps.filter(g => !globalDumpToBrowserHelper.has(g)); | 
| +    var unclassifiedGlobalDumps = skipDumpsThatDoNotIntersectRange( | 
| +        model.globalMemoryDumps.filter(g => !globalDumpToBrowserHelper.has(g)), | 
| +        opt_rangeOfInterest); | 
| if (unclassifiedGlobalDumps.length > 0) { | 
| makeKeyUniqueAndSet( | 
| browserNameToGlobalDumps, 'unknown_browser', unclassifiedGlobalDumps); | 
| @@ -106,6 +112,13 @@ tr.exportTo('tr.metrics.sh', function() { | 
| return browserNameToGlobalDumps; | 
| } | 
|  | 
| +  function skipDumpsThatDoNotIntersectRange(dumps, opt_range) { | 
| +    if (!opt_range) | 
| +      return dumps; | 
| +    return dumps.filter(d => opt_range.intersectsExplicitRangeInclusive( | 
| +        d.start, d.end)); | 
| +  } | 
| + | 
| function canonicalizeName(name) { | 
| return name.toLowerCase().replace(' ', '_'); | 
| }; | 
| @@ -246,16 +259,45 @@ tr.exportTo('tr.metrics.sh', function() { | 
| if (processDump.memoryAllocatorDumps === undefined) | 
| return; | 
| processDump.memoryAllocatorDumps.forEach(function(rootAllocatorDump) { | 
| -            CHROME_VALUE_PROPERTIES.forEach(function(spec) { | 
| +            tr.b.iterItems(CHROME_VALUE_PROPERTIES, | 
| +                function(propertyName, descriptionPrefixBuilder) { | 
| +                  addProcessScalar({ | 
| +                    source: 'reported_by_chrome', | 
| +                    component: [rootAllocatorDump.name], | 
| +                    property: propertyName, | 
| +                    value: rootAllocatorDump.numerics[propertyName], | 
| +                    descriptionPrefixBuilder: descriptionPrefixBuilder | 
| +                  }); | 
| +                }); | 
| +          }); | 
| +          // Add memory:<browser-name>:<process-name>:reported_by_chrome:v8: | 
| +          // allocated_by_malloc:effective_size when available. | 
| +          var v8Dump = processDump.getMemoryAllocatorDumpByFullName('v8'); | 
| +          if (v8Dump !== undefined) { | 
| +            var allocatedByMalloc = 0; | 
| +            var hasMallocDump = false; | 
| +            v8Dump.children.forEach(function(isolateDump) { | 
| +              var mallocDump = | 
| +                  isolateDump.getDescendantDumpByFullName('malloc'); | 
| +              if (mallocDump === undefined || | 
| +                  mallocDump.numerics['effective_size'] === undefined) { | 
| +                return; | 
| +              } | 
| +              allocatedByMalloc += mallocDump.numerics['effective_size'].value; | 
| +              hasMallocDump = true; | 
| +            }); | 
| +            if (hasMallocDump) { | 
| addProcessScalar({ | 
| source: 'reported_by_chrome', | 
| -                component: [rootAllocatorDump.name], | 
| -                property: spec.propertyName, | 
| -                value: rootAllocatorDump.numerics[spec.propertyName], | 
| -                descriptionPrefixBuilder: spec.descriptionPrefixBuilder | 
| +                component: ['v8', 'allocated_by_malloc'], | 
| +                property: 'effective_size', | 
| +                value: allocatedByMalloc, | 
| +                unit: sizeInBytes_smallerIsBetter, | 
| +                descriptionPrefixBuilder: | 
| +                    CHROME_VALUE_PROPERTIES['effective_size'] | 
| }); | 
| -            }); | 
| -          }); | 
| +            } | 
| +          } | 
| }, | 
| function(componentTree) { | 
| // Subtract memory:<browser-name>:<process-name>:reported_by_chrome: | 
| @@ -332,7 +374,13 @@ tr.exportTo('tr.metrics.sh', function() { | 
| nameParts.push(formatSpec.userFriendlyPropertyNamePrefix); | 
| nameParts.push(formatSpec.userFriendlyPropertyName); | 
| nameParts.push(formatSpec.componentPreposition); | 
| -        nameParts.push(componentPath.join(':')); | 
| +        if (componentPath[componentPath.length - 1] === 'allocated_by_malloc') { | 
| +          nameParts.push('objects allocated by malloc for'); | 
| +          nameParts.push( | 
| +              componentPath.slice(0, componentPath.length - 1).join(':')); | 
| +        } else { | 
| +          nameParts.push(componentPath.join(':')); | 
| +        } | 
| } | 
| nameParts.push('in'); | 
| } | 
| @@ -341,33 +389,22 @@ tr.exportTo('tr.metrics.sh', function() { | 
| } | 
|  | 
| // Specifications of properties reported by Chrome. | 
| -  var CHROME_VALUE_PROPERTIES = [ | 
| -    { | 
| -      propertyName: 'effective_size', | 
| -      descriptionPrefixBuilder: buildChromeValueDescriptionPrefix.bind( | 
| -          undefined, { | 
| -            userFriendlyPropertyName: 'effective size', | 
| -            componentPreposition: 'of' | 
| -          }) | 
| -    }, | 
| -    { | 
| -      propertyName: 'allocated_objects_size', | 
| -      descriptionPrefixBuilder: buildChromeValueDescriptionPrefix.bind( | 
| -          undefined, { | 
| -            userFriendlyPropertyName: 'size of all objects allocated', | 
| -            totalUserFriendlyPropertyName: 'size of all allocated objects', | 
| -            componentPreposition: 'by' | 
| -          }) | 
| -    }, | 
| -    { | 
| -      propertyName: 'locked_size', | 
| -      descriptionPrefixBuilder: buildChromeValueDescriptionPrefix.bind( | 
| -          undefined, { | 
| -            userFriendlyPropertyName: 'locked (pinned) size', | 
| -            componentPreposition: 'of' | 
| -          }) | 
| -    } | 
| -  ]; | 
| +  var CHROME_VALUE_PROPERTIES = { | 
| +    'effective_size': buildChromeValueDescriptionPrefix.bind(undefined, { | 
| +      userFriendlyPropertyName: 'effective size', | 
| +      componentPreposition: 'of' | 
| +    }), | 
| +    'allocated_objects_size': buildChromeValueDescriptionPrefix.bind( | 
| +        undefined, { | 
| +          userFriendlyPropertyName: 'size of all objects allocated', | 
| +          totalUserFriendlyPropertyName: 'size of all allocated objects', | 
| +          componentPreposition: 'by' | 
| +        }), | 
| +    'locked_size': buildChromeValueDescriptionPrefix.bind(undefined, { | 
| +      userFriendlyPropertyName: 'locked (pinned) size', | 
| +      componentPreposition: 'of' | 
| +    }) | 
| +  }; | 
|  | 
| /** | 
| * Add heavy memory dump values calculated from heavy global memory dumps to | 
| @@ -1014,7 +1051,9 @@ tr.exportTo('tr.metrics.sh', function() { | 
| return numeric; | 
| } | 
|  | 
| -  tr.metrics.MetricRegistry.register(memoryMetric); | 
| +  tr.metrics.MetricRegistry.register(memoryMetric, { | 
| +    supportsRangeOfInterest: true | 
| +  }); | 
|  | 
| return { | 
| memoryMetric: memoryMetric | 
|  |