Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2012 The Chromium Authors. All rights reserved. | 1 # Copyright 2012 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 import os | 5 import os |
| 6 | 6 |
| 7 from telemetry import decorators | 7 from telemetry import decorators |
| 8 from telemetry.core import browser_credentials | 8 from telemetry.core import browser_credentials |
| 9 from telemetry.core import exceptions | 9 from telemetry.core import exceptions |
| 10 from telemetry.core import extension_dict | 10 from telemetry.core import extension_dict |
| 11 from telemetry.core import local_server | 11 from telemetry.core import local_server |
| 12 from telemetry.core import memory_cache_http_server | 12 from telemetry.core import memory_cache_http_server |
| 13 from telemetry.core import platform | 13 from telemetry.core import platform as platform_module |
| 14 from telemetry.core import tab_list | 14 from telemetry.core import tab_list |
| 15 from telemetry.core import wpr_modes | 15 from telemetry.core import wpr_modes |
| 16 from telemetry.core import wpr_server | 16 from telemetry.core import wpr_server |
| 17 from telemetry.core.backends import browser_backend | 17 from telemetry.core.backends import browser_backend |
| 18 from telemetry.core.platform.profiler import profiler_finder | 18 from telemetry.core.platform.profiler import profiler_finder |
| 19 | 19 |
| 20 | 20 |
| 21 class Browser(object): | 21 class Browser(object): |
| 22 """A running browser instance that can be controlled in a limited way. | 22 """A running browser instance that can be controlled in a limited way. |
| 23 | 23 |
| 24 To create a browser instance, use browser_finder.FindBrowser. | 24 To create a browser instance, use browser_finder.FindBrowser. |
| 25 | 25 |
| 26 Be sure to clean up after yourself by calling Close() when you are done with | 26 Be sure to clean up after yourself by calling Close() when you are done with |
| 27 the browser. Or better yet: | 27 the browser. Or better yet: |
| 28 browser_to_create = FindBrowser(options) | 28 browser_to_create = FindBrowser(options) |
| 29 with browser_to_create.Create() as browser: | 29 with browser_to_create.Create() as browser: |
| 30 ... do all your operations on browser here | 30 ... do all your operations on browser here |
| 31 """ | 31 """ |
| 32 def __init__(self, backend, platform_backend): | 32 def __init__(self, backend, platform): |
| 33 assert isinstance(platform, platform_module.Platform) | |
| 33 self._browser_backend = backend | 34 self._browser_backend = backend |
| 34 self._http_server = None | 35 self._http_server = None |
| 35 self._wpr_server = None | 36 self._wpr_server = None |
| 36 self._platform_backend = platform_backend | 37 self._platform = platform |
| 37 self._platform = platform.Platform(platform_backend) | |
| 38 self._active_profilers = [] | 38 self._active_profilers = [] |
| 39 self._profilers_states = {} | 39 self._profilers_states = {} |
| 40 self._local_server_controller = local_server.LocalServerController(backend) | 40 self._local_server_controller = local_server.LocalServerController(backend) |
| 41 self._tabs = tab_list.TabList(backend.tab_list_backend) | 41 self._tabs = tab_list.TabList(backend.tab_list_backend) |
| 42 self.credentials = browser_credentials.BrowserCredentials() | 42 self.credentials = browser_credentials.BrowserCredentials() |
| 43 self._platform.SetFullPerformanceModeEnabled(True) | 43 self._platform.SetFullPerformanceModeEnabled(True) |
| 44 | 44 |
| 45 def __enter__(self): | 45 def __enter__(self): |
| 46 self.Start() | 46 self.Start() |
| 47 return self | 47 return self |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 return extension_dict.ExtensionDict(self._browser_backend.extension_backend) | 94 return extension_dict.ExtensionDict(self._browser_backend.extension_backend) |
| 95 | 95 |
| 96 @property | 96 @property |
| 97 def supports_tracing(self): | 97 def supports_tracing(self): |
| 98 return self._browser_backend.supports_tracing | 98 return self._browser_backend.supports_tracing |
| 99 | 99 |
| 100 def is_profiler_active(self, profiler_name): | 100 def is_profiler_active(self, profiler_name): |
| 101 return profiler_name in [profiler.name() for | 101 return profiler_name in [profiler.name() for |
| 102 profiler in self._active_profilers] | 102 profiler in self._active_profilers] |
| 103 | 103 |
| 104 | |
| 104 def _GetStatsCommon(self, pid_stats_function): | 105 def _GetStatsCommon(self, pid_stats_function): |
| 105 browser_pid = self._browser_backend.pid | 106 browser_pid = self._browser_backend.pid |
| 106 result = { | 107 result = { |
| 107 'Browser': dict(pid_stats_function(browser_pid), **{'ProcessCount': 1}), | 108 'Browser': dict(pid_stats_function(browser_pid), **{'ProcessCount': 1}), |
| 108 'Renderer': {'ProcessCount': 0}, | 109 'Renderer': {'ProcessCount': 0}, |
| 109 'Gpu': {'ProcessCount': 0}, | 110 'Gpu': {'ProcessCount': 0}, |
| 110 'Other': {'ProcessCount': 0} | 111 'Other': {'ProcessCount': 0} |
| 111 } | 112 } |
| 112 process_count = 1 | 113 process_count = 1 |
| 113 for child_pid in self._platform_backend.GetChildPids(browser_pid): | 114 for child_pid in self._platform.GetChildPids(browser_pid): |
| 114 try: | 115 try: |
| 115 child_cmd_line = self._platform_backend.GetCommandLine(child_pid) | 116 child_cmd_line = self._platform.GetCommandLine(child_pid) |
| 116 child_stats = pid_stats_function(child_pid) | 117 child_stats = pid_stats_function(child_pid) |
| 117 except exceptions.ProcessGoneException: | 118 except exceptions.ProcessGoneException: |
| 118 # It is perfectly fine for a process to have gone away between calling | 119 # It is perfectly fine for a process to have gone away between calling |
| 119 # GetChildPids() and then further examining it. | 120 # GetChildPids() and then further examining it. |
| 120 continue | 121 continue |
| 121 child_process_name = self._browser_backend.GetProcessName(child_cmd_line) | 122 child_process_name = self._browser_backend.GetProcessName(child_cmd_line) |
| 122 process_name_type_key_map = {'gpu-process': 'Gpu', 'renderer': 'Renderer'} | 123 process_name_type_key_map = {'gpu-process': 'Gpu', 'renderer': 'Renderer'} |
| 123 if child_process_name in process_name_type_key_map: | 124 if child_process_name in process_name_type_key_map: |
| 124 child_process_type_key = process_name_type_key_map[child_process_name] | 125 child_process_type_key = process_name_type_key_map[child_process_name] |
| 125 else: | 126 else: |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 'WorkingSetSizePeak': U, | 169 'WorkingSetSizePeak': U, |
| 169 'ProportionalSetSize': V, | 170 'ProportionalSetSize': V, |
| 170 'PrivateDirty': W | 171 'PrivateDirty': W |
| 171 }, | 172 }, |
| 172 'SystemCommitCharge': X, | 173 'SystemCommitCharge': X, |
| 173 'SystemTotalPhysicalMemory': Y, | 174 'SystemTotalPhysicalMemory': Y, |
| 174 'ProcessCount': Z, | 175 'ProcessCount': Z, |
| 175 } | 176 } |
| 176 Any of the above keys may be missing on a per-platform basis. | 177 Any of the above keys may be missing on a per-platform basis. |
| 177 """ | 178 """ |
| 178 self._platform_backend.PurgeUnpinnedMemory() | 179 self._platform.WillGetMemoryStats() |
| 179 result = self._GetStatsCommon(self._platform_backend.GetMemoryStats) | 180 result = self._GetStatsCommon(self._platform.GetMemoryStats) |
| 180 result['SystemCommitCharge'] = \ | 181 result['SystemCommitCharge'] = \ |
| 181 self._platform_backend.GetSystemCommitCharge() | 182 self._platform.GetSystemCommitCharge() |
| 182 result['SystemTotalPhysicalMemory'] = \ | 183 result['SystemTotalPhysicalMemory'] = \ |
| 183 self._platform_backend.GetSystemTotalPhysicalMemory() | 184 self._platform.GetSystemTotalPhysicalMemory() |
| 184 return result | 185 return result |
| 185 | 186 |
| 187 | |
| 186 @property | 188 @property |
| 187 def cpu_stats(self): | 189 def cpu_stats(self): |
|
tonyg
2014/08/02 15:58:18
I think the root of the problem here is that these
| |
| 188 """Returns a dict of cpu statistics for the system. | 190 """Returns a dict of cpu statistics for the system. |
| 189 { 'Browser': { | 191 { 'Browser': { |
| 190 'CpuProcessTime': S, | 192 'CpuProcessTime': S, |
| 191 'TotalTime': T | 193 'TotalTime': T |
| 192 }, | 194 }, |
| 193 'Gpu': { | 195 'Gpu': { |
| 194 'CpuProcessTime': S, | 196 'CpuProcessTime': S, |
| 195 'TotalTime': T | 197 'TotalTime': T |
| 196 }, | 198 }, |
| 197 'Renderer': { | 199 'Renderer': { |
| 198 'CpuProcessTime': S, | 200 'CpuProcessTime': S, |
| 199 'TotalTime': T | 201 'TotalTime': T |
| 200 } | 202 } |
| 201 } | 203 } |
| 202 Any of the above keys may be missing on a per-platform basis. | 204 Any of the above keys may be missing on a per-platform basis. |
| 203 """ | 205 """ |
| 204 result = self._GetStatsCommon(self._platform_backend.GetCpuStats) | 206 result = self._GetStatsCommon(self._platform.GetCpuStats) |
| 205 del result['ProcessCount'] | 207 del result['ProcessCount'] |
| 206 | 208 |
| 207 # We want a single time value, not the sum for all processes. | 209 # We want a single time value, not the sum for all processes. |
| 208 cpu_timestamp = self._platform_backend.GetCpuTimestamp() | 210 cpu_timestamp = self._platform.GetCpuTimestamp() |
| 209 for process_type in result: | 211 for process_type in result: |
| 210 # Skip any process_types that are empty | 212 # Skip any process_types that are empty |
| 211 if not len(result[process_type]): | 213 if not len(result[process_type]): |
| 212 continue | 214 continue |
| 213 result[process_type].update(cpu_timestamp) | 215 result[process_type].update(cpu_timestamp) |
| 214 return result | 216 return result |
| 215 | 217 |
| 216 @property | 218 @property |
| 217 def io_stats(self): | 219 def io_stats(self): |
| 218 """Returns a dict of IO statistics for the browser: | 220 """Returns a dict of IO statistics for the browser: |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 229 'WriteTransferCount': Z | 231 'WriteTransferCount': Z |
| 230 }, | 232 }, |
| 231 'Renderer': { | 233 'Renderer': { |
| 232 'ReadOperationCount': W, | 234 'ReadOperationCount': W, |
| 233 'WriteOperationCount': X, | 235 'WriteOperationCount': X, |
| 234 'ReadTransferCount': Y, | 236 'ReadTransferCount': Y, |
| 235 'WriteTransferCount': Z | 237 'WriteTransferCount': Z |
| 236 } | 238 } |
| 237 } | 239 } |
| 238 """ | 240 """ |
| 239 result = self._GetStatsCommon(self._platform_backend.GetIOStats) | 241 result = self._GetStatsCommon(self._platform.GetIOStats) |
| 240 del result['ProcessCount'] | 242 del result['ProcessCount'] |
| 241 return result | 243 return result |
| 242 | 244 |
| 243 def StartProfiling(self, profiler_name, base_output_file): | 245 def StartProfiling(self, profiler_name, base_output_file): |
| 244 """Starts profiling using |profiler_name|. Results are saved to | 246 """Starts profiling using |profiler_name|. Results are saved to |
| 245 |base_output_file|.<process_name>.""" | 247 |base_output_file|.<process_name>.""" |
| 246 assert not self._active_profilers, 'Already profiling. Must stop first.' | 248 assert not self._active_profilers, 'Already profiling. Must stop first.' |
| 247 | 249 |
| 248 profiler_class = profiler_finder.FindProfiler(profiler_name) | 250 profiler_class = profiler_finder.FindProfiler(profiler_name) |
| 249 | 251 |
| 250 if not profiler_class.is_supported(self._browser_backend.browser_type): | 252 if not profiler_class.is_supported(self._browser_backend.browser_type): |
| 251 raise Exception('The %s profiler is not ' | 253 raise Exception('The %s profiler is not ' |
| 252 'supported on this platform.' % profiler_name) | 254 'supported on this platform.' % profiler_name) |
| 253 | 255 |
| 254 if not profiler_class in self._profilers_states: | 256 if not profiler_class in self._profilers_states: |
| 255 self._profilers_states[profiler_class] = {} | 257 self._profilers_states[profiler_class] = {} |
| 256 | 258 |
| 257 self._active_profilers.append( | 259 profiler = self.platform.InstantiateProfiler( |
| 258 profiler_class(self._browser_backend, self._platform_backend, | 260 profiler_class, |
| 259 base_output_file, self._profilers_states[profiler_class])) | 261 self._browser_backend, |
| 262 base_output_file, | |
| 263 self._profilers_states[profiler_class]) | |
| 264 self._active_profilers.append(profiler) | |
| 260 | 265 |
| 261 def StopProfiling(self): | 266 def StopProfiling(self): |
| 262 """Stops all active profilers and saves their results. | 267 """Stops all active profilers and saves their results. |
| 263 | 268 |
| 264 Returns: | 269 Returns: |
| 265 A list of filenames produced by the profiler. | 270 A list of filenames produced by the profiler. |
| 266 """ | 271 """ |
| 267 output_files = [] | 272 output_files = [] |
| 268 for profiler in self._active_profilers: | 273 for profiler in self._active_profilers: |
| 269 output_files.extend(profiler.CollectProfile()) | 274 output_files.extend(profiler.CollectProfile()) |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 291 self.platform.FlushSystemCacheForDirectory( | 296 self.platform.FlushSystemCacheForDirectory( |
| 292 self._browser_backend.browser_directory) | 297 self._browser_backend.browser_directory) |
| 293 else: | 298 else: |
| 294 self.platform.FlushEntireSystemCache() | 299 self.platform.FlushEntireSystemCache() |
| 295 | 300 |
| 296 self._browser_backend.SetBrowser(self) | 301 self._browser_backend.SetBrowser(self) |
| 297 self._browser_backend.Start() | 302 self._browser_backend.Start() |
| 298 | 303 |
| 299 def Close(self): | 304 def Close(self): |
| 300 """Closes this browser.""" | 305 """Closes this browser.""" |
| 301 for profiler_class in self._profilers_states: | 306 profiler_classes = list(self._profilers_states.keys()) |
| 302 profiler_class.WillCloseBrowser(self._browser_backend, | 307 self._platform.WillCloseBrowser(self._browser_backend, |
| 303 self._platform_backend) | 308 profiler_classes) |
| 304 | 309 |
| 305 self.platform.SetFullPerformanceModeEnabled(False) | 310 self.platform.SetFullPerformanceModeEnabled(False) |
| 306 | 311 |
| 307 if self._wpr_server: | 312 if self._wpr_server: |
| 308 self._wpr_server.Close() | 313 self._wpr_server.Close() |
| 309 self._wpr_server = None | 314 self._wpr_server = None |
| 310 | 315 |
| 311 if self._http_server: | 316 if self._http_server: |
| 312 self._http_server.Close() | 317 self._http_server.Close() |
| 313 self._http_server = None | 318 self._http_server = None |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 393 | 398 |
| 394 @property | 399 @property |
| 395 def supports_system_info(self): | 400 def supports_system_info(self): |
| 396 return self._browser_backend.supports_system_info | 401 return self._browser_backend.supports_system_info |
| 397 | 402 |
| 398 def GetSystemInfo(self): | 403 def GetSystemInfo(self): |
| 399 """Returns low-level information about the system, if available. | 404 """Returns low-level information about the system, if available. |
| 400 | 405 |
| 401 See the documentation of the SystemInfo class for more details.""" | 406 See the documentation of the SystemInfo class for more details.""" |
| 402 return self._browser_backend.GetSystemInfo() | 407 return self._browser_backend.GetSystemInfo() |
| OLD | NEW |