Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Unified Diff: tools/android/loading/user_satisfied_lens.py

Issue 1888343003: Clovis: contentful paint upgrades. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@url-rename
Patch Set: rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/android/loading/tracing_unittest.py ('k') | tools/android/loading/user_satisfied_lens_unittest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/android/loading/user_satisfied_lens.py
diff --git a/tools/android/loading/user_satisfied_lens.py b/tools/android/loading/user_satisfied_lens.py
index dd99d79a3a8b57a444670ecdf20f6c4e82cfb29c..523a240ece79497b531df2283b429dc34ced8822 100644
--- a/tools/android/loading/user_satisfied_lens.py
+++ b/tools/android/loading/user_satisfied_lens.py
@@ -6,6 +6,9 @@
Several lenses are defined, for example FirstTextPaintLens and
FirstSignificantPaintLens.
+
+When run from the command line, takes a lens name and a trace, and prints the
+fingerprints of the critical resources to stdout.
"""
import logging
import operator
@@ -24,6 +27,53 @@ class _UserSatisfiedLens(object):
_ATTRS = ['_satisfied_msec', '_event_msec', '_postload_msec',
'_critical_request_ids']
+ def CriticalRequests(self):
+ """Critical requests.
+
+ Returns:
+ A sequence of request_track.Request objects representing an estimate of
+ all requests that are necessary for the user satisfaction defined by this
+ class.
+ """
+ raise NotImplementedError
+
+ def CriticalRequestIds(self):
+ """Ids of critical requests."""
+ return set(rq.request_id for rq in self.CriticalRequests())
+
+ def CriticalFingerprints(self):
+ """Fingerprints of critical requests."""
+ return set(rq.fingerprint for rq in self.CriticalRequests())
+
+ def PostloadTimeMsec(self):
+ """Return postload time.
+
+ The postload time is an estimate of the amount of time needed by chrome to
+ transform the critical results into the satisfying event.
+
+ Returns:
+ Postload time in milliseconds.
+ """
+ return 0
+
+
+class RequestFingerprintLens(_UserSatisfiedLens):
+ """A lens built using requests in a trace that match a set of fingerprints."""
+ def __init__(self, trace, fingerprints):
+ fingerprints = set(fingerprints)
+ self._critical_requests = [rq for rq in trace.request_track.GetEvents()
+ if rq.fingerprint in fingerprints]
+
+ def CriticalRequests(self):
+ """Ids of critical requests."""
+ return set(self._critical_requests)
+
+
+class _FirstEventLens(_UserSatisfiedLens):
+ """Helper abstract subclass that defines users first event manipulations."""
+ # pylint can't handle abstract subclasses.
+ # pylint: disable=abstract-method
+
def __init__(self, trace):
"""Initialize the lens.
@@ -36,34 +86,23 @@ class _UserSatisfiedLens(object):
self._critical_request_ids = None
if trace is None:
return
- self._CalculateTimes(trace.tracing_track)
- critical_requests = self._RequestsBefore(
+ self._CalculateTimes(trace)
+ self._critical_requests = self._RequestsBefore(
trace.request_track, self._satisfied_msec)
- self._critical_request_ids = set(rq.request_id for rq in critical_requests)
- if critical_requests:
- last_load = max(rq.end_msec for rq in critical_requests)
+ self._critical_request_ids = set(rq.request_id
+ for rq in self._critical_requests)
+ if self._critical_requests:
+ last_load = max(rq.end_msec for rq in self._critical_requests)
else:
last_load = float('inf')
self._postload_msec = self._event_msec - last_load
def CriticalRequests(self):
- """Request ids of critical requests.
-
- Returns:
- A set of request ids (as strings) of an estimate of all requests that are
- necessary for the user satisfaction defined by this class.
- """
- return self._critical_request_ids
+ """Override."""
+ return self._critical_requests
def PostloadTimeMsec(self):
- """Return postload time.
-
- The postload time is an estimate of the amount of time needed by chrome to
- transform the critical results into the satisfying event.
-
- Returns:
- Postload time in milliseconds.
- """
+ """Override."""
return self._postload_msec
def ToJsonDict(self):
@@ -75,7 +114,7 @@ class _UserSatisfiedLens(object):
return common_util.DeserializeAttributesFromJsonDict(
json_dict, result, cls._ATTRS)
- def _CalculateTimes(self, tracing_track):
+ def _CalculateTimes(self, trace):
"""Subclasses should implement to set _satisfied_msec and _event_msec."""
raise NotImplementedError
@@ -84,26 +123,19 @@ class _UserSatisfiedLens(object):
return [rq for rq in request_track.GetEvents()
if rq.end_msec <= time_ms]
-
-class _FirstEventLens(_UserSatisfiedLens):
- """Helper abstract subclass that defines users first event manipulations."""
- # pylint can't handle abstract subclasses.
- # pylint: disable=abstract-method
-
@classmethod
def _CheckCategory(cls, tracing_track, category):
assert category in tracing_track.Categories(), (
'The "%s" category must be enabled.' % category)
@classmethod
- def _ExtractFirstTiming(cls, times):
+ def _ExtractBestTiming(cls, times):
if not times:
return float('inf')
- if len(times) != 1:
- # TODO(mattcary): in some cases a trace has two first paint events. Why?
- logging.error('%d %s with spread of %s', len(times),
- str(cls), max(times) - min(times))
- return float(min(times))
+ assert len(times) == 1, \
+ 'Unexpected duplicate {}: {} with spread of {}'.format(
+ str(cls), len(times), max(times) - min(times))
+ return float(max(times))
class FirstTextPaintLens(_FirstEventLens):
@@ -112,12 +144,13 @@ class FirstTextPaintLens(_FirstEventLens):
This event is taken directly from a trace.
"""
_EVENT_CATEGORY = 'blink.user_timing'
- def _CalculateTimes(self, tracing_track):
- self._CheckCategory(tracing_track, self._EVENT_CATEGORY)
- first_paints = [e.start_msec for e in tracing_track.GetEvents()
- if e.Matches(self._EVENT_CATEGORY, 'firstPaint')]
+ def _CalculateTimes(self, trace):
+ self._CheckCategory(trace.tracing_track, self._EVENT_CATEGORY)
+ first_paints = [
+ e.start_msec for e in trace.tracing_track.GetMatchingMainFrameEvents(
+ 'blink.user_timing', 'firstPaint')]
self._satisfied_msec = self._event_msec = \
- self._ExtractFirstTiming(first_paints)
+ self._ExtractBestTiming(first_paints)
class FirstContentfulPaintLens(_FirstEventLens):
@@ -127,12 +160,13 @@ class FirstContentfulPaintLens(_FirstEventLens):
by filtering out things like background paint from firstPaint.
"""
_EVENT_CATEGORY = 'blink.user_timing'
- def _CalculateTimes(self, tracing_track):
- self._CheckCategory(tracing_track, self._EVENT_CATEGORY)
- first_paints = [e.start_msec for e in tracing_track.GetEvents()
- if e.Matches(self._EVENT_CATEGORY, 'firstContentfulPaint')]
+ def _CalculateTimes(self, trace):
+ self._CheckCategory(trace.tracing_track, self._EVENT_CATEGORY)
+ first_paints = [
+ e.start_msec for e in trace.tracing_track.GetMatchingMainFrameEvents(
+ 'blink.user_timing', 'firstContentfulPaint')]
self._satisfied_msec = self._event_msec = \
- self._ExtractFirstTiming(first_paints)
+ self._ExtractBestTiming(first_paints)
class FirstSignificantPaintLens(_FirstEventLens):
@@ -143,12 +177,18 @@ class FirstSignificantPaintLens(_FirstEventLens):
that is the observable event.
"""
_FIRST_LAYOUT_COUNTER = 'LayoutObjectsThatHadNeverHadLayout'
- _EVENT_CATEGORY = 'disabled-by-default-blink.debug.layout'
- def _CalculateTimes(self, tracing_track):
- self._CheckCategory(tracing_track, self._EVENT_CATEGORY)
+ _EVENT_CATEGORIES = ['blink', 'disabled-by-default-blink.debug.layout']
+ def _CalculateTimes(self, trace):
+ for cat in self._EVENT_CATEGORIES:
+ self._CheckCategory(trace.tracing_track, cat)
sync_paint_times = []
layouts = [] # (layout item count, msec).
- for e in tracing_track.GetEvents():
+ for e in trace.tracing_track.GetEvents():
+ if ('frame' in e.args and
+ e.args['frame'] != trace.tracing_track.GetMainFrameID()):
+ continue
+ # If we don't know have a frame id, we assume it applies to all events.
+
# TODO(mattcary): is this the right paint event? Check if synchronized
# paints appear at the same time as the first*Paint events, above.
if e.Matches('blink', 'FrameView::synchronizedPaint'):
@@ -158,7 +198,25 @@ class FirstSignificantPaintLens(_FirstEventLens):
layouts.append((e.args['counters'][self._FIRST_LAYOUT_COUNTER],
e.start_msec))
assert layouts, 'No layout events'
+ assert sync_paint_times,'No sync paint times'
layouts.sort(key=operator.itemgetter(0), reverse=True)
self._satisfied_msec = layouts[0][1]
- self._event_msec = self._ExtractFirstTiming([
- min(t for t in sync_paint_times if t > self._satisfied_msec)])
+ self._event_msec = min(t for t in sync_paint_times
+ if t > self._satisfied_msec)
+
+
+def main(lens_name, trace_file):
+ assert (lens_name in globals() and
+ not lens_name.startswith('_') and
+ lens_name.endswith('Lens')), 'Bad lens %s' % lens_name
+ lens_cls = globals()[lens_name]
+ trace = loading_trace.LoadingTrace.FromJsonFile(trace_file)
+ lens = lens_cls(trace)
+ for fp in sorted(lens.CriticalFingerprints()):
+ print fp
+
+
+if __name__ == '__main__':
+ import sys
+ import loading_trace
+ main(sys.argv[1], sys.argv[2])
« no previous file with comments | « tools/android/loading/tracing_unittest.py ('k') | tools/android/loading/user_satisfied_lens_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698