| 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 datetime |
| 15 import sqlite3 | 16 import sqlite3 |
| 16 import os | 17 import os |
| 17 | 18 import sys |
| 18 from resource_prefetch_predictor_pb2 import (PrefetchData, ResourceData) | |
| 19 | 19 |
| 20 | 20 |
| 21 class Entry(object): | 21 class Entry(object): |
| 22 """Represents an entry in the predictor database.""" | 22 """Represents an entry in the predictor database.""" |
| 23 def __init__( | 23 def __init__( |
| 24 self, primary_key, proto_buffer): | 24 self, primary_key, proto_buffer): |
| 25 from resource_prefetch_predictor_pb2 import (PrefetchData, ResourceData) |
| 25 self.primary_key = primary_key | 26 self.primary_key = primary_key |
| 26 self.prefetch_data = PrefetchData() | 27 self.prefetch_data = PrefetchData() |
| 27 self.prefetch_data.ParseFromString(proto_buffer) | 28 self.prefetch_data.ParseFromString(proto_buffer) |
| 28 | 29 |
| 29 @classmethod | 30 @classmethod |
| 30 def _ComputeResourceScore(cls, resource): | 31 def _ComputeResourceScore(cls, resource): |
| 31 """Mirrors ResourcePrefetchPredictorTables::ComputeResourceScore. | 32 """Mirrors ResourcePrefetchPredictorTables::ComputeResourceScore. |
| 32 | 33 |
| 33 Args: | 34 Args: |
| 34 resource: ResourceData. | 35 resource: ResourceData. |
| 35 | 36 |
| 36 Return: | 37 Return: |
| 37 The resource score (int). | 38 The resource score (int). |
| 38 """ | 39 """ |
| 40 from resource_prefetch_predictor_pb2 import (PrefetchData, ResourceData) |
| 39 priority_multiplier = 1 | 41 priority_multiplier = 1 |
| 40 type_multiplier = 1 | 42 type_multiplier = 1 |
| 41 | 43 |
| 42 if resource.priority == ResourceData.REQUEST_PRIORITY_HIGHEST: | 44 if resource.priority == ResourceData.REQUEST_PRIORITY_HIGHEST: |
| 43 priority_multiplier = 3 | 45 priority_multiplier = 3 |
| 44 elif resource.priority == ResourceData.REQUEST_PRIORITY_MEDIUM: | 46 elif resource.priority == ResourceData.REQUEST_PRIORITY_MEDIUM: |
| 45 priority_multiplier = 2 | 47 priority_multiplier = 2 |
| 46 | 48 |
| 47 if resource.resource_type in (ResourceData.RESOURCE_TYPE_STYLESHEET, | 49 if resource.resource_type in (ResourceData.RESOURCE_TYPE_STYLESHEET, |
| 48 ResourceData.RESOURCE_TYPE_SCRIPT): | 50 ResourceData.RESOURCE_TYPE_SCRIPT): |
| (...skipping 22 matching lines...) Expand all Loading... |
| 71 def PrettyPrintCandidates(self): | 73 def PrettyPrintCandidates(self): |
| 72 """Prints the candidates for prefetch.""" | 74 """Prints the candidates for prefetch.""" |
| 73 print 'primary_key: %s' % self.prefetch_data.primary_key | 75 print 'primary_key: %s' % self.prefetch_data.primary_key |
| 74 for resource in self.prefetch_data.resources: | 76 for resource in self.prefetch_data.resources: |
| 75 confidence = float(resource.number_of_hits) / ( | 77 confidence = float(resource.number_of_hits) / ( |
| 76 resource.number_of_hits + resource.number_of_misses) | 78 resource.number_of_hits + resource.number_of_misses) |
| 77 if resource.number_of_hits < 2 or confidence < .7: | 79 if resource.number_of_hits < 2 or confidence < .7: |
| 78 continue | 80 continue |
| 79 self._PrettyPrintResource(resource) | 81 self._PrettyPrintResource(resource) |
| 80 | 82 |
| 83 def DumpOriginDatabaseRow(domain, primary_key, proto): |
| 84 from resource_prefetch_predictor_pb2 import OriginData |
| 85 entry = OriginData() |
| 86 entry.ParseFromString(proto) |
| 87 # For the offset, see kWindowsEpochDeltaMicroseconds in |
| 88 # base/time/time_posix.cc. |
| 89 last_visit_timestamp = int(entry.last_visit_time / 1e6 - 11644473600) |
| 90 formatted_last_visit_time = datetime.datetime.utcfromtimestamp( |
| 91 last_visit_timestamp).strftime('%Y-%m-%d %H:%M:%S') |
| 92 print '''host: %s |
| 93 last_visit_time: %s |
| 94 origins:''' % (entry.host, formatted_last_visit_time) |
| 95 for origin_stat in entry.origins: |
| 96 print ''' origin: %s |
| 97 number_of_hits: %d |
| 98 number_of_misses: %d |
| 99 consecutive_misses: %d |
| 100 average_position: %f |
| 101 always_access_network: %s |
| 102 accessed_network: %s |
| 103 ''' % (origin_stat.origin, origin_stat.number_of_hits, |
| 104 origin_stat.number_of_misses, origin_stat.consecutive_misses, |
| 105 origin_stat.average_position, origin_stat.always_access_network, |
| 106 origin_stat.accessed_network) |
| 107 |
| 108 |
| 81 # The version of python sqlite3 library we have in Ubuntu 14.04 LTS doesn't | 109 # The version of python sqlite3 library we have in Ubuntu 14.04 LTS doesn't |
| 82 # support views but command line util does. | 110 # support views but command line util does. |
| 83 # TODO(alexilin): get rid of this when python sqlite3 adds view support. | 111 # TODO(alexilin): get rid of this when python sqlite3 adds view support. |
| 84 def CreateCompatibleDatabaseCopy(filename): | 112 def CreateCompatibleDatabaseCopy(filename): |
| 85 import tempfile, shutil, subprocess | 113 import tempfile, shutil, subprocess |
| 86 _, tmpfile = tempfile.mkstemp() | 114 _, tmpfile = tempfile.mkstemp() |
| 87 shutil.copy2(filename, tmpfile) | 115 shutil.copy2(filename, tmpfile) |
| 88 subprocess.call(['sqlite3', tmpfile, 'DROP VIEW MmapStatus']) | 116 subprocess.call(['sqlite3', tmpfile, 'DROP VIEW MmapStatus']) |
| 89 return tmpfile | 117 return tmpfile |
| 90 | 118 |
| 91 def DatabaseStats(filename, domain): | 119 def DatabaseStats(filename, host): |
| 120 query_template = 'SELECT key, proto from %s' |
| 92 connection = sqlite3.connect(filename) | 121 connection = sqlite3.connect(filename) |
| 93 c = connection.cursor() | 122 c = connection.cursor() |
| 94 query = ('SELECT key, proto FROM resource_prefetch_predictor_host') | 123 print 'HOST DATABASE' |
| 124 query = query_template % 'resource_prefetch_predictor_host' |
| 95 entries = [Entry.FromRow(row) for row in c.execute(query)] | 125 entries = [Entry.FromRow(row) for row in c.execute(query)] |
| 96 for x in entries: | 126 for x in entries: |
| 97 if domain is None or x.primary_key == domain: | 127 if host is None or x.primary_key == host: |
| 98 x.PrettyPrintCandidates() | 128 x.PrettyPrintCandidates() |
| 99 | 129 |
| 130 print '\n\nORIGIN DATABASE' |
| 131 query = query_template % 'resource_prefetch_predictor_origin' |
| 132 rows = [row for row in c.execute(query) |
| 133 if host is None or row.primary_key == host] |
| 134 for row in rows: |
| 135 DumpOriginDatabaseRow(host, *row) |
| 136 |
| 137 |
| 138 def _AddProtocolBuffersPath(build_dir): |
| 139 assert os.path.isdir(build_dir) |
| 140 proto_dir = os.path.join( |
| 141 build_dir, os.path.join('pyproto', 'chrome', 'browser', 'predictors')) |
| 142 sys.path.append(proto_dir) |
| 143 |
| 100 | 144 |
| 101 def main(): | 145 def main(): |
| 102 parser = argparse.ArgumentParser() | 146 parser = argparse.ArgumentParser() |
| 103 parser.add_argument('-f', dest='database_filename', required=True, | 147 parser.add_argument('-f', dest='database_filename', required=True, |
| 104 help='Path to the database') | 148 help='Path to the database') |
| 105 parser.add_argument('-d', dest='domain', default=None, help='Domain') | 149 parser.add_argument('-d', dest='domain', default=None, help='Domain') |
| 150 parser.add_argument('--build-dir', dest='build_dir', required=True, |
| 151 help='Path to the build directory.') |
| 106 args = parser.parse_args() | 152 args = parser.parse_args() |
| 153 _AddProtocolBuffersPath(args.build_dir) |
| 154 |
| 107 try: | 155 try: |
| 108 database_copy = CreateCompatibleDatabaseCopy(args.database_filename) | 156 database_copy = CreateCompatibleDatabaseCopy(args.database_filename) |
| 109 DatabaseStats(database_copy, args.domain) | 157 DatabaseStats(database_copy, args.domain) |
| 110 finally: | 158 finally: |
| 111 if os.path.exists(database_copy): | 159 if os.path.exists(database_copy): |
| 112 os.remove(database_copy) | 160 os.remove(database_copy) |
| 113 | 161 |
| 114 | 162 |
| 115 if __name__ == '__main__': | 163 if __name__ == '__main__': |
| 116 main() | 164 main() |
| OLD | NEW |