OLD | NEW |
---|---|
1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Models for loading in chrome. | 5 """Models for loading in chrome. |
6 | 6 |
7 (Redirect the following to the general model module once we have one) | 7 (Redirect the following to the general model module once we have one) |
8 A model is an object with the following methods. | 8 A model is an object with the following methods. |
9 CostMs(): return the cost of the model in milliseconds. | 9 CostMs(): return the cost of the model in milliseconds. |
10 Set(): set model-specific parameters. | 10 Set(): set model-specific parameters. |
(...skipping 12 matching lines...) Expand all Loading... | |
23 import dag | 23 import dag |
24 import loading_trace | 24 import loading_trace |
25 import request_dependencies_lens | 25 import request_dependencies_lens |
26 | 26 |
27 class ResourceGraph(object): | 27 class ResourceGraph(object): |
28 """A model of loading by a DAG (tree?) of resource dependancies. | 28 """A model of loading by a DAG (tree?) of resource dependancies. |
29 | 29 |
30 Set parameters: | 30 Set parameters: |
31 cache_all: if true, assume zero loading time for all resources. | 31 cache_all: if true, assume zero loading time for all resources. |
32 """ | 32 """ |
33 def __init__(self, trace): | 33 def __init__(self, trace, content_lens=None): |
34 """Create from a LoadingTrace (or json of a trace). | 34 """Create from a LoadingTrace (or json of a trace). |
35 | 35 |
36 Args: | 36 Args: |
37 trace: (LoadingTrace/JSON) Loading trace or JSON of a trace. | 37 trace: (LoadingTrace/JSON) Loading trace or JSON of a trace. |
38 content_lens: (ContentClassificationLens) Lens used to annotate the | |
39 nodes, or None. | |
38 """ | 40 """ |
39 if type(trace) == dict: | 41 if type(trace) == dict: |
40 trace = loading_trace.LoadingTrace.FromJsonDict(trace) | 42 trace = loading_trace.LoadingTrace.FromJsonDict(trace) |
43 self._content_lens = content_lens | |
41 self._BuildDag(trace) | 44 self._BuildDag(trace) |
42 self._global_start = min([n.StartTime() for n in self._node_info]) | 45 self._global_start = min([n.StartTime() for n in self._node_info]) |
43 # Sort before splitting children so that we can correctly dectect if a | 46 # Sort before splitting children so that we can correctly dectect if a |
44 # reparented child is actually a dependency for a child of its new parent. | 47 # reparented child is actually a dependency for a child of its new parent. |
45 try: | 48 try: |
46 for n in dag.TopologicalSort(self._nodes): | 49 for n in dag.TopologicalSort(self._nodes): |
47 self._SplitChildrenByTime(self._node_info[n.Index()]) | 50 self._SplitChildrenByTime(self._node_info[n.Index()]) |
48 except AssertionError as exc: | 51 except AssertionError as exc: |
49 sys.stderr.write('Bad topological sort: %s\n' | 52 sys.stderr.write('Bad topological sort: %s\n' |
50 'Skipping child split\n' % str(exc)) | 53 'Skipping child split\n' % str(exc)) |
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
324 class _NodeInfo(object): | 327 class _NodeInfo(object): |
325 """Our internal class that adds cost and other information to nodes. | 328 """Our internal class that adds cost and other information to nodes. |
326 | 329 |
327 Costs are stored on the node as well as edges. Edge information is only | 330 Costs are stored on the node as well as edges. Edge information is only |
328 stored on successor edges and not predecessor, that is, you get them from | 331 stored on successor edges and not predecessor, that is, you get them from |
329 the parent and not the child. | 332 the parent and not the child. |
330 | 333 |
331 We also store the request on the node, and expose request-derived | 334 We also store the request on the node, and expose request-derived |
332 information like content type. | 335 information like content type. |
333 """ | 336 """ |
334 def __init__(self, node, request): | 337 def __init__(self, node, request, is_ad, is_tracking): |
335 """Create a new node info. | 338 """Create a new node info. |
336 | 339 |
337 Args: | 340 Args: |
338 node: The node to augment. | 341 node: The node to augment. |
339 request: The request associated with this node. | 342 request: The request associated with this node. |
343 is_ad: (bool) Whether the request is an Ad. | |
344 is_tracking: (bool) Whether the request is related to tracking. | |
340 """ | 345 """ |
341 self._request = request | 346 self._request = request |
347 self._is_ad = is_ad | |
348 self._is_tracking = is_tracking | |
342 self._node = node | 349 self._node = node |
343 self._edge_costs = {} | 350 self._edge_costs = {} |
344 self._edge_annotations = {} | 351 self._edge_annotations = {} |
345 # All fields in timing are millis relative to request_time, which is epoch | 352 # All fields in timing are millis relative to request_time, which is epoch |
346 # seconds. | 353 # seconds. |
347 self._node_cost = max( | 354 self._node_cost = max( |
348 [0] + [t for f, t in request.timing._asdict().iteritems() | 355 [0] + [t for f, t in request.timing._asdict().iteritems() |
349 if f != 'request_time']) | 356 if f != 'request_time']) |
350 | 357 |
351 def __str__(self): | 358 def __str__(self): |
352 return self.ShortName() | 359 return self.ShortName() |
353 | 360 |
354 def Node(self): | 361 def Node(self): |
355 return self._node | 362 return self._node |
356 | 363 |
357 def Index(self): | 364 def Index(self): |
358 return self._node.Index() | 365 return self._node.Index() |
359 | 366 |
367 def IsAd(self): | |
368 return self._is_ad | |
369 | |
370 def IsTracking(self): | |
371 return self._is_tracking | |
372 | |
360 def Request(self): | 373 def Request(self): |
361 return self._request | 374 return self._request |
362 | 375 |
363 def NodeCost(self): | 376 def NodeCost(self): |
364 return self._node_cost | 377 return self._node_cost |
365 | 378 |
366 def EdgeCost(self, s): | 379 def EdgeCost(self, s): |
367 return self._edge_costs[s] | 380 return self._edge_costs[s] |
368 | 381 |
369 def StartTime(self): | 382 def StartTime(self): |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
473 trace: A LoadingTrace. | 486 trace: A LoadingTrace. |
474 """ | 487 """ |
475 self._nodes = [] | 488 self._nodes = [] |
476 self._node_info = [] | 489 self._node_info = [] |
477 index_by_request = {} | 490 index_by_request = {} |
478 for request in trace.request_track.GetEvents(): | 491 for request in trace.request_track.GetEvents(): |
479 next_index = len(self._nodes) | 492 next_index = len(self._nodes) |
480 assert request not in index_by_request | 493 assert request not in index_by_request |
481 index_by_request[request] = next_index | 494 index_by_request[request] = next_index |
482 node = dag.Node(next_index) | 495 node = dag.Node(next_index) |
483 node_info = self._NodeInfo(node, request) | 496 is_ad = (self._content_lens.IsAdRequest(request) |
497 if self._content_lens else False) | |
498 is_tracking = (self._content_lens.IsTrackingRequest(request) | |
499 if self._content_lens else False) | |
500 node_info = self._NodeInfo(node, request, is_ad, is_tracking) | |
mattcary
2016/01/25 16:08:58
I think it would be nicer to add setters to NodeIn
Benoit L
2016/01/26 13:31:13
Absolutely, thanks for the suggestion.
Done.
| |
484 self._nodes.append(node) | 501 self._nodes.append(node) |
485 self._node_info.append(node_info) | 502 self._node_info.append(node_info) |
486 | 503 |
487 dependencies = request_dependencies_lens.RequestDependencyLens( | 504 dependencies = request_dependencies_lens.RequestDependencyLens( |
488 trace).GetRequestDependencies() | 505 trace).GetRequestDependencies() |
489 for parent_rq, child_rq, reason in dependencies: | 506 for parent_rq, child_rq, reason in dependencies: |
490 parent = self._node_info[index_by_request[parent_rq]] | 507 parent = self._node_info[index_by_request[parent_rq]] |
491 child = self._node_info[index_by_request[child_rq]] | 508 child = self._node_info[index_by_request[child_rq]] |
492 edge_cost = child.StartTime() - parent.EndTime() | 509 edge_cost = child.StartTime() - parent.EndTime() |
493 if edge_cost < 0: | 510 if edge_cost < 0: |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
599 node_info = self._node_info[index] | 616 node_info = self._node_info[index] |
600 color = self._ContentTypeToColor(node_info.ContentType()) | 617 color = self._ContentTypeToColor(node_info.ContentType()) |
601 max_age = node_info.Request().MaxAge() | 618 max_age = node_info.Request().MaxAge() |
602 shape = 'polygon' if max_age > 300 else 'oval' | 619 shape = 'polygon' if max_age > 300 else 'oval' |
603 styles = ['filled'] | 620 styles = ['filled'] |
604 if highlight: | 621 if highlight: |
605 for fragment in highlight: | 622 for fragment in highlight: |
606 if fragment in node_info.Url(): | 623 if fragment in node_info.Url(): |
607 styles.append('dotted') | 624 styles.append('dotted') |
608 break | 625 break |
626 if node_info.IsAd() or node_info.IsTracking(): | |
627 styles += ['bold', 'diagonals'] | |
609 return ('%d [label = "%s\\n%.2f->%.2f (%.2f)"; style = "%s"; ' | 628 return ('%d [label = "%s\\n%.2f->%.2f (%.2f)"; style = "%s"; ' |
610 'fillcolor = %s; shape = %s];\n' | 629 'fillcolor = %s; shape = %s];\n' |
611 % (index, node_info.ShortName(), | 630 % (index, node_info.ShortName(), |
612 node_info.StartTime() - self._global_start, | 631 node_info.StartTime() - self._global_start, |
613 node_info.EndTime() - self._global_start, | 632 node_info.EndTime() - self._global_start, |
614 node_info.EndTime() - node_info.StartTime(), | 633 node_info.EndTime() - node_info.StartTime(), |
615 ','.join(styles), color, shape)) | 634 ','.join(styles), color, shape)) |
616 | 635 |
617 @classmethod | 636 @classmethod |
618 def _IsAdUrl(cls, url): | 637 def _IsAdUrl(cls, url): |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
700 Dict of image url + short name to NodeInfo. | 719 Dict of image url + short name to NodeInfo. |
701 """ | 720 """ |
702 image_to_info = {} | 721 image_to_info = {} |
703 for n in self._node_info: | 722 for n in self._node_info: |
704 if (n.ContentType().startswith('image') and | 723 if (n.ContentType().startswith('image') and |
705 not self._IsAdUrl(n.Url())): | 724 not self._IsAdUrl(n.Url())): |
706 key = str((n.Url(), n.ShortName(), n.StartTime())) | 725 key = str((n.Url(), n.ShortName(), n.StartTime())) |
707 assert key not in image_to_info, n.Url() | 726 assert key not in image_to_info, n.Url() |
708 image_to_info[key] = n | 727 image_to_info[key] = n |
709 return image_to_info | 728 return image_to_info |
OLD | NEW |