OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright 2016 The Chromium Authors. All rights reserved. | 2 # Copyright 2016 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Inspection of the prefetch predictor database. | 6 """Inspection of the prefetch predictor database. |
7 | 7 |
8 On Android, the database can be extracted using: | 8 On Android, the database can be extracted using: |
9 adb pull \ | 9 adb pull \ |
10 '/data/user/0/$package_name/app_chrome/Default/Network Action Predictor' | 10 '/data/user/0/$package_name/app_chrome/Default/Network Action Predictor' |
11 predictor_db | 11 predictor_db |
12 """ | 12 """ |
13 | 13 |
14 import argparse | 14 import argparse |
15 import operator | |
16 import sqlite3 | 15 import sqlite3 |
17 | 16 |
18 from resource_prefetch_predictor_pb2 import ResourceData | 17 from resource_prefetch_predictor_pb2 import (PrefetchData, ResourceData) |
19 | 18 |
20 | 19 |
21 class Entry(object): | 20 class Entry(object): |
22 """Represents an entry in the predictor database.""" | 21 """Represents an entry in the predictor database.""" |
23 def __init__( | 22 def __init__( |
24 self, main_page_url, resource_url, proto_buffer): | 23 self, primary_key, proto_buffer): |
25 self.main_page_url = main_page_url | 24 self.primary_key = primary_key |
26 self.resource_url = resource_url | 25 self.prefetch_data = PrefetchData() |
27 self.proto = ResourceData() | 26 self.prefetch_data.ParseFromString(proto_buffer) |
28 self.proto.ParseFromString(proto_buffer) | |
29 self.confidence = float(self.proto.number_of_hits / ( | |
30 self.proto.number_of_hits + self.proto.number_of_misses)) | |
31 self.score = self._Score() | |
32 | 27 |
33 def _Score(self): | 28 @classmethod |
34 """Mirrors ResourcePrefetchPredictorTables::ComputeResourceScore.""" | 29 def _ComputeResourceScore(cls, resource): |
| 30 """Mirrors ResourcePrefetchPredictorTables::ComputeResourceScore. |
| 31 |
| 32 Args: |
| 33 resource: ResourceData. |
| 34 |
| 35 Return: |
| 36 The resource score (int). |
| 37 """ |
35 priority_multiplier = 1 | 38 priority_multiplier = 1 |
36 type_multiplier = 1 | 39 type_multiplier = 1 |
37 | 40 |
38 if self.proto.priority == ResourceData.REQUEST_PRIORITY_HIGHEST: | 41 if resource.priority == ResourceData.REQUEST_PRIORITY_HIGHEST: |
39 priority_multiplier = 3 | 42 priority_multiplier = 3 |
40 elif self.proto.priority == ResourceData.REQUEST_PRIORITY_MEDIUM: | 43 elif resource.priority == ResourceData.REQUEST_PRIORITY_MEDIUM: |
41 priority_multiplier = 2 | 44 priority_multiplier = 2 |
42 | 45 |
43 if self.proto.resource_type in (ResourceData.RESOURCE_TYPE_STYLESHEET, | 46 if resource.resource_type in (ResourceData.RESOURCE_TYPE_STYLESHEET, |
44 ResourceData.RESOURCE_TYPE_SCRIPT): | 47 ResourceData.RESOURCE_TYPE_SCRIPT): |
45 type_multiplier = 3 | 48 type_multiplier = 3 |
46 elif self.proto.resource_type == ResourceData.RESOURCE_TYPE_FONT_RESOURCE: | 49 elif resource.resource_type == ResourceData.RESOURCE_TYPE_FONT_RESOURCE: |
47 type_multiplier = 2 | 50 type_multiplier = 2 |
48 | 51 |
49 return (100 * (priority_multiplier * 100 + type_multiplier * 10) | 52 return (100 * (priority_multiplier * 100 + type_multiplier * 10) |
50 - self.proto.average_position) | 53 - resource.average_position) |
51 | 54 |
52 @classmethod | 55 @classmethod |
53 def FromRow(cls, row): | 56 def FromRow(cls, row): |
54 """Builds an entry from a database row.""" | 57 """Builds an entry from a database row.""" |
55 return Entry(*row) | 58 return Entry(*row) |
56 | 59 |
57 def __str__(self): | 60 @classmethod |
58 return 'score: %s\nmain_page_url: %s\nconfidence: %f"\n%s' % ( | 61 def _PrettyPrintResource(cls, resource): |
59 self.score, self.main_page_url, self.confidence, self.proto) | 62 """Pretty-prints a resource to stdout. |
60 | 63 |
| 64 Args: |
| 65 resource: ResourceData. |
| 66 """ |
| 67 print 'score: %d' % cls._ComputeResourceScore(resource) |
| 68 print resource |
61 | 69 |
62 def FilterAndSort(entries, domain): | 70 def PrettyPrintCandidates(self): |
63 """Filters and sorts the entries to be prefetched for a given domain. | 71 """Prints the candidates for prefetch.""" |
64 | 72 print 'primary_key: %s' % self.prefetch_data.primary_key |
65 Uses the default thresholds defined in resource_prefetch_common.cc. | 73 for resource in self.prefetch_data.resources: |
66 """ | 74 confidence = float(resource.number_of_hits) / ( |
67 result = filter( | 75 resource.number_of_hits + resource.number_of_misses) |
68 lambda x: ((domain is None or x.main_page_url == domain) | 76 if resource.number_of_hits < 2 or confidence < .7: |
69 and x.confidence > .7 | 77 continue |
70 and x.proto.number_of_hits >= 2), entries) | 78 self._PrettyPrintResource(resource) |
71 return sorted(result, key=operator.attrgetter('score'), reverse=True) | |
72 | 79 |
73 | 80 |
74 def DatabaseStats(filename, domain): | 81 def DatabaseStats(filename, domain): |
75 connection = sqlite3.connect(filename) | 82 connection = sqlite3.connect(filename) |
76 c = connection.cursor() | 83 c = connection.cursor() |
77 query = ('SELECT main_page_url, resource_url, proto ' | 84 query = ('SELECT key, proto FROM resource_prefetch_predictor_host') |
78 'FROM resource_prefetch_predictor_host') | |
79 entries = [Entry.FromRow(row) for row in c.execute(query)] | 85 entries = [Entry.FromRow(row) for row in c.execute(query)] |
80 prefetched = FilterAndSort(entries, domain) | 86 for x in entries: |
81 for x in prefetched: | 87 if domain is None or x.primary_key == domain: |
82 print x | 88 x.PrettyPrintCandidates() |
83 | 89 |
84 | 90 |
85 def main(): | 91 def main(): |
86 parser = argparse.ArgumentParser() | 92 parser = argparse.ArgumentParser() |
87 parser.add_argument('-f', dest='database_filename', required=True, | 93 parser.add_argument('-f', dest='database_filename', required=True, |
88 help='Path to the database') | 94 help='Path to the database') |
89 parser.add_argument('-d', dest='domain', default=None, help='Domain') | 95 parser.add_argument('-d', dest='domain', default=None, help='Domain') |
90 args = parser.parse_args() | 96 args = parser.parse_args() |
91 DatabaseStats(args.database_filename, args.domain) | 97 DatabaseStats(args.database_filename, args.domain) |
92 | 98 |
93 | 99 |
94 if __name__ == '__main__': | 100 if __name__ == '__main__': |
95 main() | 101 main() |
OLD | NEW |