diff options
author | rmcilroy@chromium.org <rmcilroy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-30 17:33:40 +0000 |
---|---|---|
committer | rmcilroy@chromium.org <rmcilroy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-30 17:33:40 +0000 |
commit | 4b2ef583d4185db262d5dcc90cd45f3c3ea3e5a0 (patch) | |
tree | 040905198c483f5c20da7cdf3ade92da6bf10a91 | |
parent | e42a741b90919f7b61738cf287976583e7bd42ee (diff) | |
download | chromium_src-4b2ef583d4185db262d5dcc90cd45f3c3ea3e5a0.zip chromium_src-4b2ef583d4185db262d5dcc90cd45f3c3ea3e5a0.tar.gz chromium_src-4b2ef583d4185db262d5dcc90cd45f3c3ea3e5a0.tar.bz2 |
[Telemetry] Add support for capturing V8 object stats to Telemetry.
BUG=
Review URL: https://chromiumcodereview.appspot.com/23112028
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@220606 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/renderer/benchmarking_extension.cc | 37 | ||||
-rw-r--r-- | tools/perf/measurements/page_cycler.py | 20 | ||||
-rw-r--r-- | tools/perf/metrics/v8_object_stats.py | 192 |
3 files changed, 244 insertions, 5 deletions
diff --git a/chrome/renderer/benchmarking_extension.cc b/chrome/renderer/benchmarking_extension.cc index b04a306..a5094ad 100644 --- a/chrome/renderer/benchmarking_extension.cc +++ b/chrome/renderer/benchmarking_extension.cc @@ -29,6 +29,10 @@ class BenchmarkingWrapper : public v8::Extension { " native function GetCounter();" " return GetCounter(name);" "};" + "chrome.benchmarking.counterForRenderer = function(name) {" + " native function GetCounterForRenderer();" + " return GetCounterForRenderer(name);" + "};" "chrome.benchmarking.isSingleProcess = function() {" " native function IsSingleProcess();" " return IsSingleProcess();" @@ -59,6 +63,8 @@ class BenchmarkingWrapper : public v8::Extension { v8::Handle<v8::String> name) OVERRIDE { if (name->Equals(v8::String::New("GetCounter"))) { return v8::FunctionTemplate::New(GetCounter); + } else if (name->Equals(v8::String::New("GetCounterForRenderer"))) { + return v8::FunctionTemplate::New(GetCounterForRenderer); } else if (name->Equals(v8::String::New("IsSingleProcess"))) { return v8::FunctionTemplate::New(IsSingleProcess); } else if (name->Equals(v8::String::New("HiResTime"))) { @@ -68,20 +74,41 @@ class BenchmarkingWrapper : public v8::Extension { return v8::Handle<v8::FunctionTemplate>(); } + /* + * Extract the counter name from arguments. + */ + static void ExtractCounterName( + const v8::FunctionCallbackInfo<v8::Value>& args, + char* name, + size_t capacity) { + name[0] = 'c'; + name[1] = ':'; + args[0]->ToString()->WriteUtf8(&name[2], capacity - 3); + } + static void GetCounter(const v8::FunctionCallbackInfo<v8::Value>& args) { if (!args.Length() || !args[0]->IsString() || !base::StatsTable::current()) return; - // Extract the name argument char name[256]; - name[0] = 'c'; - name[1] = ':'; - args[0]->ToString()->WriteUtf8(&name[2], sizeof(name) - 3); - + ExtractCounterName(args, name, sizeof(name)); int counter = base::StatsTable::current()->GetCounterValue(name); args.GetReturnValue().Set(static_cast<int32_t>(counter)); } + static void GetCounterForRenderer( + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (!args.Length() || !args[0]->IsString() || !base::StatsTable::current()) + return; + + char name[256]; + ExtractCounterName(args, name, sizeof(name)); + int counter = base::StatsTable::current()->GetCounterValue( + name, + base::GetCurrentProcId()); + args.GetReturnValue().Set(static_cast<int32_t>(counter)); + } + static void IsSingleProcess(const v8::FunctionCallbackInfo<v8::Value>& args) { args.GetReturnValue().Set( CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)); diff --git a/tools/perf/measurements/page_cycler.py b/tools/perf/measurements/page_cycler.py index 9e18706..2e4e39c 100644 --- a/tools/perf/measurements/page_cycler.py +++ b/tools/perf/measurements/page_cycler.py @@ -21,6 +21,7 @@ import sys from metrics import io from metrics import memory +from metrics import v8_object_stats from telemetry.core import util from telemetry.page import page_measurement @@ -32,7 +33,10 @@ class PageCycler(page_measurement.PageMeasurement): 'page_cycler.js'), 'r') as f: self._page_cycler_js = f.read() + self._record_v8_object_stats = False + self._memory_metric = None + self._v8_object_stats_metric = None self._number_warm_runs = None self._cold_runs_requested = False self._has_loaded_page = collections.defaultdict(int) @@ -46,12 +50,19 @@ class PageCycler(page_measurement.PageMeasurement): parser.remove_option('--pageset-repeat') parser.add_option(pageset_repeat_option) + parser.add_option('--v8-object-stats', + action='store_true', + help='Enable detailed V8 object statistics.') + parser.add_option('--cold-load-percent', type='int', default=0, help='%d of page visits for which a cold load is forced') + def DidStartBrowser(self, browser): """Initialize metrics once right after the browser has been launched.""" self._memory_metric = memory.MemoryMetric(browser) + if self._record_v8_object_stats: + self._v8_object_stats_metric = v8_object_stats.V8ObjectStatsMetric() def DidStartHTTPServer(self, tab): # Avoid paying for a cross-renderer navigation on the first page on legacy @@ -65,12 +76,18 @@ class PageCycler(page_measurement.PageMeasurement): def DidNavigateToPage(self, page, tab): self._memory_metric.Start(page, tab) + if self._record_v8_object_stats: + self._v8_object_stats_metric.Start(page, tab) def CustomizeBrowserOptions(self, options): memory.MemoryMetric.CustomizeBrowserOptions(options) io.IOMetric.CustomizeBrowserOptions(options) options.AppendExtraBrowserArg('--js-flags=--expose_gc') + if options.v8_object_stats: + self._record_v8_object_stats = True + v8_object_stats.V8ObjectStatsMetric.CustomizeBrowserOptions(options) + # A disk cache bug causes some page cyclers to hang on mac. # TODO(tonyg): Re-enable these tests when crbug.com/268646 is fixed. if (sys.platform == 'darwin' and @@ -121,6 +138,9 @@ class PageCycler(page_measurement.PageMeasurement): self._memory_metric.Stop(page, tab) self._memory_metric.AddResults(tab, results) + if self._record_v8_object_stats: + self._v8_object_stats_metric.Stop(page, tab) + self._v8_object_stats_metric.AddResults(tab, results) def DidRunTest(self, tab, results): self._memory_metric.AddSummaryResults(results) diff --git a/tools/perf/metrics/v8_object_stats.py b/tools/perf/metrics/v8_object_stats.py new file mode 100644 index 0000000..79b0fad --- /dev/null +++ b/tools/perf/metrics/v8_object_stats.py @@ -0,0 +1,192 @@ +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import json +import logging + +from metrics import Metric + +_COUNTER_NAMES = [ + 'V8.OsMemoryAllocated', + 'V8.MemoryNewSpaceBytesAvailable', + 'V8.MemoryNewSpaceBytesCommitted', + 'V8.MemoryNewSpaceBytesUsed', + 'V8.MemoryOldPointerSpaceBytesAvailable', + 'V8.MemoryOldPointerSpaceBytesCommitted', + 'V8.MemoryOldPointerSpaceBytesUsed', + 'V8.MemoryOldDataSpaceBytesAvailable', + 'V8.MemoryOldDataSpaceBytesCommitted', + 'V8.MemoryOldDataSpaceBytesUsed', + 'V8.MemoryCodeSpaceBytesAvailable', + 'V8.MemoryCodeSpaceBytesCommitted', + 'V8.MemoryCodeSpaceBytesUsed', + 'V8.MemoryMapSpaceBytesAvailable', + 'V8.MemoryMapSpaceBytesCommitted', + 'V8.MemoryMapSpaceBytesUsed', + 'V8.MemoryCellSpaceBytesAvailable', + 'V8.MemoryCellSpaceBytesCommitted', + 'V8.MemoryCellSpaceBytesUsed', + 'V8.MemoryPropertyCellSpaceBytesAvailable', + 'V8.MemoryPropertyCellSpaceBytesCommitted', + 'V8.MemoryPropertyCellSpaceBytesUsed', + 'V8.MemoryLoSpaceBytesAvailable', + 'V8.MemoryLoSpaceBytesCommitted', + 'V8.MemoryLoSpaceBytesUsed)', + 'V8.SizeOf_ACCESSOR_PAIR_TYPE', + 'V8.SizeOf_ACCESS_CHECK_INFO_TYPE', + 'V8.SizeOf_ALIASED_ARGUMENTS_ENTRY_TYPE', + 'V8.SizeOf_ALLOCATION_MEMENTO_TYPE', + 'V8.SizeOf_ALLOCATION_SITE_TYPE', + 'V8.SizeOf_ASCII_INTERNALIZED_STRING_TYPE', + 'V8.SizeOf_ASCII_STRING_TYPE', + 'V8.SizeOf_BOX_TYPE', + 'V8.SizeOf_BREAK_POINT_INFO_TYPE', + 'V8.SizeOf_BYTE_ARRAY_TYPE', + 'V8.SizeOf_CALL_HANDLER_INFO_TYPE', + 'V8.SizeOf_CELL_TYPE', + 'V8.SizeOf_CODE_CACHE_TYPE', + 'V8.SizeOf_CODE_TYPE', + 'V8.SizeOf_CODE_TYPE-BINARY_OP_IC', + 'V8.SizeOf_CODE_TYPE-BUILTIN', + 'V8.SizeOf_CODE_TYPE-CALL_IC', + 'V8.SizeOf_CODE_TYPE-COMPARE_IC', + 'V8.SizeOf_CODE_TYPE-COMPARE_NIL_IC', + 'V8.SizeOf_CODE_TYPE-FUNCTION', + 'V8.SizeOf_CODE_TYPE-KEYED_CALL_IC', + 'V8.SizeOf_CODE_TYPE-KEYED_LOAD_IC', + 'V8.SizeOf_CODE_TYPE-KEYED_STORE_IC', + 'V8.SizeOf_CODE_TYPE-LOAD_IC', + 'V8.SizeOf_CODE_TYPE-OPTIMIZED_FUNCTION', + 'V8.SizeOf_CODE_TYPE-REGEXP', + 'V8.SizeOf_CODE_TYPE-STORE_IC', + 'V8.SizeOf_CODE_TYPE-STUB', + 'V8.SizeOf_CODE_TYPE-TO_BOOLEAN_IC', + 'V8.SizeOf_CONS_ASCII_INTERNALIZED_STRING_TYPE', + 'V8.SizeOf_CONS_ASCII_STRING_TYPE', + 'V8.SizeOf_CONS_INTERNALIZED_STRING_TYPE', + 'V8.SizeOf_CONS_STRING_TYPE', + 'V8.SizeOf_DEBUG_INFO_TYPE', + 'V8.SizeOf_DECLARED_ACCESSOR_DESCRIPTOR_TYPE', + 'V8.SizeOf_DECLARED_ACCESSOR_INFO_TYPE', + 'V8.SizeOf_EXECUTABLE_ACCESSOR_INFO_TYPE', + 'V8.SizeOf_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE', + 'V8.SizeOf_EXTERNAL_ASCII_STRING_TYPE', + 'V8.SizeOf_EXTERNAL_BYTE_ARRAY_TYPE', + 'V8.SizeOf_EXTERNAL_DOUBLE_ARRAY_TYPE', + 'V8.SizeOf_EXTERNAL_FLOAT_ARRAY_TYPE', + 'V8.SizeOf_EXTERNAL_INTERNALIZED_STRING_TYPE', + 'V8.SizeOf_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE', + 'V8.SizeOf_EXTERNAL_INT_ARRAY_TYPE', + 'V8.SizeOf_EXTERNAL_PIXEL_ARRAY_TYPE', + 'V8.SizeOf_EXTERNAL_SHORT_ARRAY_TYPE', + 'V8.SizeOf_EXTERNAL_STRING_TYPE', + 'V8.SizeOf_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE', + 'V8.SizeOf_EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE', + 'V8.SizeOf_EXTERNAL_UNSIGNED_INT_ARRAY_TYPE', + 'V8.SizeOf_EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE', + 'V8.SizeOf_FILLER_TYPE', + 'V8.SizeOf_FIXED_ARRAY-DESCRIPTOR_ARRAY_SUB_TYPE', + 'V8.SizeOf_FIXED_ARRAY-DICTIONARY_ELEMENTS_SUB_TYPE', + 'V8.SizeOf_FIXED_ARRAY-DICTIONARY_PROPERTIES_SUB_TYPE', + 'V8.SizeOf_FIXED_ARRAY-FAST_ELEMENTS_SUB_TYPE', + 'V8.SizeOf_FIXED_ARRAY-FAST_PROPERTIES_SUB_TYPE', + 'V8.SizeOf_FIXED_ARRAY-MAP_CODE_CACHE_SUB_TYPE', + 'V8.SizeOf_FIXED_ARRAY-SCOPE_INFO_SUB_TYPE', + 'V8.SizeOf_FIXED_ARRAY-STRING_TABLE_SUB_TYPE', + 'V8.SizeOf_FIXED_ARRAY-TRANSITION_ARRAY_SUB_TYPE', + 'V8.SizeOf_FIXED_ARRAY_TYPE', + 'V8.SizeOf_FIXED_DOUBLE_ARRAY_TYPE', + 'V8.SizeOf_FOREIGN_TYPE', + 'V8.SizeOf_FREE_SPACE_TYPE', + 'V8.SizeOf_FUNCTION_TEMPLATE_INFO_TYPE', + 'V8.SizeOf_HEAP_NUMBER_TYPE', + 'V8.SizeOf_INTERCEPTOR_INFO_TYPE', + 'V8.SizeOf_INTERNALIZED_STRING_TYPE', + 'V8.SizeOf_JS_ARRAY_BUFFER_TYPE', + 'V8.SizeOf_JS_ARRAY_TYPE', + 'V8.SizeOf_JS_BUILTINS_OBJECT_TYPE', + 'V8.SizeOf_JS_CONTEXT_EXTENSION_OBJECT_TYPE', + 'V8.SizeOf_JS_DATA_VIEW_TYPE', + 'V8.SizeOf_JS_DATE_TYPE', + 'V8.SizeOf_JS_FUNCTION_PROXY_TYPE', + 'V8.SizeOf_JS_FUNCTION_TYPE', + 'V8.SizeOf_JS_GENERATOR_OBJECT_TYPE', + 'V8.SizeOf_JS_GLOBAL_OBJECT_TYPE', + 'V8.SizeOf_JS_GLOBAL_PROXY_TYPE', + 'V8.SizeOf_JS_MAP_TYPE', + 'V8.SizeOf_JS_MESSAGE_OBJECT_TYPE', + 'V8.SizeOf_JS_MODULE_TYPE', + 'V8.SizeOf_JS_OBJECT_TYPE', + 'V8.SizeOf_JS_PROXY_TYPE', + 'V8.SizeOf_JS_REGEXP_TYPE', + 'V8.SizeOf_JS_SET_TYPE', + 'V8.SizeOf_JS_TYPED_ARRAY_TYPE', + 'V8.SizeOf_JS_VALUE_TYPE', + 'V8.SizeOf_JS_WEAK_MAP_TYPE', + 'V8.SizeOf_JS_WEAK_SET_TYPE', + 'V8.SizeOf_MAP_TYPE', + 'V8.SizeOf_OBJECT_TEMPLATE_INFO_TYPE', + 'V8.SizeOf_ODDBALL_TYPE', + 'V8.SizeOf_POLYMORPHIC_CODE_CACHE_TYPE', + 'V8.SizeOf_PROPERTY_CELL_TYPE', + 'V8.SizeOf_SCRIPT_TYPE', + 'V8.SizeOf_SHARED_FUNCTION_INFO_TYPE', + 'V8.SizeOf_SHORT_EXTERNAL_ASCII_INTERNALIZED_STRING_TYPE', + 'V8.SizeOf_SHORT_EXTERNAL_ASCII_STRING_TYPE', + 'V8.SizeOf_SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE', + 'V8.SizeOf_SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE', + 'V8.SizeOf_SHORT_EXTERNAL_STRING_TYPE', + 'V8.SizeOf_SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE', + 'V8.SizeOf_SIGNATURE_INFO_TYPE', + 'V8.SizeOf_SLICED_ASCII_STRING_TYPE', + 'V8.SizeOf_SLICED_STRING_TYPE', + 'V8.SizeOf_STRING_TYPE', + 'V8.SizeOf_SYMBOL_TYPE', + 'V8.SizeOf_TYPE_FEEDBACK_INFO_TYPE', + 'V8.SizeOf_TYPE_SWITCH_INFO_TYPE' + ] + +class V8ObjectStatsMetric(Metric): + """V8ObjectStatsMetric gathers statistics on the size of types in the V8 heap. + + It does this by enabling the --track_gc_object_stats flag on V8 and reading + these statistics from the StatsTableMetric. + """ + + def __init__(self): + super(V8ObjectStatsMetric, self).__init__() + self._results = None + + @classmethod + def CustomizeBrowserOptions(cls, options): + options.AppendExtraBrowserArg('--enable-stats-table') + options.AppendExtraBrowserArg('--enable-benchmarking') + options.AppendExtraBrowserArg( + '--js-flags=--track_gc_object_stats --expose_gc') + + def Start(self, page, tab): + """Do Nothing.""" + pass + + def Stop(self, page, tab): + """Get the values in the stats table after the page is loaded.""" + self._results = tab.EvaluateJavaScript(""" + (function(counters) { + var results = {}; + if (!window.chrome || !window.chrome.benchmarking) + return results; + window.gc(); // Trigger GC to ensure stats are checkpointed. + for (var i = 0; i < counters.length; i++) + results[counters[i]] = chrome.benchmarking.counterForRenderer(counters[i]); + return results; + })(%s); + """ % json.dumps(_COUNTER_NAMES)) + if not self._results: + logging.warning('No V8 object stats from website: ' + page.display_url) + + def AddResults(self, tab, results): + """Add results for this page to the results object.""" + assert self._results != None, 'Must call Stop() first' + for counter_name in self._results: + results.Add(counter_name, 'kb', self._results[counter_name] / 1024.0) |