| 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 4a42bb8a61f3f9754187e0fd87992f994b0fa133..ca6a8a4811cf670fd412bc62e4f76d73a94feae5 100644
|
| --- a/tracing/tracing/metrics/system_health/memory_metric.html
|
| +++ b/tracing/tracing/metrics/system_health/memory_metric.html
|
| @@ -6,6 +6,7 @@ found in the LICENSE file.
|
| -->
|
|
|
| <link rel="import" href="/tracing/base/iteration_helpers.html">
|
| +<link rel="import" href="/tracing/base/multi_dimensional_view.html">
|
| <link rel="import" href="/tracing/base/range.html">
|
| <link rel="import" href="/tracing/metrics/metric_registry.html">
|
| <link rel="import" href="/tracing/model/container_memory_dump.html">
|
| @@ -19,7 +20,6 @@ found in the LICENSE file.
|
| 'use strict';
|
|
|
| tr.exportTo('tr.metrics.sh', function() {
|
| -
|
| var LIGHT = tr.model.ContainerMemoryDump.LevelOfDetail.LIGHT;
|
| var DETAILED = tr.model.ContainerMemoryDump.LevelOfDetail.DETAILED;
|
| var ScalarNumeric = tr.v.ScalarNumeric;
|
| @@ -27,37 +27,8 @@ tr.exportTo('tr.metrics.sh', function() {
|
| tr.v.Unit.byName.sizeInBytes_smallerIsBetter;
|
| var unitlessNumber_smallerIsBetter =
|
| tr.v.Unit.byName.unitlessNumber_smallerIsBetter;
|
| -
|
| - var MMAPS_VALUES = {
|
| - 'overall:pss': {
|
| - path: [],
|
| - byteStat: 'proportionalResident',
|
| - descriptionPrefix: 'total proportional resident size (PSS) of'
|
| - },
|
| - 'overall:private_dirty': {
|
| - path: [],
|
| - byteStat: 'privateDirtyResident',
|
| - descriptionPrefix: 'total private dirty size of'
|
| - },
|
| - 'java_heap:private_dirty': {
|
| - path: ['Android', 'Java runtime', 'Spaces'],
|
| - byteStat: 'privateDirtyResident',
|
| - descriptionPrefix: 'private dirty size of the Java heap in'
|
| - },
|
| - 'ashmem:pss': {
|
| - path: ['Android', 'Ashmem'],
|
| - byteStat: 'proportionalResident',
|
| - descriptionPrefix: 'proportional resident size (PSS) of ashmem in'
|
| - },
|
| - 'native_heap:pss': {
|
| - path: ['Native heap'],
|
| - byteStat: 'proportionalResident',
|
| - descriptionPrefix:
|
| - 'proportional resident size (PSS) of the native heap in'
|
| - }
|
| - };
|
| -
|
| - var ALL_PROCESS_NAMES = 'all';
|
| + var DISPLAYED_SIZE_NUMERIC_NAME =
|
| + tr.model.MemoryAllocatorDump.DISPLAYED_SIZE_NUMERIC_NAME;
|
|
|
| var LEVEL_OF_DETAIL_NAMES = new Map();
|
| LEVEL_OF_DETAIL_NAMES.set(LIGHT, 'light');
|
| @@ -79,9 +50,9 @@ tr.exportTo('tr.metrics.sh', function() {
|
|
|
| function memoryMetric(values, model) {
|
| var browserNameToGlobalDumps = splitGlobalDumpsByBrowserName(model);
|
| - addGeneralMemoryDumpValues(browserNameToGlobalDumps, values, model);
|
| - addDetailedMemoryDumpValues(browserNameToGlobalDumps, values, model);
|
| - addMemoryDumpCountValues(browserNameToGlobalDumps, values, model);
|
| + addGeneralMemoryDumpValues(browserNameToGlobalDumps, values);
|
| + addDetailedMemoryDumpValues(browserNameToGlobalDumps, values);
|
| + addMemoryDumpCountValues(browserNameToGlobalDumps, values);
|
| }
|
|
|
| /**
|
| @@ -171,27 +142,35 @@ tr.exportTo('tr.metrics.sh', function() {
|
| return '\'' + browserName + '\' browser';
|
| }
|
|
|
| + function canonicalizeProcessName(rawProcessName) {
|
| + var baseCanonicalName = canonicalizeName(rawProcessName);
|
| + switch (baseCanonicalName) {
|
| + case 'renderer':
|
| + return 'renderer_processes'; // Intentionally plural.
|
| + case 'browser':
|
| + return 'browser_process';
|
| + default:
|
| + return baseCanonicalName;
|
| + }
|
| + }
|
| +
|
| /**
|
| - * Convert a canonical process name used in value names to a plural
|
| - * user-friendly name used in value descriptions.
|
| - *
|
| - * Examples:
|
| - *
|
| - * CANONICAL PROCESS NAME -> PLURAL USER-FRIENDLY NAME
|
| - * browser -> browser processes
|
| - * renderer -> renderer processes
|
| - * all -> all processes
|
| - * gpu_process -> GPU processes
|
| - * other -> 'other' processes
|
| + * Convert a canonical process name used in value names to a user-friendly
|
| + * name used in value descriptions.
|
| */
|
| - function convertProcessNameToPluralUserFriendlyName(processName) {
|
| + function convertProcessNameToUserFriendlyName(processName,
|
| + opt_requirePlural) {
|
| switch (processName) {
|
| - case 'browser':
|
| - case 'renderer':
|
| - case ALL_PROCESS_NAMES:
|
| - return processName + ' processes';
|
| + case 'browser_process':
|
| + return opt_requirePlural ? 'browser processes' : 'the browser process';
|
| + case 'renderer_processes':
|
| + return 'renderer processes';
|
| case 'gpu_process':
|
| - return 'GPU processes';
|
| + return opt_requirePlural ? 'GPU processes' : 'the GPU process';
|
| + case 'ppapi_process':
|
| + return opt_requirePlural ? 'PPAPI processes' : 'the PPAPI process';
|
| + case 'all_processes':
|
| + return 'all processes';
|
| default:
|
| return '\'' + processName + '\' processes';
|
| }
|
| @@ -228,135 +207,377 @@ tr.exportTo('tr.metrics.sh', function() {
|
| }
|
|
|
| /**
|
| - * Add general memory dump values calculated from all global memory dumps in
|
| - * |model| to |values|. In particular, this function adds the following
|
| - * values:
|
| + * Add general memory dump values calculated from all global memory dumps to
|
| + * |values|. In particular, this function adds the following values:
|
| *
|
| * * PROCESS COUNTS
|
| - * memory:{chrome, webview}:{browser, renderer, ..., all}:process_count
|
| + * memory:{chrome, webview}:
|
| + * {browser_process, renderer_processes, ..., all_processes}:
|
| + * process_count
|
| * type: tr.v.Numeric (histogram over all matching global memory dumps)
|
| * unit: unitlessNumber_smallerIsBetter
|
| *
|
| - * * SUBSYSTEM STATISTICS
|
| - * memory:{chrome, webview}:{browser, renderer, ..., all}:subsystem:
|
| - * {v8, malloc, ...}:{effective_size, allocated_objects_size}
|
| - * memory:{chrome, webview}:{browser, renderer, ..., all}:subsystem:
|
| - * gpu:android_memtrack:{gl, ...}:memtrack_pss
|
| - * memory:{chrome, webview}:{browser, renderer, ..., all}:subsystem:
|
| - * discardable:locked_size
|
| + * * MEMORY USAGE REPORTED BY CHROME
|
| + * memory:{chrome, webview}:
|
| + * {browser_process, renderer_processes, ..., all_processes}:
|
| + * reported_by_chrome[:{v8, malloc, ...}]:
|
| + * {effective_size, allocated_objects_size, locked_size}
|
| * type: tr.v.Numeric (histogram over all matching global memory dumps)
|
| * unit: sizeInBytes_smallerIsBetter
|
| */
|
| - function addGeneralMemoryDumpValues(
|
| - browserNameToGlobalDumps, values, model) {
|
| - addPerProcessNameMemoryDumpValues(browserNameToGlobalDumps,
|
| + function addGeneralMemoryDumpValues(browserNameToGlobalDumps, values) {
|
| + addMemoryDumpValues(browserNameToGlobalDumps,
|
| gmd => true /* process all global memory dumps */,
|
| function(processDump, addProcessScalar) {
|
| - // Increment process_count value.
|
| - addProcessScalar(
|
| - 'process_count',
|
| - new ScalarNumeric(unitlessNumber_smallerIsBetter, 1),
|
| - 'total number of');
|
| + // Increment memory:<browser-name>:<process-name>:process_count value.
|
| + addProcessScalar({
|
| + source: 'process_count',
|
| + value: 1,
|
| + unit: unitlessNumber_smallerIsBetter,
|
| + descriptionPrefixBuilder: buildProcessCountDescriptionPrefix
|
| + });
|
|
|
| + // Add memory:<browser-name>:<process-name>:reported_by_chrome:...
|
| + // values.
|
| if (processDump.memoryAllocatorDumps === undefined)
|
| return;
|
| -
|
| processDump.memoryAllocatorDumps.forEach(function(rootAllocatorDump) {
|
| - var name = rootAllocatorDump.name;
|
| - var valueNamePrefix = 'subsystem:' + name;
|
| -
|
| - // Add generic values for each root memory allocator dump
|
| - // (memory:<browser-name>:<process-name>:subsystem:<name>:
|
| - // {effective_size, allocated_objects_size}).
|
| - addProcessScalar(
|
| - valueNamePrefix + ':effective_size',
|
| - rootAllocatorDump.numerics['effective_size'],
|
| - 'total effective size of ' + name + ' in');
|
| - addProcessScalar(
|
| - valueNamePrefix + ':allocated_objects_size',
|
| - rootAllocatorDump.numerics['allocated_objects_size'],
|
| - 'total size of all objects allocated by ' + name + ' in');
|
| -
|
| - // Add subsystem-specific values.
|
| - switch (rootAllocatorDump.name) {
|
| - // memory:<browser-name>:<process-name>:subsystem:gpu:
|
| - // android_memtrack:<component-name>:memtrack_pss.
|
| - case 'gpu':
|
| - var memtrackDump =
|
| - rootAllocatorDump.getDescendantDumpByFullName(
|
| - 'android_memtrack');
|
| - if (memtrackDump !== undefined) {
|
| - memtrackDump.children.forEach(function(memtrackChildDump) {
|
| - var childName = memtrackChildDump.name;
|
| - addProcessScalar(
|
| - valueNamePrefix + ':android_memtrack:' + childName +
|
| - ':memtrack_pss',
|
| - memtrackChildDump.numerics['memtrack_pss'],
|
| - 'total proportional resident size (PSS) of the ' +
|
| - childName + ' component of Android memtrack in');
|
| - });
|
| - }
|
| - break;
|
| - // memory:<browser-name>:<process-name>:subsystem:discardable:
|
| - // locked_size.
|
| - case 'discardable':
|
| - addProcessScalar(
|
| - valueNamePrefix + ':locked_size',
|
| - rootAllocatorDump.numerics['locked_size'],
|
| - 'total locked (pinned) size of ' + name + ' in');
|
| - break;
|
| - }
|
| + CHROME_VALUE_PROPERTIES.forEach(function(spec) {
|
| + addProcessScalar({
|
| + source: 'reported_by_chrome',
|
| + component: [rootAllocatorDump.name],
|
| + property: spec.propertyName,
|
| + value: rootAllocatorDump.numerics[spec.propertyName],
|
| + descriptionPrefixBuilder: spec.descriptionPrefixBuilder
|
| + });
|
| + });
|
| });
|
| - }, values, model);
|
| + },
|
| + function(componentTree) {
|
| + // Subtract memory:<browser-name>:<process-name>:reported_by_chrome:
|
| + // tracing:<size-property> from memory:<browser-name>:<process-name>:
|
| + // reported_by_chrome:<size-property> if applicable.
|
| + var tracingNode = componentTree.children[1].get('tracing');
|
| + if (tracingNode === undefined)
|
| + return;
|
| + for (var i = 0; i < componentTree.values.length; i++)
|
| + componentTree.values[i].total -= tracingNode.values[i].total;
|
| + }, values);
|
| }
|
|
|
| /**
|
| - * Add heavy memory dump values calculated from heavy global memory dumps in
|
| - * |model| to |values|. In particular, this function adds the following
|
| - * values:
|
| - *
|
| - * * VIRTUAL MEMORY STATISTICS
|
| - * memory:{chrome, webview}:{browser, renderer, ..., all}:vmstats:
|
| - * {overall, ashmem, native_heap}:pss
|
| - * memory:{chrome, webview}:{browser, renderer, ..., all}:vmstats:
|
| - * {overall, java_heap}:private_dirty
|
| + * Build a description prefix for a memory:<browser-name>:<process-name>:
|
| + * process_count value.
|
| + *
|
| + * @param {!Array<string>} componentPath The underlying component path (must
|
| + * be empty).
|
| + * @param {string} processName The canonical name of the process.
|
| + * @return {string} Prefix for the value's description (always
|
| + * 'total number of renderer processes').
|
| + */
|
| + function buildProcessCountDescriptionPrefix(componentPath, processName) {
|
| + if (componentPath.length > 0) {
|
| + throw new Error('Unexpected process count non-empty component path: ' +
|
| + componentPath.join(':'));
|
| + }
|
| + return 'total number of ' + convertProcessNameToUserFriendlyName(
|
| + processName, true /* opt_requirePlural */);
|
| + }
|
| +
|
| + /**
|
| + * Build a description prefix for a memory:<browser-name>:<process-name>:
|
| + * reported_by_chrome:... value.
|
| + *
|
| + * @param {{
|
| + * userFriendlyPropertyName: string,
|
| + * userFriendlyPropertyNamePrefix: (string|undefined),
|
| + * totalUserFriendlyPropertyName: (string|undefined),
|
| + * componentPreposition: (string|undefined) }}
|
| + * formatSpec Specification of how the property should be formatted.
|
| + * @param {!Array<string>} componentPath The underlying component path (e.g.
|
| + * ['malloc']).
|
| + * @param {string} processName The canonical name of the process.
|
| + * @return {string} Prefix for the value's description (e.g.
|
| + * 'effective size of malloc in the browser process').
|
| + */
|
| + function buildChromeValueDescriptionPrefix(
|
| + formatSpec, componentPath, processName) {
|
| + var nameParts = [];
|
| + if (componentPath.length === 0) {
|
| + nameParts.push('total');
|
| + if (formatSpec.totalUserFriendlyPropertyName) {
|
| + nameParts.push(formatSpec.totalUserFriendlyPropertyName);
|
| + } else {
|
| + if (formatSpec.userFriendlyPropertyNamePrefix)
|
| + nameParts.push(formatSpec.userFriendlyPropertyNamePrefix);
|
| + nameParts.push(formatSpec.userFriendlyPropertyName);
|
| + }
|
| + nameParts.push('reported by Chrome for');
|
| + } else {
|
| + if (formatSpec.componentPreposition === undefined) {
|
| + // Use component name as an adjective
|
| + // (e.g. 'size of V8 code and metadata').
|
| + if (formatSpec.userFriendlyPropertyNamePrefix)
|
| + nameParts.push(formatSpec.userFriendlyPropertyNamePrefix);
|
| + nameParts.push(componentPath.join(':'));
|
| + nameParts.push(formatSpec.userFriendlyPropertyName);
|
| + } else {
|
| + // Use component name as a noun with a preposition
|
| + // (e.g. 'size of all objects allocated BY MALLOC').
|
| + if (formatSpec.userFriendlyPropertyNamePrefix)
|
| + nameParts.push(formatSpec.userFriendlyPropertyNamePrefix);
|
| + nameParts.push(formatSpec.userFriendlyPropertyName);
|
| + nameParts.push(formatSpec.componentPreposition);
|
| + nameParts.push(componentPath.join(':'));
|
| + }
|
| + nameParts.push('in');
|
| + }
|
| + nameParts.push(convertProcessNameToUserFriendlyName(processName));
|
| + return nameParts.join(' ');
|
| + }
|
| +
|
| + // 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'
|
| + })
|
| + }
|
| + ];
|
| +
|
| + /**
|
| + * Add heavy memory dump values calculated from heavy global memory dumps to
|
| + * |values|. In particular, this function adds the following values:
|
| + *
|
| + * * MEMORY USAGE REPORTED BY THE OS
|
| + * memory:{chrome, webview}:
|
| + * {browser_process, renderer_processes, ..., all_processes}:
|
| + * reported_by_os:system_memory:[{ashmem, native_heap, java_heap}:]
|
| + * {proportional_resident_size, private_dirty_size}
|
| + * memory:{chrome, webview}:
|
| + * {browser_process, renderer_processes, ..., all_processes}:
|
| + * reported_by_os:gpu_memory:[{gl, graphics, ...}:]
|
| + * proportional_resident_size
|
| + * type: tr.v.Numeric (histogram over matching heavy global memory dumps)
|
| + * unit: sizeInBytes_smallerIsBetter
|
| + *
|
| + * * MEMORY USAGE REPORTED BY CHROME
|
| + * memory:{chrome, webview}:
|
| + * {browser_process, renderer_processes, ..., all_processes}:
|
| + * reported_by_chrome:v8:code_and_metadata_size
|
| * type: tr.v.Numeric (histogram over matching heavy global memory dumps)
|
| * unit: sizeInBytes_smallerIsBetter
|
| */
|
| - function addDetailedMemoryDumpValues(
|
| - browserNameToGlobalDumps, values, model) {
|
| - addPerProcessNameMemoryDumpValues(browserNameToGlobalDumps,
|
| + function addDetailedMemoryDumpValues(browserNameToGlobalDumps, values) {
|
| + addMemoryDumpValues(browserNameToGlobalDumps,
|
| g => g.levelOfDetail === DETAILED,
|
| function(processDump, addProcessScalar) {
|
| - // Add memory:<browser-name>:<process-name>:vmstats:<name> value for
|
| - // each mmap metric.
|
| - tr.b.iterItems(MMAPS_VALUES, function(valueName, valueSpec) {
|
| - var node = getDescendantVmRegionClassificationNode(
|
| - processDump.vmRegions, valueSpec.path);
|
| - var value = node ? (node.byteStats[valueSpec.byteStat] || 0) : 0;
|
| - addProcessScalar(
|
| - 'vmstats:' + valueName,
|
| - new ScalarNumeric(sizeInBytes_smallerIsBetter, value),
|
| - valueSpec.descriptionPrefix);
|
| - });
|
| + // Add memory:<browser-name>:<process-name>:reported_by_os:
|
| + // system_memory:... values.
|
| + tr.b.iterItems(
|
| + SYSTEM_VALUE_COMPONENTS,
|
| + function(componentName, componentSpec) {
|
| + tr.b.iterItems(
|
| + SYSTEM_VALUE_PROPERTIES,
|
| + function(propertyName, propertySpec) {
|
| + var node = getDescendantVmRegionClassificationNode(
|
| + processDump.vmRegions,
|
| + componentSpec.classificationPath);
|
| + var componentPath = ['system_memory'];
|
| + if (componentName)
|
| + componentPath.push(componentName);
|
| + addProcessScalar({
|
| + source: 'reported_by_os',
|
| + component: componentPath,
|
| + property: propertyName,
|
| + value: node === undefined ?
|
| + 0 : (node.byteStats[propertySpec.byteStat] || 0),
|
| + unit: sizeInBytes_smallerIsBetter,
|
| + descriptionPrefixBuilder:
|
| + propertySpec.descriptionPrefixBuilder
|
| + });
|
| + });
|
| + });
|
|
|
| - // Add memory:<browser-name>:<process-name>:subsystem:v8:
|
| + // Add memory:<browser-name>:<process-name>:reported_by_os:
|
| + // gpu_memory:... values.
|
| + var memtrackDump = processDump.getMemoryAllocatorDumpByFullName(
|
| + 'gpu/android_memtrack');
|
| + if (memtrackDump !== undefined) {
|
| + var descriptionPrefixBuilder = SYSTEM_VALUE_PROPERTIES[
|
| + 'proportional_resident_size'].descriptionPrefixBuilder;
|
| + memtrackDump.children.forEach(function(memtrackChildDump) {
|
| + var childName = memtrackChildDump.name;
|
| + addProcessScalar({
|
| + source: 'reported_by_os',
|
| + component: ['gpu_memory', childName],
|
| + property: 'proportional_resident_size',
|
| + value: memtrackChildDump.numerics['memtrack_pss'],
|
| + descriptionPrefixBuilder: descriptionPrefixBuilder
|
| + });
|
| + });
|
| + }
|
| +
|
| + // Add memory:<browser-name>:<process-name>:reported_by_chrome:v8:
|
| // code_and_metadata_size when available.
|
| var v8Dump = processDump.getMemoryAllocatorDumpByFullName('v8');
|
| if (v8Dump !== undefined) {
|
| - var CODE_SIZE_METRIC = 'subsystem:v8:code_and_metadata_size';
|
| // V8 generates bytecode when interpreting and code objects when
|
| // compiling the javascript. Total code size includes the size
|
| // of code and bytecode objects.
|
| - addProcessScalar(
|
| - CODE_SIZE_METRIC,
|
| - v8Dump.numerics['code_and_metadata_size']);
|
| - addProcessScalar(
|
| - CODE_SIZE_METRIC,
|
| - v8Dump.numerics['bytecode_and_metadata_size']);
|
| + addProcessScalar({
|
| + source: 'reported_by_chrome',
|
| + component: ['v8'],
|
| + property: 'code_and_metadata_size',
|
| + value: v8Dump.numerics['code_and_metadata_size'],
|
| + descriptionPrefixBuilder:
|
| + buildCodeAndMetadataSizeValueDescriptionPrefix
|
| + });
|
| + addProcessScalar({
|
| + source: 'reported_by_chrome',
|
| + component: ['v8'],
|
| + property: 'code_and_metadata_size',
|
| + value: v8Dump.numerics['bytecode_and_metadata_size'],
|
| + descriptionPrefixBuilder:
|
| + buildCodeAndMetadataSizeValueDescriptionPrefix
|
| + });
|
| + }
|
| + }, function(componentTree) {}, values);
|
| + }
|
| +
|
| + // Specifications of components reported by the system.
|
| + var SYSTEM_VALUE_COMPONENTS = {
|
| + '': {
|
| + classificationPath: [],
|
| + },
|
| + 'java_heap': {
|
| + classificationPath: ['Android', 'Java runtime', 'Spaces'],
|
| + userFriendlyName: 'the Java heap'
|
| + },
|
| + 'ashmem': {
|
| + classificationPath: ['Android', 'Ashmem'],
|
| + userFriendlyName: 'ashmem'
|
| + },
|
| + 'native_heap': {
|
| + classificationPath: ['Native heap'],
|
| + userFriendlyName: 'the native heap'
|
| + }
|
| + };
|
| +
|
| + // Specifications of properties reported by the system.
|
| + var SYSTEM_VALUE_PROPERTIES = {
|
| + 'proportional_resident_size': {
|
| + byteStat: 'proportionalResident',
|
| + descriptionPrefixBuilder: buildOsValueDescriptionPrefix.bind(
|
| + undefined, 'proportional resident size (PSS)')
|
| + },
|
| + 'private_dirty_size': {
|
| + byteStat: 'privateDirtyResident',
|
| + descriptionPrefixBuilder: buildOsValueDescriptionPrefix.bind(
|
| + undefined, 'private dirty size')
|
| + }
|
| + };
|
| +
|
| + /**
|
| + * Build a description prefix for a memory:<browser-name>:<process-name>:
|
| + * reported_by_os:... value.
|
| + *
|
| + * @param {string} userFriendlyPropertyName User-friendly name of the
|
| + * underlying property (e.g. 'private dirty size').
|
| + * @param {!Array<string>} componentPath The underlying component path (e.g.
|
| + * ['system', 'java_heap']).
|
| + * @param {string} processName The canonical name of the process.
|
| + * @return {string} Prefix for the value's description (e.g.
|
| + * 'total private dirty size of the Java heal in the GPU process').
|
| + */
|
| + function buildOsValueDescriptionPrefix(
|
| + userFriendlyPropertyName, componentPath, processName) {
|
| + if (componentPath.length > 2) {
|
| + throw new Error('OS value component path for \'' +
|
| + userFriendlyPropertyName + '\' too long: ' + componentPath.join(':'));
|
| + }
|
| +
|
| + var nameParts = [];
|
| + if (componentPath.length < 2)
|
| + nameParts.push('total');
|
| +
|
| + nameParts.push(userFriendlyPropertyName);
|
| +
|
| + if (componentPath.length > 0) {
|
| + switch (componentPath[0]) {
|
| + case 'system_memory':
|
| + if (componentPath.length > 1) {
|
| + var userFriendlyComponentName =
|
| + SYSTEM_VALUE_COMPONENTS[componentPath[1]].userFriendlyName;
|
| + if (userFriendlyComponentName === undefined) {
|
| + throw new Error('System value sub-component for \'' +
|
| + userFriendlyPropertyName + '\' unknown: ' +
|
| + componentPath.join(':'));
|
| + }
|
| + nameParts.push('of', userFriendlyComponentName, 'in');
|
| + } else {
|
| + nameParts.push('of system memory (RAM) used by');
|
| + }
|
| + break;
|
| +
|
| + case 'gpu_memory':
|
| + if (componentPath.length > 1) {
|
| + nameParts.push('of the', componentPath[1]);
|
| + nameParts.push('Android memtrack component in');
|
| + } else {
|
| + nameParts.push('of GPU memory (Android memtrack) used by');
|
| }
|
| + break;
|
| +
|
| + default:
|
| + throw new Error('OS value component for \'' +
|
| + userFriendlyPropertyName + '\' unknown: ' +
|
| + componentPath.join(':'));
|
| + }
|
| + } else {
|
| + nameParts.push('reported by the OS for');
|
| + }
|
|
|
| - }, values, model);
|
| + nameParts.push(convertProcessNameToUserFriendlyName(processName));
|
| + return nameParts.join(' ');
|
| + }
|
| +
|
| + /**
|
| + * Build a description prefix for a memory:<browser-name>:<process-name>:
|
| + * reported_by_chrome:...:code_and_metadata_size value.
|
| + *
|
| + * @param {!Array<string>} componentPath The underlying component path (e.g.
|
| + * ['v8']).
|
| + * @param {string} processName The canonical name of the process.
|
| + * @return {string} Prefix for the value's description (e.g.
|
| + * 'size of v8 code and metadata in').
|
| + */
|
| + function buildCodeAndMetadataSizeValueDescriptionPrefix(
|
| + componentPath, processName) {
|
| + return buildChromeValueDescriptionPrefix({
|
| + userFriendlyPropertyNamePrefix: 'size of',
|
| + userFriendlyPropertyName: 'code and metadata'
|
| + }, componentPath, processName);
|
| }
|
|
|
| /**
|
| @@ -374,11 +595,11 @@ tr.exportTo('tr.metrics.sh', function() {
|
| }
|
|
|
| /**
|
| - * Add global memory dump counts in |model| to |values|. In particular,
|
| - * this function adds the following values:
|
| + * Add global memory dump counts to |values|. In particular, this function
|
| + * adds the following values:
|
| *
|
| * * DUMP COUNTS
|
| - * memory:{chrome, webview}:all:dump_count:{light, detailed, total}
|
| + * memory:{chrome, webview}:all_processes:dump_count[:{light, detailed}]
|
| * type: tr.v.ScalarNumeric (scalar over the whole trace)
|
| * unit: unitlessNumber_smallerIsBetter
|
| *
|
| @@ -387,17 +608,16 @@ tr.exportTo('tr.metrics.sh', function() {
|
| * because it doesn't make sense to aggregate them (they are already counts
|
| * over all global dumps associated with the relevant browser).
|
| */
|
| - function addMemoryDumpCountValues(
|
| - browserNameToGlobalDumps, values, model) {
|
| + function addMemoryDumpCountValues(browserNameToGlobalDumps, values) {
|
| browserNameToGlobalDumps.forEach(function(globalDumps, browserName) {
|
| - var levelOfDetailNameToDumpCount = { 'total': 0 };
|
| + var totalDumpCount = 0;
|
| + var levelOfDetailNameToDumpCount = {};
|
| LEVEL_OF_DETAIL_NAMES.forEach(function(levelOfDetailName) {
|
| levelOfDetailNameToDumpCount[levelOfDetailName] = 0;
|
| });
|
|
|
| globalDumps.forEach(function(globalDump) {
|
| - // Increment the total dump count.
|
| - levelOfDetailNameToDumpCount.total++;
|
| + totalDumpCount++;
|
|
|
| // Increment the level-of-detail-specific dump count (if possible).
|
| var levelOfDetailName =
|
| @@ -407,32 +627,51 @@ tr.exportTo('tr.metrics.sh', function() {
|
| levelOfDetailNameToDumpCount[levelOfDetailName]++;
|
| });
|
|
|
| - // Add memory:<browser-name>:dump_count:<level> value for each level of
|
| - // detail (and total).
|
| - var browserUserFriendlyName =
|
| - convertBrowserNameToUserFriendlyName(browserName);
|
| + // Add memory:<browser-name>:all_processes:dump_count[:<level>] values.
|
| + reportMemoryDumpCountAsValue(browserName, undefined /* total */,
|
| + totalDumpCount, values);
|
| tr.b.iterItems(levelOfDetailNameToDumpCount,
|
| function(levelOfDetailName, levelOfDetailDumpCount) {
|
| - var description = [
|
| - 'total number of',
|
| - levelOfDetailName === 'total' ? 'all' : levelOfDetailName,
|
| - 'memory dumps added by',
|
| - browserUserFriendlyName,
|
| - 'to the trace'
|
| - ].join(' ');
|
| - values.addValue(new tr.v.NumericValue(
|
| - ['memory', browserName, ALL_PROCESS_NAMES, 'dump_count',
|
| - levelOfDetailName].join(':'),
|
| - new ScalarNumeric(
|
| - unitlessNumber_smallerIsBetter, levelOfDetailDumpCount),
|
| - { description: description }));
|
| + reportMemoryDumpCountAsValue(browserName, levelOfDetailName,
|
| + levelOfDetailDumpCount, values);
|
| });
|
| });
|
| }
|
|
|
| /**
|
| + * Add a tr.v.ScalarNumeric value to |values| reporting that the number of
|
| + * |levelOfDetailName| memory dumps added by |browserName| was
|
| + * |levelOfDetailCount|.
|
| + */
|
| + function reportMemoryDumpCountAsValue(
|
| + browserName, levelOfDetailName, levelOfDetailDumpCount, values) {
|
| + // Construct the name of the memory value.
|
| + var nameParts = ['memory', browserName, 'all_processes', 'dump_count'];
|
| + if (levelOfDetailName !== undefined)
|
| + nameParts.push(levelOfDetailName);
|
| + var name = nameParts.join(':');
|
| +
|
| + // Build the underlying numeric for the memory value.
|
| + var numeric = new ScalarNumeric(
|
| + unitlessNumber_smallerIsBetter, levelOfDetailDumpCount);
|
| +
|
| + // Build the options for the memory value.
|
| + var description = [
|
| + 'total number of',
|
| + levelOfDetailName || 'all',
|
| + 'memory dumps added by',
|
| + convertBrowserNameToUserFriendlyName(browserName),
|
| + 'to the trace'
|
| + ].join(' ');
|
| + var options = { description: description };
|
| +
|
| + // Report the memory value.
|
| + values.addValue(new tr.v.NumericValue(name, numeric, options));
|
| + }
|
| +
|
| + /**
|
| * Add generic values extracted from process memory dumps and aggregated by
|
| - * browser and process name into |values|.
|
| + * process name and component path into |values|.
|
| *
|
| * For each browser and set of global dumps in |browserNameToGlobalDumps|,
|
| * |customProcessDumpValueExtractor| is applied to every process memory dump
|
| @@ -441,41 +680,99 @@ tr.exportTo('tr.metrics.sh', function() {
|
| *
|
| * function sampleProcessDumpCallback(processDump, addProcessValue) {
|
| * ...
|
| - * addProcessValue('value_name_1', valueExtractedFromProcessDump1);
|
| - * ...
|
| - * addProcessValue('value_name_2', valueExtractedFromProcessDump2);
|
| + * addProcessScalar({
|
| + * source: 'reported_by_chrome',
|
| + * component: ['system', 'native_heap'],
|
| + * property: 'proportional_resident_size',
|
| + * value: pssExtractedFromProcessDump2,
|
| + * descriptionPrefixBuilder: function(componentPath) {
|
| + * return 'PSS of ' + componentPath.join('/') + ' in';
|
| + * }
|
| + * });
|
| * ...
|
| * }
|
| *
|
| * For each global memory dump, the extracted values are summed by process
|
| - * name (browser, renderer, ..., all). The sums are then aggregated over all
|
| - * global memory dumps associated with the given browser. For example,
|
| - * assuming that |customProcessDumpValueExtractor| extracts a value called
|
| - * 'x' from each process memory dump, the following values will be reported:
|
| - *
|
| - * memory:<browser-name>:browser:x : tr.v.Numeric aggregated over [
|
| - * sum of 'x' in all 'browser' process dumps in global dump 1,
|
| - * sum of 'x' in all 'browser' process dumps in global dump 2,
|
| - * ...
|
| - * sum of 'x' in all 'browser' process dumps in global dump N
|
| + * name (browser_process, renderer_processes, ..., all_processes) and
|
| + * component path (e.g. gpu is a sum of gpu:gl, gpu:graphics, ...). The sums
|
| + * are then aggregated over all global memory dumps associated with the given
|
| + * browser. For example, assuming that |customProcessDumpValueExtractor|
|
| + * extracts 'proportional_resident_size' values for component paths
|
| + * ['X', 'A'], ['X', 'B'] and ['Y'] under the same 'source' from each process
|
| + * memory dump, the following values will be reported (for Chrome):
|
| + *
|
| + * memory:chrome:browser_process:source:X:A:proportional_resident_size :
|
| + * Numeric aggregated over [
|
| + * sum of X:A in all 'browser' process dumps in global dump 1,
|
| + * ...
|
| + * sum of X:A in all 'browser' process dumps in global dump N
|
| + * ]
|
| + *
|
| + * memory:chrome:browser_process:source:X:B:proportional_resident_size :
|
| + * Numeric aggregated over [
|
| + * sum of X:B in all 'browser' process dumps in global dump 1,
|
| + * ...
|
| + * sum of X:B in all 'browser' process dumps in global dump N
|
| + * ]
|
| + *
|
| + * memory:chrome:browser_process:source:X:proportional_resident_size :
|
| + * Numeric aggregated over [
|
| + * sum of X:A+X:B in all 'browser' process dumps in global dump 1,
|
| + * ...
|
| + * sum of X:A+X:B in all 'browser' process dumps in global dump N
|
| + * ]
|
| + *
|
| + * memory:chrome:browser_process:source:Y:proportional_resident_size :
|
| + * Numeric aggregated over [
|
| + * sum of Y in all 'browser' process dumps in global dump 1,
|
| + * ...
|
| + * sum of Y in all 'browser' process dumps in global dump N
|
| + * ]
|
| + *
|
| + * memory:chrome:browser_process:source:proportional_resident_size :
|
| + * Numeric aggregated over [
|
| + * sum of X:A+X:B+Y in all 'browser' process dumps in global dump 1,
|
| + * ...
|
| + * sum of X:A+X:B+Y in all 'browser' process dumps in global dump N
|
| + * ]
|
| + *
|
| + * ...
|
| + *
|
| + * memory:chrome:all_processes:source:X:A:proportional_resident_size :
|
| + * Numeric aggregated over [
|
| + * sum of X:A in all process dumps in global dump 1,
|
| + * ...
|
| + * sum of X:A in all process dumps in global dump N,
|
| * ]
|
| *
|
| - * memory:<browser-name>:renderer:x : tr.v.Numeric aggregated over [
|
| - * sum of 'x' in all 'renderer' process dumps in global dump 1,
|
| - * sum of 'x' in all 'renderer' process dumps in global dump 2,
|
| - * ...
|
| - * sum of 'x' in all 'renderer' process dumps in global dump N
|
| + * memory:chrome:all_processes:source:X:B:proportional_resident_size :
|
| + * Numeric aggregated over [
|
| + * sum of X:B in all process dumps in global dump 1,
|
| + * ...
|
| + * sum of X:B in all process dumps in global dump N,
|
| * ]
|
| *
|
| - * ...
|
| + * memory:chrome:all_processes:source:X:proportional_resident_size :
|
| + * Numeric aggregated over [
|
| + * sum of X:A+X:B in all process dumps in global dump 1,
|
| + * ...
|
| + * sum of X:A+X:B in all process dumps in global dump N,
|
| + * ]
|
| *
|
| - * memory:<browser-name>:all:x : tr.v.Numeric aggregated over [
|
| - * sum of 'x' in all process dumps in global dump 1,
|
| - * sum of 'x' in all process dumps in global dump 2,
|
| - * ...
|
| - * sum of 'x' in all process dumps in global dump N,
|
| + * memory:chrome:all_processes:source:Y:proportional_resident_size :
|
| + * Numeric aggregated over [
|
| + * sum of Y in all process dumps in global dump 1,
|
| + * ...
|
| + * sum of Y in all process dumps in global dump N
|
| * ]
|
| *
|
| + * memory:chrome:all_processes:source:proportional_resident_size :
|
| + * Numeric aggregated over [
|
| + * sum of X:A+X:B+Y in all process dumps in global dump 1,
|
| + * ...
|
| + * sum of X:A+X:B+Y in all process dumps in global dump N
|
| + * ]
|
| + *
|
| * where global dumps 1 to N are the global dumps associated with the given
|
| * browser.
|
| *
|
| @@ -487,32 +784,31 @@ tr.exportTo('tr.metrics.sh', function() {
|
| * customGlobalDumpFilter Predicate for filtering global memory dumps.
|
| * @param {!function(
|
| * !tr.model.ProcessMemoryDump,
|
| - * !function(string, !tr.v.ScalarNumeric))}
|
| + * !function(!{
|
| + * source: string,
|
| + * componentPath: (!Array<string>|undefined),
|
| + * propertyName: (string|undefined),
|
| + * value: (!tr.v.ScalarNumeric|number|undefined),
|
| + * unit: (!tr.v.Unit|undefined),
|
| + * descriptionPrefixBuilder: (!function(!Array<string>): string)
|
| + * }))}
|
| * customProcessDumpValueExtractor Callback for extracting values from a
|
| * process memory dump.
|
| + * @param {!function(!tr.b.MultiDimensionalViewNode)}
|
| + * customComponentTreeModifier Callback applied to every component tree
|
| + * wrt each process name.
|
| * @param {!tr.metrics.ValueSet} values List of values to which the
|
| * resulting aggregated values are added.
|
| - * @param {!tr.Model} model The underlying trace model.
|
| */
|
| - function addPerProcessNameMemoryDumpValues(
|
| - browserNameToGlobalDumps, customGlobalDumpFilter,
|
| - customProcessDumpValueExtractor, values, model) {
|
| + function addMemoryDumpValues(browserNameToGlobalDumps, customGlobalDumpFilter,
|
| + customProcessDumpValueExtractor, customComponentTreeModifier,
|
| + values) {
|
| browserNameToGlobalDumps.forEach(function(globalDumps, browserName) {
|
| var filteredGlobalDumps = globalDumps.filter(customGlobalDumpFilter);
|
| -
|
| - // Value name -> {unit: tr.v.Unit, descriptionPrefix: string}.
|
| - var valueNameToSpec = {};
|
| -
|
| - // Global memory dump timestamp (list index) -> Process name ->
|
| - // Value name -> number.
|
| - var timeToProcessNameToValueNameToSum =
|
| - calculatePerProcessNameMemoryDumpValues(filteredGlobalDumps,
|
| - valueNameToSpec, customProcessDumpValueExtractor);
|
| -
|
| - injectTotalsIntoPerProcessNameMemoryDumpValues(
|
| - timeToProcessNameToValueNameToSum);
|
| - reportPerProcessNameMemoryDumpValues(timeToProcessNameToValueNameToSum,
|
| - valueNameToSpec, browserName, values, model);
|
| + var sourceToPropertyToData = extractDataFromGlobalDumps(
|
| + filteredGlobalDumps, customProcessDumpValueExtractor);
|
| + reportDataAsValues(sourceToPropertyToData, browserName,
|
| + customComponentTreeModifier, values);
|
| });
|
| }
|
|
|
| @@ -521,141 +817,196 @@ tr.exportTo('tr.metrics.sh', function() {
|
| * sums of values extracted by |customProcessDumpValueExtractor| from the
|
| * associated process memory dumps.
|
| *
|
| - * This function returns the following list of nested maps:
|
| + * This function returns the following nested map structure:
|
| *
|
| - * Global memory dump timestamp (list index)
|
| - * -> Process name (dict with keys 'browser', 'renderer', ...)
|
| - * -> Value name (dict with keys 'subsystem:v8', ...)
|
| - * -> Sum of value over the processes (number).
|
| + * Source name (Map key, e.g. 'reported_by_os')
|
| + * -> Property name (Map key, e.g. 'proportional_resident_size')
|
| + * -> {unit, descriptionPrefixBuilder, processAndComponentTreeBuilder}
|
| *
|
| - * and updates the |valueNameToSpec| argument to be a map from the names of
|
| - * the extracted values to specifications:
|
| + * where |processAndComponentTreeBuilder| is a
|
| + * tr.b.MultiDimensionalViewBuilder:
|
| *
|
| - * Value name (dict with keys 'subsystem:v8', ...)
|
| - * -> { unit: tr.v.Unit, descriptionPrefix: string }.
|
| + * Browser name (0th dimension key, e.g. 'webview') x
|
| + * -> Component path (1st dimension keys, e.g. ['system', 'native_heap'])
|
| + * -> Sum of value over the processes (number).
|
| *
|
| - * See addPerProcessNameMemoryDumpValues for more details.
|
| + * See addMemoryDumpValues for more details.
|
| */
|
| - function calculatePerProcessNameMemoryDumpValues(
|
| - globalDumps, valueNameToSpec, customProcessDumpValueExtractor) {
|
| - return globalDumps.map(function(globalDump) {
|
| - // Process name -> Value name -> Sum over processes.
|
| - var processNameToValueNameToSum = {};
|
| -
|
| + function extractDataFromGlobalDumps(
|
| + globalDumps, customProcessDumpValueExtractor) {
|
| + var sourceToPropertyToData = new Map();
|
| + var dumpCount = globalDumps.length;
|
| + globalDumps.forEach(function(globalDump, dumpIndex) {
|
| tr.b.iterItems(globalDump.processMemoryDumps, function(_, processDump) {
|
| - // Process name is typically 'browser', 'renderer', etc.
|
| - var rawProcessName = processDump.process.name || 'unknown';
|
| - var processName = canonicalizeName(rawProcessName);
|
| -
|
| - // Value name -> Sum over processes.
|
| - var valueNameToSum = processNameToValueNameToSum[processName];
|
| - if (valueNameToSum === undefined)
|
| - processNameToValueNameToSum[processName] = valueNameToSum = {};
|
| -
|
| - customProcessDumpValueExtractor(
|
| - processDump,
|
| - function addProcessScalar(
|
| - name, processDumpScalar, descriptionPrefix) {
|
| - if (processDumpScalar === undefined)
|
| - return;
|
| - var valueSpec = valueNameToSpec[name];
|
| - if (valueSpec === undefined) {
|
| - valueNameToSpec[name] = valueSpec = {
|
| - unit: processDumpScalar.unit,
|
| - descriptionPrefix: descriptionPrefix
|
| - };
|
| - } else {
|
| - if (processDumpScalar.unit !== valueSpec.unit) {
|
| - throw new Error('Multiple units provided for value \'' +
|
| - name + '\': ' + valueSpec.unit.unitName + ' and ' +
|
| - processDumpScalar.unit.unitName);
|
| - }
|
| - if (descriptionPrefix !== valueSpec.descriptionPrefix) {
|
| - throw new Error('Multiple description prefixes provided ' +
|
| - 'for value \'' + name + '\': \'' +
|
| - valueSpec.descriptionPrefix + '\' and \'' +
|
| - descriptionPrefix + '\'');
|
| - }
|
| - }
|
| - valueNameToSum[name] = (valueNameToSum[name] || 0) +
|
| - processDumpScalar.value;
|
| - });
|
| + extractDataFromProcessDump(
|
| + processDump, sourceToPropertyToData, dumpIndex, dumpCount,
|
| + customProcessDumpValueExtractor);
|
| });
|
| - return processNameToValueNameToSum;
|
| });
|
| + return sourceToPropertyToData;
|
| }
|
|
|
| - /**
|
| - * For each timestamp (corresponding to a global memory dump) in
|
| - * |timeToProcessNameToValueNameToSum|, sum per-process-name sums into total
|
| - * sums over all process names.
|
| - *
|
| - * See addPerProcessNameMemoryDumpValues for more details.
|
| - */
|
| - function injectTotalsIntoPerProcessNameMemoryDumpValues(
|
| - timeToProcessNameToValueNameToSum) {
|
| - timeToProcessNameToValueNameToSum.forEach(
|
| - function(processNameToValueNameToSum) {
|
| - var valueNameToProcessNameToSum = tr.b.invertArrayOfDicts(
|
| - tr.b.dictionaryValues(processNameToValueNameToSum));
|
| - processNameToValueNameToSum[ALL_PROCESS_NAMES] = tr.b.mapItems(
|
| - valueNameToProcessNameToSum,
|
| - function(valueName, perProcessSums) {
|
| - return perProcessSums.reduce((acc, sum) => acc + sum, 0);
|
| - });
|
| + function extractDataFromProcessDump(processDump, sourceToPropertyToData,
|
| + dumpIndex, dumpCount, customProcessDumpValueExtractor) {
|
| + // Process name is typically 'browser', 'renderer', etc.
|
| + var rawProcessName = processDump.process.name || 'unknown';
|
| + var processNamePath = [canonicalizeProcessName(rawProcessName)];
|
| +
|
| + customProcessDumpValueExtractor(
|
| + processDump,
|
| + function addProcessScalar(spec) {
|
| + if (spec.value === undefined)
|
| + return;
|
| +
|
| + var component = spec.component || [];
|
| + function createDetailsForErrorMessage() {
|
| + var propertyUserFriendlyName =
|
| + spec.property === undefined ? '(undefined)' : spec.property;
|
| + var componentUserFriendlyName =
|
| + component.length === 0 ? '(empty)' : component.join(':');
|
| + return ['source=', spec.source, ', property=',
|
| + propertyUserFriendlyName, ', component=',
|
| + componentUserFriendlyName, ' in ',
|
| + processDump.process.userFriendlyName].join('');
|
| + }
|
| +
|
| + var value, unit;
|
| + if (spec.value instanceof ScalarNumeric) {
|
| + value = spec.value.value;
|
| + unit = spec.value.unit;
|
| + if (spec.unit !== undefined) {
|
| + throw new Error('ScalarNumeric value for ' +
|
| + createDetailsForErrorMessage() + ' already specifies a unit');
|
| + }
|
| + } else {
|
| + value = spec.value;
|
| + unit = spec.unit;
|
| + }
|
| +
|
| + var propertyToData = sourceToPropertyToData.get(spec.source);
|
| + if (propertyToData === undefined) {
|
| + propertyToData = new Map();
|
| + sourceToPropertyToData.set(spec.source, propertyToData);
|
| + }
|
| +
|
| + var data = propertyToData.get(spec.property);
|
| + if (data === undefined) {
|
| + data = {
|
| + processAndComponentTreeBuilder:
|
| + new tr.b.MultiDimensionalViewBuilder(
|
| + 2 /* dimensions (process name and component path) */,
|
| + dumpCount /* valueCount */),
|
| + unit: unit,
|
| + descriptionPrefixBuilder: spec.descriptionPrefixBuilder
|
| + };
|
| + propertyToData.set(spec.property, data);
|
| + } else if (data.unit !== unit) {
|
| + throw new Error('Multiple units provided for ' +
|
| + createDetailsForErrorMessage() + ':' +
|
| + data.unit.unitName + ' and ' + unit.unitName);
|
| + } else if (data.descriptionPrefixBuilder !==
|
| + spec.descriptionPrefixBuilder) {
|
| + throw new Error(
|
| + 'Multiple description prefix builders provided for' +
|
| + createDetailsForErrorMessage());
|
| + }
|
| +
|
| + var values = new Array(dumpCount);
|
| + values[dumpIndex] = value;
|
| +
|
| + data.processAndComponentTreeBuilder.addPath(
|
| + [processNamePath, component] /* path */, values,
|
| + tr.b.MultiDimensionalViewBuilder.ValueKind.TOTAL /* valueKind */);
|
| });
|
| }
|
|
|
| + function reportDataAsValues(sourceToPropertyToData, browserName,
|
| + customComponentTreeModifier, values) {
|
| + // For each source name (e.g. 'reported_by_os')...
|
| + sourceToPropertyToData.forEach(function(propertyToData, sourceName) {
|
| + // For each property name (e.g. 'effective_size')...
|
| + propertyToData.forEach(function(data, propertyName) {
|
| + var tree = data.processAndComponentTreeBuilder.buildTopDownTreeView();
|
| + var unit = data.unit;
|
| + var descriptionPrefixBuilder = data.descriptionPrefixBuilder;
|
| +
|
| + // Total over 'all' processes...
|
| + customComponentTreeModifier(tree);
|
| + reportComponentDataAsValues(browserName, sourceName,
|
| + propertyName, 'all_processes', [] /* componentPath */, tree,
|
| + unit, descriptionPrefixBuilder, values);
|
| +
|
| + // For each process name (e.g. 'renderer')...
|
| + tree.children[0].forEach(function(processTree, processName) {
|
| + if (processTree.children[0].size > 0) {
|
| + throw new Error('Multi-dimensional view node for source=' +
|
| + sourceName + ', property=' +
|
| + (propertyName === undefined ? '(undefined)' : propertyName) +
|
| + ', process=' + processName +
|
| + ' has children wrt the process name dimension');
|
| + }
|
| + customComponentTreeModifier(processTree);
|
| + reportComponentDataAsValues(browserName, sourceName,
|
| + propertyName, processName, [] /* componentPath */, processTree,
|
| + unit, descriptionPrefixBuilder, values);
|
| + });
|
| + });
|
| + });
|
| + }
|
| +
|
| /**
|
| - * For each process name (plus total over 'all' process names) and value
|
| - * name, add a tr.v.Numeric aggregating the associated values across all
|
| - * timestamps (corresponding to global memory dumps associated with the given
|
| - * browser) in |timeToProcessNameToValueNameToSum| to |values|.
|
| + * For the given |browserName| (e.g. 'chrome'), |processName|
|
| + * (e.g. 'gpu_process'), |propertyName| (e.g. 'effective_size'),
|
| + * |componentPath| (e.g. ['v8']), add a tr.v.Numeric with |unit| aggregating
|
| + * the total values of the associated |componentNode| across all timestamps
|
| + * (corresponding to global memory dumps associated with the given browser)
|
| + * to |values|.
|
| *
|
| - * See addPerProcessNameMemoryDumpValues for more details.
|
| + * See addMemoryDumpValues for more details.
|
| */
|
| - function reportPerProcessNameMemoryDumpValues(
|
| - timeToProcessNameToValueNameToSum, valueNameToSpec, browserName, values,
|
| - model) {
|
| - var browserUserFriendlyName =
|
| - convertBrowserNameToUserFriendlyName(browserName);
|
| - var processNameToTimeToValueNameToSum =
|
| - tr.b.invertArrayOfDicts(timeToProcessNameToValueNameToSum);
|
| - tr.b.iterItems(
|
| - processNameToTimeToValueNameToSum,
|
| - function(processName, timeToValueNameToSum) {
|
| - var processPluralUserFriendlyName =
|
| - convertProcessNameToPluralUserFriendlyName(processName);
|
| - var valueNameToTimeToSum =
|
| - tr.b.invertArrayOfDicts(timeToValueNameToSum);
|
| - tr.b.iterItems(
|
| - valueNameToTimeToSum,
|
| - function(valueName, timeToSum) {
|
| - var valueSpec = valueNameToSpec[valueName];
|
| - var description = [
|
| - valueSpec.descriptionPrefix,
|
| - processPluralUserFriendlyName,
|
| - 'in',
|
| - browserUserFriendlyName
|
| - ].join(' ');
|
| - values.addValue(new tr.v.NumericValue(
|
| - ['memory', browserName, processName, valueName].join(':'),
|
| - buildMemoryNumeric(timeToSum, valueSpec.unit),
|
| - { description: description }));
|
| - });
|
| - });
|
| + function reportComponentDataAsValues(
|
| + browserName, sourceName, propertyName, processName, componentPath,
|
| + componentNode, unit, descriptionPrefixBuilder, values) {
|
| + // Construct the name of the memory value.
|
| + var nameParts = ['memory', browserName, processName, sourceName].concat(
|
| + componentPath);
|
| + if (propertyName !== undefined)
|
| + nameParts.push(propertyName);
|
| + var name = nameParts.join(':');
|
| +
|
| + // Build the underlying numeric for the memory value.
|
| + var numeric = buildMemoryNumericFromNode(componentNode, unit);
|
| +
|
| + // Build the options for the memory value.
|
| + var description = [
|
| + descriptionPrefixBuilder(componentPath, processName),
|
| + 'in',
|
| + convertBrowserNameToUserFriendlyName(browserName)
|
| + ].join(' ');
|
| + var options = { description: description };
|
| +
|
| + // Report the memory value.
|
| + values.addValue(new tr.v.NumericValue(name, numeric, options));
|
| +
|
| + // Recursively report memory values for sub-components.
|
| + var depth = componentPath.length;
|
| + componentPath.push(undefined);
|
| + componentNode.children[1].forEach(function(childNode, childName) {
|
| + componentPath[depth] = childName;
|
| + reportComponentDataAsValues(
|
| + browserName, sourceName, propertyName, processName, componentPath,
|
| + childNode, unit, descriptionPrefixBuilder, values);
|
| + });
|
| + componentPath.pop();
|
| }
|
|
|
| /**
|
| - * Create a memory tr.v.Numeric (histogram) for |unit| and add all |sums| to
|
| - * it.
|
| - *
|
| - * Undefined items in |sums| are treated as zeros.
|
| + * Create a memory tr.v.Numeric (histogram) with |unit| and add all total
|
| + * values in |node| to it.
|
| */
|
| - function buildMemoryNumeric(sums, unit) {
|
| + function buildMemoryNumericFromNode(node, unit) {
|
| var numeric = MEMORY_NUMERIC_BUILDER_MAP.get(unit).build();
|
| - for (var i = 0; i < sums.length; i++)
|
| - numeric.add(sums[i] || 0);
|
| + node.values.forEach(v => numeric.add(v.total));
|
| return numeric;
|
| }
|
|
|
|
|