| Index: tools/android/loading/process_request_log.py
|
| diff --git a/tools/android/loading/process_request_log.py b/tools/android/loading/process_request_log.py
|
| deleted file mode 100755
|
| index bbec0a8f533d01472d8ab378add3ed79b593d339..0000000000000000000000000000000000000000
|
| --- a/tools/android/loading/process_request_log.py
|
| +++ /dev/null
|
| @@ -1,189 +0,0 @@
|
| -#! /usr/bin/python
|
| -# 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.
|
| -
|
| -"""Creates a Graphviz file visualizing the resource dependencies from a JSON
|
| -file dumped by log_requests.py.
|
| -"""
|
| -
|
| -import collections
|
| -import sys
|
| -import urlparse
|
| -
|
| -import log_parser
|
| -from log_parser import Resource
|
| -
|
| -
|
| -def _BuildResourceDependencyGraph(requests):
|
| - """Builds the graph of resource dependencies.
|
| -
|
| - Args:
|
| - requests: [RequestData, ...]
|
| -
|
| - Returns:
|
| - A tuple ([Resource], [(resource1, resource2, reason), ...])
|
| - """
|
| - resources = log_parser.GetResources(requests)
|
| - resources_from_url = {resource.url: resource for resource in resources}
|
| - requests_by_completion = log_parser.SortedByCompletion(requests)
|
| - deps = []
|
| - for r in requests:
|
| - resource = Resource.FromRequest(r)
|
| - initiator = r.initiator
|
| - initiator_type = initiator['type']
|
| - dep = None
|
| - if initiator_type == 'parser':
|
| - url = initiator['url']
|
| - blocking_resource = resources_from_url.get(url, None)
|
| - if blocking_resource is None:
|
| - continue
|
| - dep = (blocking_resource, resource, 'parser')
|
| - elif initiator_type == 'script' and 'stackTrace' in initiator:
|
| - for frame in initiator['stackTrace']:
|
| - url = frame['url']
|
| - blocking_resource = resources_from_url.get(url, None)
|
| - if blocking_resource is None:
|
| - continue
|
| - dep = (blocking_resource, resource, 'stack')
|
| - break
|
| - else:
|
| - # When the initiator is a script without a stackTrace, infer that it comes
|
| - # from the most recent script from the same hostname.
|
| - # TLD+1 might be better, but finding what is a TLD requires a database.
|
| - request_hostname = urlparse.urlparse(r.url).hostname
|
| - sorted_script_requests_from_hostname = [
|
| - r for r in requests_by_completion
|
| - if (resource.GetContentType() in ('script', 'html', 'json')
|
| - and urlparse.urlparse(r.url).hostname == request_hostname)]
|
| - most_recent = None
|
| - # Linear search is bad, but this shouldn't matter here.
|
| - for request in sorted_script_requests_from_hostname:
|
| - if request.timestamp < r.timing.requestTime:
|
| - most_recent = request
|
| - else:
|
| - break
|
| - if most_recent is not None:
|
| - blocking = resources_from_url.get(most_recent.url, None)
|
| - if blocking is not None:
|
| - dep = (blocking, resource, 'script_inferred')
|
| - if dep is not None:
|
| - deps.append(dep)
|
| - return (resources, deps)
|
| -
|
| -
|
| -def PrefetchableResources(requests):
|
| - """Returns a list of resources that are discoverable without JS.
|
| -
|
| - Args:
|
| - requests: List of requests.
|
| -
|
| - Returns:
|
| - List of discoverable resources, with their initial request.
|
| - """
|
| - resource_to_request = log_parser.ResourceToRequestMap(requests)
|
| - (_, all_deps) = _BuildResourceDependencyGraph(requests)
|
| - # Only keep "parser" arcs
|
| - deps = [(first, second) for (first, second, reason) in all_deps
|
| - if reason == 'parser']
|
| - deps_per_resource = collections.defaultdict(list)
|
| - for (first, second) in deps:
|
| - deps_per_resource[first].append(second)
|
| - result = []
|
| - visited = set()
|
| - to_visit = [deps[0][0]]
|
| - while len(to_visit) != 0:
|
| - r = to_visit.pop()
|
| - visited.add(r)
|
| - to_visit += deps_per_resource[r]
|
| - result.append(resource_to_request[r])
|
| - return result
|
| -
|
| -
|
| -_CONTENT_TYPE_TO_COLOR = {'html': 'red', 'css': 'green', 'script': 'blue',
|
| - 'json': 'purple', 'gif_image': 'grey',
|
| - 'image': 'orange', 'other': 'white'}
|
| -
|
| -
|
| -def _ResourceGraphvizNode(resource, request, resource_to_index):
|
| - """Returns the node description for a given resource.
|
| -
|
| - Args:
|
| - resource: Resource.
|
| - request: RequestData associated with the resource.
|
| - resource_to_index: {Resource: int}.
|
| -
|
| - Returns:
|
| - A string describing the resource in graphviz format.
|
| - The resource is color-coded according to its content type, and its shape is
|
| - oval if its max-age is less than 300s (or if it's not cacheable).
|
| - """
|
| - color = _CONTENT_TYPE_TO_COLOR[resource.GetContentType()]
|
| - max_age = log_parser.MaxAge(request)
|
| - shape = 'polygon' if max_age > 300 else 'oval'
|
| - return ('%d [label = "%s"; style = "filled"; fillcolor = %s; shape = %s];\n'
|
| - % (resource_to_index[resource], resource.GetShortName(), color,
|
| - shape))
|
| -
|
| -
|
| -def _GraphvizFileFromDeps(resources, requests, deps, output_filename):
|
| - """Writes a graphviz file from a set of resource dependencies.
|
| -
|
| - Args:
|
| - resources: [Resource, ...]
|
| - requests: list of requests
|
| - deps: [(resource1, resource2, reason), ...]
|
| - output_filename: file to write the graph to.
|
| - """
|
| - with open(output_filename, 'w') as f:
|
| - f.write("""digraph dependencies {
|
| - rankdir = LR;
|
| - """)
|
| - resource_to_request = log_parser.ResourceToRequestMap(requests)
|
| - resource_to_index = {r: i for (i, r) in enumerate(resources)}
|
| - resources_with_edges = set()
|
| - for (first, second, reason) in deps:
|
| - resources_with_edges.add(first)
|
| - resources_with_edges.add(second)
|
| - if len(resources_with_edges) != len(resources):
|
| - f.write("""subgraph cluster_orphans {
|
| - color=black;
|
| - label="Orphans";
|
| -""")
|
| - for resource in resources:
|
| - if resource not in resources_with_edges:
|
| - request = resource_to_request[resource]
|
| - f.write(_ResourceGraphvizNode(resource, request, resource_to_index))
|
| - f.write('}\n')
|
| -
|
| - f.write("""subgraph cluster_nodes {
|
| - color=invis;
|
| -""")
|
| - for resource in resources:
|
| - request = resource_to_request[resource]
|
| - print resource.url
|
| - if resource in resources_with_edges:
|
| - f.write(_ResourceGraphvizNode(resource, request, resource_to_index))
|
| - for (first, second, reason) in deps:
|
| - arrow = ''
|
| - if reason == 'parser':
|
| - arrow = '[color = red]'
|
| - elif reason == 'stack':
|
| - arrow = '[color = blue]'
|
| - elif reason == 'script_inferred':
|
| - arrow = '[color = blue; style=dotted]'
|
| - f.write('%d -> %d %s;\n' % (
|
| - resource_to_index[first], resource_to_index[second], arrow))
|
| - f.write('}\n}\n')
|
| -
|
| -
|
| -def main():
|
| - filename = sys.argv[1]
|
| - requests = log_parser.ParseJsonFile(filename)
|
| - requests = log_parser.FilterRequests(requests)
|
| - (resources, deps) = _BuildResourceDependencyGraph(requests)
|
| - _GraphvizFileFromDeps(resources, requests, deps, filename + '.dot')
|
| -
|
| -
|
| -if __name__ == '__main__':
|
| - main()
|
|
|