Chromium Code Reviews| 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 |