[Storage] Blob Storage perf tests
BUG=489799 CQ_EXTRA_TRYBOTS=tryserver.chromium.perf:linux_perf_bisect;tryserver.chromium.perf:mac_perf_bisect;tryserver.chromium.perf:win_perf_bisect;tryserver.chromium.perf:android_nexus5_perf_bisect Review URL: https://codereview.chromium.org/1104053006 Cr-Commit-Position: refs/heads/master@{#332541}
This commit is contained in:
storage/browser/blob
tools
perf
telemetry
telemetry
@ -159,7 +159,7 @@ void BlobURLRequestJob::SetExtraRequestHeaders(
|
||||
|
||||
BlobURLRequestJob::~BlobURLRequestJob() {
|
||||
STLDeleteValues(&index_to_reader_);
|
||||
TRACE_EVENT_ASYNC_END1("Blob", "Request", this, "uuid",
|
||||
TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest", this, "uuid",
|
||||
blob_data_ ? blob_data_->uuid() : "NotFound");
|
||||
}
|
||||
|
||||
|
42
tools/perf/benchmarks/blob_storage.py
Normal file
42
tools/perf/benchmarks/blob_storage.py
Normal file
@ -0,0 +1,42 @@
|
||||
# Copyright 2015 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.
|
||||
# Copyright 2015 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.
|
||||
|
||||
from core import perf_benchmark
|
||||
|
||||
from telemetry.core.platform import tracing_category_filter
|
||||
from telemetry.web_perf import timeline_based_measurement
|
||||
|
||||
import page_sets
|
||||
|
||||
|
||||
BLOB_CATEGORY = 'Blob'
|
||||
TIMELINE_REQUIRED_CATEGORY = 'blink.console'
|
||||
|
||||
|
||||
class BlobStorage(perf_benchmark.PerfBenchmark):
|
||||
"""Timeline based measurement benchmark for Blob Storage."""
|
||||
|
||||
page_set = page_sets.BlobWorkshopPageSet
|
||||
|
||||
def CreateTimelineBasedMeasurementOptions(self):
|
||||
cat_filter = tracing_category_filter.CreateMinimalOverheadFilter()
|
||||
cat_filter.AddIncludedCategory(BLOB_CATEGORY)
|
||||
cat_filter.AddIncludedCategory(TIMELINE_REQUIRED_CATEGORY)
|
||||
|
||||
return timeline_based_measurement.Options(
|
||||
overhead_level=cat_filter)
|
||||
|
||||
@classmethod
|
||||
def Name(cls):
|
||||
return 'blob_storage.blob_storage'
|
||||
|
||||
@classmethod
|
||||
def ValueCanBeAddedPredicate(cls, value, is_first_result):
|
||||
if ('blob-writes' not in value.name and
|
||||
'blob-reads' not in value.name):
|
||||
return False
|
||||
return value.values != None
|
169
tools/perf/page_sets/blob/blob-workshop.html
Normal file
169
tools/perf/page_sets/blob/blob-workshop.html
Normal file
@ -0,0 +1,169 @@
|
||||
<script>
|
||||
var blobs = [];
|
||||
var bytes = 0;
|
||||
var timeStart;
|
||||
var timeEnd;
|
||||
var doneReading = false;
|
||||
var errors = [];
|
||||
var disableUI = false;
|
||||
|
||||
function recordError(error) {
|
||||
console.log(error);
|
||||
errors.push(error);
|
||||
}
|
||||
|
||||
function updateStats() {
|
||||
if (disableUI) return;
|
||||
var num_blobs = document.getElementById('num_blobs');
|
||||
var total_bytes = document.getElementById('total_bytes');
|
||||
var time = document.getElementById('time');
|
||||
num_blobs.innerHTML = '' + blobs.length;
|
||||
total_bytes.innerHTML = '' + bytes;
|
||||
time.innerHTML = '' + (timeEnd - timeStart);
|
||||
}
|
||||
|
||||
function createAndRead(size) {
|
||||
doneReading = false;
|
||||
errors = [];
|
||||
var reader = new FileReader();
|
||||
var currentBlob = 0;
|
||||
var totalSize = 0;
|
||||
var error = document.getElementById('error');
|
||||
var numRead = 0;
|
||||
|
||||
var blob = new Blob([new Uint8Array(size)], {type: 'application/octet-string'});
|
||||
|
||||
reader.onloadend = function(e) {
|
||||
if (reader.error) {
|
||||
recordError('Error when reading blob: ' + reader.error);
|
||||
doneReading = true;
|
||||
return;
|
||||
}
|
||||
if (reader.result.byteLength != size) {
|
||||
recordError("Sizes don't match");
|
||||
}
|
||||
doneReading = true;
|
||||
}
|
||||
reader.readAsArrayBuffer(blob);
|
||||
}
|
||||
|
||||
function createBlob(size) {
|
||||
timeStart = performance.now();
|
||||
var blob = new Blob([new Uint8Array(size)], {type: 'application/octet-string'});
|
||||
timeEnd = performance.now();
|
||||
blobs.push(blob);
|
||||
bytes += size;
|
||||
updateStats();
|
||||
}
|
||||
|
||||
function garbageCollect() {
|
||||
blobs = [];
|
||||
bytes = 0;
|
||||
updateStats();
|
||||
}
|
||||
|
||||
function addCustom() {
|
||||
var custom_input = document.getElementById('custom_input');
|
||||
var custom_bytes = custom_input.value;
|
||||
createBlob(custom_bytes * 1);
|
||||
}
|
||||
|
||||
function readBlobsSerially() {
|
||||
doneReading = false;
|
||||
errors = [];
|
||||
if (blobs.length == 0) {
|
||||
return;
|
||||
}
|
||||
timeStart = performance.now();
|
||||
var reader = new FileReader();
|
||||
var currentBlob = 0;
|
||||
var totalSize = 0;
|
||||
var error = document.getElementById('error');
|
||||
var numRead = 0;
|
||||
reader.onloadend = function(e) {
|
||||
if (reader.error) {
|
||||
if (!disableUI)
|
||||
error.innerHTML += '<br/>Reader error:<br/>' + reader.error.message;
|
||||
recordError('Error when reading blob ' + currentBlob + ': ' + reader.error);
|
||||
doneReading = true;
|
||||
return;
|
||||
}
|
||||
totalSize += reader.result.byteLength;
|
||||
currentBlob++;
|
||||
if (currentBlob < blobs.length) {
|
||||
reader.readAsArrayBuffer(blobs[currentBlob]);
|
||||
} else {
|
||||
timeEnd = performance.now();
|
||||
// we're done reading
|
||||
if (totalSize != bytes) {
|
||||
recordError("Sizes don't match");
|
||||
if (!disableUI)
|
||||
error.innerHTML += '<br/>Sizes don\'t match: ' + totalSize + ' vs ' + bytes;
|
||||
}
|
||||
doneReading = true;
|
||||
updateStats();
|
||||
}
|
||||
}
|
||||
reader.readAsArrayBuffer(blobs[currentBlob]);
|
||||
}
|
||||
function readBlobsInParallel() {
|
||||
doneReading = false;
|
||||
errors = [];
|
||||
if (blobs.length == 0) {
|
||||
return;
|
||||
}
|
||||
timeStart = performance.now();
|
||||
var currentBlob = 0;
|
||||
var totalSize = 0;
|
||||
var error = document.getElementById('error');
|
||||
var numRead = 0;
|
||||
for (; currentBlob < blobs.length; currentBlob++) {
|
||||
var genReader = function(index) {
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function(e) {
|
||||
if (reader.error) {
|
||||
if (!disableUI)
|
||||
error.innerHTML += '<br/>Reader error:<br/>' + reader.error.message;
|
||||
recordError('Error when reading blob ' + index + ': ' + reader.error);
|
||||
doneReading = true;
|
||||
return;
|
||||
}
|
||||
totalSize += reader.result.byteLength;
|
||||
numRead++;
|
||||
if (numRead >= blobs.length) {
|
||||
timeEnd = performance.now();
|
||||
// we're done reading
|
||||
if (totalSize != bytes) {
|
||||
recordError("Sizes don't match");
|
||||
if (!disableUI)
|
||||
error.innerHTML += '<br/>Sizes don\'t match: ' + totalSize + ' vs ' + bytes;
|
||||
}
|
||||
doneReading = true;
|
||||
updateStats();
|
||||
}
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
genReader(currentBlob).readAsArrayBuffer(blobs[currentBlob]);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<div>Number of blobs: <span id="num_blobs">0</span>, total memory size: <span id="total_bytes">0</span> bytes.</div>
|
||||
<input type="button" id="custom_input_submit" value="Add Blob with Size" onclick="addCustom();"/>
|
||||
<input type="text" inputmode="numeric" id="custom_input" value=""/><br/>
|
||||
|
||||
Shorcut buttons for person:
|
||||
<input type="button" value="2 bytes" onclick="createBlob(2);" />
|
||||
<input type="button" value="1 kb" onclick="createBlob(1024);" />
|
||||
<input type="button" value="16 kb" onclick="createBlob(16*1024);" />
|
||||
<input type="button" value="1 mb" onclick="createBlob(1024 * 1024);" />
|
||||
<input type="button" value="40 mb" onclick="createBlob(40 * 1024 * 1024);" />
|
||||
<input type="button" value="400 mb" onclick="createBlob(400 * 1024 * 1024);" />
|
||||
|
||||
<input type="button" id="read_blobs_serial" value="Read Blobs Serially" onclick="readBlobsSerially();" />
|
||||
<input type="button" id="read_blobs_parallel" value="Read Blobs Parallel" onclick="readBlobsInParallel();" /><br/>
|
||||
<input type="button" id="garbage_collect" value="Garbage Collect Blobs" onclick="garbageCollect();" /><br/>
|
||||
Operation Time:
|
||||
<div id="time"></div>
|
||||
Errors:
|
||||
<div id="error"></div>
|
94
tools/perf/page_sets/blob_workshop.py
Normal file
94
tools/perf/page_sets/blob_workshop.py
Normal file
@ -0,0 +1,94 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
from telemetry.page import page as page_module
|
||||
from telemetry.page import page_test as page_test
|
||||
from telemetry.page import page_set as page_set_module
|
||||
|
||||
|
||||
NUM_BLOB_MASS_CREATE_READS = 15
|
||||
|
||||
|
||||
class BlobCreateThenRead(page_module.Page):
|
||||
|
||||
def __init__(self, write_method, blob_sizes, page_set):
|
||||
super(BlobCreateThenRead, self).__init__(
|
||||
url='file://blob/blob-workshop.html',
|
||||
page_set=page_set,
|
||||
name='blob-create-read-' + write_method)
|
||||
self._blob_sizes = blob_sizes
|
||||
|
||||
def RunPageInteractions(self, action_runner):
|
||||
action_runner.ExecuteJavaScript('disableUI = true;')
|
||||
|
||||
for size_bytes in self._blob_sizes:
|
||||
with action_runner.CreateInteraction('Action_CreateAndReadBlob',
|
||||
repeatable=True):
|
||||
action_runner.ExecuteJavaScript(
|
||||
'createAndRead(' + str(size_bytes) + ');')
|
||||
action_runner.WaitForJavaScriptCondition(
|
||||
'doneReading === true || errors', 60)
|
||||
|
||||
errors = action_runner.EvaluateJavaScript('errors')
|
||||
if errors:
|
||||
raise page_test.Failure('Errors on page: ' + ', '.join(self.errors))
|
||||
|
||||
|
||||
class BlobMassCreate(page_module.Page):
|
||||
def __init__(self, write_method, blob_sizes, page_set):
|
||||
super(BlobMassCreate, self).__init__(
|
||||
url='file://blob/blob-workshop.html',
|
||||
page_set=page_set,
|
||||
name='blob-mass-create-' + write_method)
|
||||
self._blob_sizes = blob_sizes
|
||||
|
||||
def RunPageInteractions(self, action_runner):
|
||||
action_runner.ExecuteJavaScript('disableUI = true;')
|
||||
|
||||
# Add blobs
|
||||
for size_bytes in self._blob_sizes:
|
||||
with action_runner.CreateInteraction('Action_CreateBlob',
|
||||
repeatable=True):
|
||||
action_runner.ExecuteJavaScript('createBlob(' + str(size_bytes) + ');')
|
||||
|
||||
# Read blobs
|
||||
for _ in range(0, NUM_BLOB_MASS_CREATE_READS):
|
||||
with action_runner.CreateInteraction('Action_ReadBlobs',
|
||||
repeatable=True):
|
||||
action_runner.ExecuteJavaScript('readBlobsSerially();')
|
||||
action_runner.WaitForJavaScriptCondition(
|
||||
'doneReading === true || errors', 60)
|
||||
|
||||
errors = action_runner.EvaluateJavaScript('errors')
|
||||
if errors:
|
||||
raise page_test.Failure('Errors on page: ' + ', '.join(self.errors))
|
||||
|
||||
|
||||
class BlobWorkshopPageSet(page_set_module.PageSet):
|
||||
"""The BlobWorkshop page set."""
|
||||
|
||||
def __init__(self):
|
||||
super(BlobWorkshopPageSet, self).__init__()
|
||||
self.AddUserStory(
|
||||
BlobMassCreate('2Bx200', [2] * 200, self))
|
||||
self.AddUserStory(
|
||||
BlobMassCreate('1KBx200', [1024] * 200, self))
|
||||
self.AddUserStory(
|
||||
BlobMassCreate('150KBx200', [150 * 1024] * 200, self))
|
||||
self.AddUserStory(
|
||||
BlobMassCreate('1MBx200', [1024 * 1024] * 200, self))
|
||||
self.AddUserStory(
|
||||
BlobMassCreate('10MBx30', [10 * 1024 * 1024] * 30, self))
|
||||
self.AddUserStory(
|
||||
BlobMassCreate('100MBx5', [100 * 1024 * 1024] * 5, self))
|
||||
|
||||
self.AddUserStory(BlobCreateThenRead('2Bx200', [2] * 200, self))
|
||||
self.AddUserStory(BlobCreateThenRead('1KBx200', [1024] * 200, self))
|
||||
self.AddUserStory(
|
||||
BlobCreateThenRead('150KBx200', [150 * 1024 - 1] * 200, self))
|
||||
self.AddUserStory(BlobCreateThenRead('1MBx200', [1024 * 1024] * 200, self))
|
||||
self.AddUserStory(
|
||||
BlobCreateThenRead('10MBx30', [10 * 1024 * 1024] * 30, self))
|
||||
self.AddUserStory(
|
||||
BlobCreateThenRead('100MBx5', [100 * 1024 * 1024] * 5, self))
|
112
tools/telemetry/telemetry/web_perf/metrics/blob_timeline.py
Normal file
112
tools/telemetry/telemetry/web_perf/metrics/blob_timeline.py
Normal file
@ -0,0 +1,112 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
from telemetry.value import list_of_scalar_values
|
||||
from telemetry.web_perf.metrics import timeline_based_metric
|
||||
|
||||
|
||||
WRITE_EVENT_NAME = 'Registry::RegisterBlob'
|
||||
READ_EVENT_NAME = 'BlobRequest'
|
||||
|
||||
|
||||
class BlobTimelineMetric(timeline_based_metric.TimelineBasedMetric):
|
||||
"""BlobTimelineMetric reports timing information about blob storage.
|
||||
|
||||
The following metrics are added to the results:
|
||||
* blob write times (blob_writes)
|
||||
* blob read times (blob_reads)
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(BlobTimelineMetric, self).__init__()
|
||||
|
||||
@staticmethod
|
||||
def IsWriteEvent(event):
|
||||
return event.name == WRITE_EVENT_NAME
|
||||
|
||||
@staticmethod
|
||||
def IsReadEvent(event):
|
||||
return event.name == READ_EVENT_NAME
|
||||
|
||||
@staticmethod
|
||||
def IsEventInInteraction(event, interaction):
|
||||
return interaction.start <= event.start <= interaction.end
|
||||
|
||||
@staticmethod
|
||||
def ThreadDurationIfPresent(event):
|
||||
if event.thread_duration:
|
||||
return event.thread_duration
|
||||
else:
|
||||
return event.end - event.start
|
||||
|
||||
def AddResults(self, model, renderer_thread, interactions, results):
|
||||
assert interactions
|
||||
|
||||
browser_process = [p for p in model.GetAllProcesses()
|
||||
if p.name == "Browser"][0]
|
||||
|
||||
write_events = []
|
||||
read_events = []
|
||||
for event in renderer_thread.parent.IterAllEvents(
|
||||
event_predicate=self.IsWriteEvent):
|
||||
write_events.append(event)
|
||||
for event in browser_process.parent.IterAllEvents(
|
||||
event_predicate=self.IsReadEvent):
|
||||
read_events.append(event)
|
||||
|
||||
# Only these private methods are tested for mocking simplicity.
|
||||
self._AddWriteResultsInternal(write_events, interactions, results)
|
||||
self._AddReadResultsInternal(read_events, interactions, results)
|
||||
|
||||
def _AddWriteResultsInternal(self, events, interactions, results):
|
||||
writes = []
|
||||
for event in events:
|
||||
if (self.IsWriteEvent(event) and
|
||||
any(self.IsEventInInteraction(event, interaction)
|
||||
for interaction in interactions)):
|
||||
writes.append(self.ThreadDurationIfPresent(event))
|
||||
if writes:
|
||||
results.AddValue(list_of_scalar_values.ListOfScalarValues(
|
||||
page=results.current_page,
|
||||
name='blob-writes',
|
||||
units='ms',
|
||||
values=writes,
|
||||
description='List of durations of blob writes.'))
|
||||
else:
|
||||
results.AddValue(list_of_scalar_values.ListOfScalarValues(
|
||||
page=results.current_page,
|
||||
name='blob-writes',
|
||||
units='ms',
|
||||
values=None,
|
||||
none_value_reason='No blob write events found for this interaction.'))
|
||||
|
||||
|
||||
def _AddReadResultsInternal(self, events, interactions, results):
|
||||
reads = dict()
|
||||
for event in events:
|
||||
if (not self.IsReadEvent(event) or
|
||||
not any(self.IsEventInInteraction(event, interaction)
|
||||
for interaction in interactions)):
|
||||
continue
|
||||
# Every blob has unique UUID. To get the total time for reading
|
||||
# a blob, we add up the time of all events with the same blob UUID.
|
||||
uuid = event.args['uuid']
|
||||
if uuid not in reads:
|
||||
reads[uuid] = 0
|
||||
reads[uuid] += self.ThreadDurationIfPresent(event)
|
||||
|
||||
if reads:
|
||||
results.AddValue(list_of_scalar_values.ListOfScalarValues(
|
||||
page=results.current_page,
|
||||
name='blob-reads',
|
||||
units='ms',
|
||||
values=reads.values(),
|
||||
description='List of read times for blobs.'))
|
||||
else:
|
||||
results.AddValue(list_of_scalar_values.ListOfScalarValues(
|
||||
page=results.current_page,
|
||||
name='blob-reads',
|
||||
units='ms',
|
||||
values=None,
|
||||
none_value_reason='No blob read events found for this interaction.'))
|
@ -0,0 +1,139 @@
|
||||
# Copyright 2015 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 unittest
|
||||
|
||||
from collections import namedtuple
|
||||
from telemetry.page import page
|
||||
from telemetry.results import page_test_results
|
||||
from telemetry.web_perf.metrics import blob_timeline
|
||||
from telemetry.web_perf import timeline_interaction_record
|
||||
|
||||
|
||||
FakeEvent = namedtuple('Event', 'name, start, end, thread_duration, args')
|
||||
Interaction = timeline_interaction_record.TimelineInteractionRecord
|
||||
TEST_INTERACTION_LABEL = 'Action_TestInteraction'
|
||||
WRITE_EVENT_NAME = 'Registry::RegisterBlob'
|
||||
READ_EVENT_NAME = 'BlobRequest'
|
||||
|
||||
|
||||
def GetBlobMetrics(events, interactions):
|
||||
results = page_test_results.PageTestResults()
|
||||
test_page = page.Page('file://blank.html')
|
||||
results.WillRunPage(test_page)
|
||||
blob_timeline.BlobTimelineMetric()._AddWriteResultsInternal(
|
||||
events, interactions, results) # pylint:disable=protected-access
|
||||
blob_timeline.BlobTimelineMetric()._AddReadResultsInternal(
|
||||
events, interactions, results) # pylint:disable=protected-access
|
||||
return_dict = dict((value.name, value.values) for value in
|
||||
results.current_page_run.values)
|
||||
results.DidRunPage(test_page)
|
||||
return return_dict
|
||||
|
||||
def FakeWriteEvent(start, end, thread_duration=None):
|
||||
if not thread_duration:
|
||||
thread_duration = end - start
|
||||
return FakeEvent(blob_timeline.WRITE_EVENT_NAME,
|
||||
start, end, thread_duration, {'uuid':'fakeuuid'})
|
||||
|
||||
def FakeReadEvent(start, end, uuid, thread_duration=None):
|
||||
if not thread_duration:
|
||||
thread_duration = end - start
|
||||
return FakeEvent(blob_timeline.READ_EVENT_NAME,
|
||||
start, end, thread_duration, {'uuid': uuid})
|
||||
|
||||
def TestInteraction(start, end):
|
||||
return Interaction(TEST_INTERACTION_LABEL, start, end)
|
||||
|
||||
|
||||
class BlobTimelineMetricUnitTest(unittest.TestCase):
|
||||
def testWriteMetric(self):
|
||||
events = [FakeWriteEvent(0, 1),
|
||||
FakeWriteEvent(9, 11),
|
||||
FakeWriteEvent(10, 13),
|
||||
FakeWriteEvent(20, 24),
|
||||
FakeWriteEvent(21, 26),
|
||||
FakeWriteEvent(29, 35),
|
||||
FakeWriteEvent(30, 37),
|
||||
FakeWriteEvent(40, 48),
|
||||
FakeWriteEvent(41, 50),
|
||||
FakeEvent('something', 10, 13, 3, {}),
|
||||
FakeEvent('FrameView::something', 20, 24, 4, {}),
|
||||
FakeEvent('SomeThing::performLayout', 30, 37, 7, {}),
|
||||
FakeEvent('something else', 40, 48, 8, {})]
|
||||
interactions = [TestInteraction(10, 20),
|
||||
TestInteraction(30, 40)]
|
||||
|
||||
self.assertEqual({'blob-reads': None, 'blob-writes': None},
|
||||
GetBlobMetrics(events, []))
|
||||
self.assertEqual({'blob-reads': None, 'blob-writes': None},
|
||||
GetBlobMetrics([], interactions))
|
||||
|
||||
# The first event starts before the first interaction, so it is ignored.
|
||||
# The second event starts before the first interaction, so it is ignored.
|
||||
# The third event starts during the first interaction, and its duration is
|
||||
# 13 - 10 = 3.
|
||||
# The fourth event starts during the first interaction, and its duration is
|
||||
# 24 - 20 = 4.
|
||||
# The fifth event starts between the two interactions, so it is ignored.
|
||||
# The sixth event starts between the two interactions, so it is ignored.
|
||||
# The seventh event starts during the second interaction, and its duration
|
||||
# is 37 - 30 = 7.
|
||||
# The eighth event starts during the second interaction and its duration is
|
||||
# 48 - 40 = 8.
|
||||
# The ninth event starts after the last interaction, so it is ignored.
|
||||
# The rest of the events are not layout events, so they are ignored.
|
||||
self.assertEqual({'blob-reads': None, 'blob-writes': [3, 4, 7, 8]},
|
||||
GetBlobMetrics(events, interactions))
|
||||
|
||||
def testReadMetric(self):
|
||||
events = [FakeReadEvent(0, 1, 'a'),
|
||||
FakeReadEvent(9, 11, 'a'),
|
||||
FakeReadEvent(10, 13, 'b', 1), # counts
|
||||
FakeReadEvent(15, 18, 'b'), # counts
|
||||
FakeReadEvent(21, 26, 'b'),
|
||||
FakeReadEvent(29, 35, 'c'),
|
||||
FakeReadEvent(31, 32, 'e'), # counts
|
||||
FakeReadEvent(34, 36, 'e', 1), # counts
|
||||
FakeReadEvent(32, 37, 'd'), # counts
|
||||
FakeEvent('something', 10, 13, 3, {}),
|
||||
FakeEvent('something else', 40, 48, 8, {})]
|
||||
interactions = [TestInteraction(10, 20),
|
||||
TestInteraction(30, 40)]
|
||||
|
||||
self.assertEqual({'blob-reads': None, 'blob-writes': None},
|
||||
GetBlobMetrics(events, []))
|
||||
self.assertEqual({'blob-reads': None, 'blob-writes': None},
|
||||
GetBlobMetrics([], interactions))
|
||||
|
||||
# We ignore events outside of the interaction intervals, and we use the
|
||||
# begining of the first event of the interval and the end of the last
|
||||
# event.
|
||||
# 18 - 10 = 8
|
||||
# 37 - 32 = 5
|
||||
self.assertEqual({'blob-reads': [4, 2, 5], 'blob-writes': None},
|
||||
GetBlobMetrics(events, interactions))
|
||||
|
||||
def testReadAndWriteMetrics(self):
|
||||
events = [FakeReadEvent(0, 1, 'a'),
|
||||
FakeReadEvent(9, 11, 'a'),
|
||||
FakeReadEvent(10, 13, 'b'), # counts
|
||||
FakeWriteEvent(15, 18), # counts
|
||||
FakeReadEvent(21, 26, 'c'),
|
||||
FakeReadEvent(29, 35, 'd'),
|
||||
FakeWriteEvent(31, 34, 1), # counts
|
||||
FakeReadEvent(32, 33, 'e'), # counts
|
||||
FakeReadEvent(34, 35, 'e'), # counts
|
||||
FakeEvent('something', 31, 33, 2, {})]
|
||||
interactions = [TestInteraction(10, 20),
|
||||
TestInteraction(30, 35)]
|
||||
|
||||
self.assertEqual({'blob-reads': None, 'blob-writes': None},
|
||||
GetBlobMetrics(events, []))
|
||||
self.assertEqual({'blob-reads': None, 'blob-writes': None},
|
||||
GetBlobMetrics([], interactions))
|
||||
|
||||
# We use the read events in the interactions, so the same as the test above.
|
||||
self.assertEqual({'blob-reads': [3, 2], 'blob-writes': [3, 1]},
|
||||
GetBlobMetrics(events, interactions))
|
@ -8,6 +8,7 @@ from telemetry.core.platform import tracing_category_filter
|
||||
from telemetry.core.platform import tracing_options
|
||||
from telemetry.timeline import model as model_module
|
||||
from telemetry.value import trace
|
||||
from telemetry.web_perf.metrics import blob_timeline
|
||||
from telemetry.web_perf.metrics import gpu_timeline
|
||||
from telemetry.web_perf.metrics import layout
|
||||
from telemetry.web_perf.metrics import responsiveness_metric
|
||||
@ -37,7 +38,8 @@ def _GetAllTimelineBasedMetrics():
|
||||
return (smoothness.SmoothnessMetric(),
|
||||
responsiveness_metric.ResponsivenessMetric(),
|
||||
layout.LayoutMetric(),
|
||||
gpu_timeline.GPUTimelineMetric())
|
||||
gpu_timeline.GPUTimelineMetric(),
|
||||
blob_timeline.BlobTimelineMetric())
|
||||
|
||||
|
||||
class InvalidInteractions(Exception):
|
||||
|
Reference in New Issue
Block a user