java_heap_profiler.py revision 1e9bf3e0803691d0a228da41fc608347b6db4340
1# Copyright (c) 2013 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import os 6import subprocess 7import threading 8 9from telemetry.core import util 10from telemetry.core.backends.chrome import android_browser_finder 11from telemetry.core.platform import profiler 12 13class JavaHeapProfiler(profiler.Profiler): 14 """Android-specific, trigger and fetch java heap dumps.""" 15 16 _DEFAULT_DEVICE_DIR = '/data/local/tmp/javaheap' 17 # TODO(bulach): expose this as a command line option somehow. 18 _DEFAULT_INTERVAL = 20 19 def __init__(self, browser_backend, platform_backend, output_path, state): 20 super(JavaHeapProfiler, self).__init__( 21 browser_backend, platform_backend, output_path, state) 22 self._run_count = 1 23 24 self._DumpJavaHeap(False) 25 26 self._timer = threading.Timer(self._DEFAULT_INTERVAL, self._OnTimer) 27 self._timer.start() 28 29 @classmethod 30 def name(cls): 31 return 'java-heap' 32 33 @classmethod 34 def is_supported(cls, browser_type): 35 if browser_type == 'any': 36 return android_browser_finder.CanFindAvailableBrowsers() 37 return browser_type.startswith('android') 38 39 def CollectProfile(self): 40 self._timer.cancel() 41 self._DumpJavaHeap(True) 42 self._browser_backend.adb.Adb().Adb().Pull( 43 self._DEFAULT_DEVICE_DIR, self._output_path) 44 self._browser_backend.adb.RunShellCommand( 45 'rm ' + os.path.join(self._DEFAULT_DEVICE_DIR, '*')) 46 output_files = [] 47 for f in os.listdir(self._output_path): 48 if os.path.splitext(f)[1] == '.aprof': 49 input_file = os.path.join(self._output_path, f) 50 output_file = input_file.replace('.aprof', '.hprof') 51 subprocess.call(['hprof-conv', input_file, output_file]) 52 output_files.append(output_file) 53 return output_files 54 55 def _OnTimer(self): 56 self._DumpJavaHeap(False) 57 58 def _DumpJavaHeap(self, wait_for_completion): 59 if not self._browser_backend.adb.Adb().FileExistsOnDevice( 60 self._DEFAULT_DEVICE_DIR): 61 self._browser_backend.adb.RunShellCommand( 62 'mkdir -p ' + self._DEFAULT_DEVICE_DIR) 63 self._browser_backend.adb.RunShellCommand( 64 'chmod 777 ' + self._DEFAULT_DEVICE_DIR) 65 66 device_dump_file = None 67 for pid in self._GetProcessOutputFileMap().iterkeys(): 68 device_dump_file = '%s/%s.%s.aprof' % (self._DEFAULT_DEVICE_DIR, pid, 69 self._run_count) 70 self._browser_backend.adb.RunShellCommand('am dumpheap %s %s' % 71 (pid, device_dump_file)) 72 if device_dump_file and wait_for_completion: 73 util.WaitFor(lambda: self._FileSize(device_dump_file) > 0, timeout=2) 74 self._run_count += 1 75 76 def _FileSize(self, file_name): 77 f = self._browser_backend.adb.Adb().ListPathContents(file_name) 78 return f.get(os.path.basename(file_name), (0, ))[0] 79