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 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
283 for c in children: | 283 for c in children: |
284 assert n in c.Predecessors() # Integrity checking | 284 assert n in c.Predecessors() # Integrity checking |
285 queue.append(c) | 285 queue.append(c) |
286 assert len(visited) == len(self._nodes) | 286 assert len(visited) == len(self._nodes) |
287 return '\n'.join(output) | 287 return '\n'.join(output) |
288 | 288 |
289 ## | 289 ## |
290 ## Internal items | 290 ## Internal items |
291 ## | 291 ## |
292 | 292 |
293 _CONTENT_TYPE_TO_COLOR = {'html': 'red', 'css': 'green', 'script': 'blue', | 293 _CONTENT_KIND_TO_COLOR = { |
blundell
2016/01/21 14:11:38
Worth documenting what these mean?
mattcary
2016/01/21 16:11:35
Done.
| |
294 'json': 'purple', 'gif_image': 'grey', | 294 'application': 'blue', |
295 'image': 'orange', 'other': 'white'} | 295 'font': 'grey2', |
296 'image': 'orange', # This probably catches gifs? | |
Benoit L
2016/01/21 14:14:38
it does.
mattcary
2016/01/21 16:11:35
Then this isn't what we want. Well, let me land th
Benoit L
2016/01/21 16:20:03
About as high as deciding on the bike shed color.
| |
297 } | |
298 | |
299 _CONTENT_TYPE_TO_COLOR = { | |
300 'html': 'red', | |
301 'css': 'green', | |
302 'script': 'blue', | |
303 'javascript': 'blue', | |
304 'json': 'purple', | |
305 'gif': 'grey', | |
306 'image': 'orange', | |
307 'jpeg': 'orange', | |
308 'png': 'orange', | |
309 'plain': 'brown3', | |
310 'octet-stream': 'brown3', | |
311 'other': 'white', | |
312 } | |
296 | 313 |
297 # This resource type may induce a timing dependency. See _SplitChildrenByTime | 314 # This resource type may induce a timing dependency. See _SplitChildrenByTime |
298 # for details. | 315 # for details. |
299 # TODO(mattcary): are these right? | 316 # TODO(mattcary): are these right? |
300 _CAN_BE_TIMING_PARENT = set(['script', 'magic-debug-content']) | 317 _CAN_BE_TIMING_PARENT = set(['script', 'magic-debug-content']) |
301 _CAN_MAKE_TIMING_DEPENDENCE = set(['json', 'other', 'magic-debug-content']) | 318 _CAN_MAKE_TIMING_DEPENDENCE = set(['json', 'other', 'magic-debug-content']) |
302 | 319 |
303 class _NodeInfo(object): | 320 class _NodeInfo(object): |
304 """Our internal class that adds cost and other information to nodes. | 321 """Our internal class that adds cost and other information to nodes. |
305 | 322 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
356 | 373 |
357 def ContentType(self): | 374 def ContentType(self): |
358 return self._request.GetContentType() | 375 return self._request.GetContentType() |
359 | 376 |
360 def ShortName(self): | 377 def ShortName(self): |
361 """Returns either the hostname of the resource, or the filename, | 378 """Returns either the hostname of the resource, or the filename, |
362 or the end of the path. Tries to include the domain as much as possible. | 379 or the end of the path. Tries to include the domain as much as possible. |
363 """ | 380 """ |
364 parsed = urlparse.urlparse(self._request.url) | 381 parsed = urlparse.urlparse(self._request.url) |
365 path = parsed.path | 382 path = parsed.path |
383 hostname = parsed.hostname if parsed.hostname else '?.?.?' | |
366 if path != '' and path != '/': | 384 if path != '' and path != '/': |
367 last_path = parsed.path.split('/')[-1] | 385 last_path = parsed.path.split('/')[-1] |
368 if len(last_path) < 10: | 386 if len(last_path) < 10: |
369 if len(path) < 10: | 387 if len(path) < 10: |
370 return parsed.hostname + '/' + path | 388 return hostname + '/' + path |
371 else: | 389 else: |
372 return parsed.hostname + '/..' + parsed.path[-10:] | 390 return hostname + '/..' + parsed.path[-10:] |
373 elif len(last_path) > 10: | 391 elif len(last_path) > 10: |
374 return parsed.hostname + '/..' + last_path[:5] | 392 return hostname + '/..' + last_path[:5] |
375 else: | 393 else: |
376 return parsed.hostname + '/..' + last_path | 394 return hostname + '/..' + last_path |
377 else: | 395 else: |
378 return parsed.hostname | 396 return hostname |
379 | 397 |
380 def Url(self): | 398 def Url(self): |
381 return self._request.url | 399 return self._request.url |
382 | 400 |
383 def SetEdgeCost(self, child, cost): | 401 def SetEdgeCost(self, child, cost): |
384 assert child.Node() in self._node.Successors() | 402 assert child.Node() in self._node.Successors() |
385 self._edge_costs[child] = cost | 403 self._edge_costs[child] = cost |
386 | 404 |
387 def AddEdgeAnnotation(self, s, annotation): | 405 def AddEdgeAnnotation(self, s, annotation): |
388 assert s.Node() in self._node.Successors() | 406 assert s.Node() in self._node.Successors() |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
456 next_index = len(self._nodes) | 474 next_index = len(self._nodes) |
457 assert request not in index_by_request | 475 assert request not in index_by_request |
458 index_by_request[request] = next_index | 476 index_by_request[request] = next_index |
459 node = dag.Node(next_index) | 477 node = dag.Node(next_index) |
460 node_info = self._NodeInfo(node, request) | 478 node_info = self._NodeInfo(node, request) |
461 self._nodes.append(node) | 479 self._nodes.append(node) |
462 self._node_info.append(node_info) | 480 self._node_info.append(node_info) |
463 | 481 |
464 dependencies = request_dependencies_lens.RequestDependencyLens( | 482 dependencies = request_dependencies_lens.RequestDependencyLens( |
465 trace).GetRequestDependencies() | 483 trace).GetRequestDependencies() |
466 for child_rq, parent_rq, reason in dependencies: | 484 for parent_rq, child_rq, reason in dependencies: |
467 parent = self._node_info[index_by_request[parent_rq]] | 485 parent = self._node_info[index_by_request[parent_rq]] |
468 child = self._node_info[index_by_request[child_rq]] | 486 child = self._node_info[index_by_request[child_rq]] |
469 edge_cost = child.StartTime() - parent.EndTime() | 487 edge_cost = child.StartTime() - parent.EndTime() |
470 if edge_cost < 0: | 488 if edge_cost < 0: |
471 edge_cost = 0 | 489 edge_cost = 0 |
472 if child.StartTime() < parent.StartTime(): | 490 if child.StartTime() < parent.StartTime(): |
473 logging.error('Inverted dependency: %s->%s', | 491 logging.error('Inverted dependency: %s->%s', |
474 parent.ShortName(), child.ShortName()) | 492 parent.ShortName(), child.ShortName()) |
475 # Note that child.StartTime() < parent.EndTime() appears to happen a | 493 # Note that child.StartTime() < parent.EndTime() appears to happen a |
476 # fair amount in practice. | 494 # fair amount in practice. |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
542 break | 560 break |
543 if end_mark >= len(children_by_end_time): | 561 if end_mark >= len(children_by_end_time): |
544 break # It's not possible to rearrange any more children. | 562 break # It's not possible to rearrange any more children. |
545 if go_to_next_child: | 563 if go_to_next_child: |
546 continue # We can't rearrange this child, but the next child may be | 564 continue # We can't rearrange this child, but the next child may be |
547 # eligible. | 565 # eligible. |
548 if children_by_end_time[end_mark].EndTime() <= current.StartTime(): | 566 if children_by_end_time[end_mark].EndTime() <= current.StartTime(): |
549 current.ReparentTo(parent, children_by_end_time[end_mark]) | 567 current.ReparentTo(parent, children_by_end_time[end_mark]) |
550 children_by_end_time[end_mark].AddEdgeAnnotation(current, 'timing') | 568 children_by_end_time[end_mark].AddEdgeAnnotation(current, 'timing') |
551 | 569 |
570 def _ContentTypeToColor(self, content_type): | |
571 if not content_type: | |
572 type_str = 'other' | |
573 elif '/' in content_type: | |
574 kind, type_str = content_type.split('/') | |
575 if kind in self._CONTENT_KIND_TO_COLOR: | |
blundell
2016/01/21 14:11:38
hmm, also probably worth documenting the relations
mattcary
2016/01/21 16:11:35
I don't really know how these mime-types work. I t
| |
576 return self._CONTENT_KIND_TO_COLOR[kind] | |
577 else: | |
578 type_str = content_type | |
579 return self._CONTENT_TYPE_TO_COLOR[type_str] | |
580 | |
552 def _GraphvizNode(self, index, highlight): | 581 def _GraphvizNode(self, index, highlight): |
553 """Returns a graphviz node description for a given node. | 582 """Returns a graphviz node description for a given node. |
554 | 583 |
555 Args: | 584 Args: |
556 index: index of the node. | 585 index: index of the node. |
557 highlight: a list of node items to emphasize. Any resource url which | 586 highlight: a list of node items to emphasize. Any resource url which |
558 contains any highlight text will be distinguished in the output. | 587 contains any highlight text will be distinguished in the output. |
559 | 588 |
560 Returns: | 589 Returns: |
561 A string describing the resource in graphviz format. | 590 A string describing the resource in graphviz format. |
562 The resource is color-coded according to its content type, and its shape | 591 The resource is color-coded according to its content type, and its shape |
563 is oval if its max-age is less than 300s (or if it's not cacheable). | 592 is oval if its max-age is less than 300s (or if it's not cacheable). |
564 """ | 593 """ |
565 node_info = self._node_info[index] | 594 node_info = self._node_info[index] |
566 color = self._CONTENT_TYPE_TO_COLOR[node_info.ContentType()] | 595 color = self._ContentTypeToColor(node_info.ContentType()) |
567 max_age = node_info.Request().MaxAge() | 596 max_age = node_info.Request().MaxAge() |
568 shape = 'polygon' if max_age > 300 else 'oval' | 597 shape = 'polygon' if max_age > 300 else 'oval' |
569 styles = ['filled'] | 598 styles = ['filled'] |
570 if highlight: | 599 if highlight: |
571 for fragment in highlight: | 600 for fragment in highlight: |
572 if fragment in node_info.Url(): | 601 if fragment in node_info.Url(): |
573 styles.append('dotted') | 602 styles.append('dotted') |
574 break | 603 break |
575 return ('%d [label = "%s\\n%.2f->%.2f (%.2f)"; style = "%s"; ' | 604 return ('%d [label = "%s\\n%.2f->%.2f (%.2f)"; style = "%s"; ' |
576 'fillcolor = %s; shape = %s];\n' | 605 'fillcolor = %s; shape = %s];\n' |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
666 Dict of image url + short name to NodeInfo. | 695 Dict of image url + short name to NodeInfo. |
667 """ | 696 """ |
668 image_to_info = {} | 697 image_to_info = {} |
669 for n in self._node_info: | 698 for n in self._node_info: |
670 if (n.ContentType().startswith('image') and | 699 if (n.ContentType().startswith('image') and |
671 not self._IsAdUrl(n.Url())): | 700 not self._IsAdUrl(n.Url())): |
672 key = str((n.Url(), n.ShortName(), n.StartTime())) | 701 key = str((n.Url(), n.ShortName(), n.StartTime())) |
673 assert key not in image_to_info, n.Url() | 702 assert key not in image_to_info, n.Url() |
674 image_to_info[key] = n | 703 image_to_info[key] = n |
675 return image_to_info | 704 return image_to_info |
OLD | NEW |