SamplingProfilerIntegration.java revision eec2f41d607c3eacba4f7d9cc098b335c7310d23
1e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leepackage com.android.internal.os; 2e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 3e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport dalvik.system.SamplingProfiler; 4e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 5e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.io.File; 6e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.io.FileOutputStream; 7e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.io.IOException; 8e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.io.FileNotFoundException; 9e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.util.concurrent.Executor; 10e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.util.concurrent.Executors; 11e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 12e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport android.util.Log; 13e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport android.os.*; 14e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 15e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee/** 16e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * Integrates the framework with Dalvik's sampling profiler. 17e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 18e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leepublic class SamplingProfilerIntegration { 19e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 20e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee private static final String TAG = "SamplingProfilerIntegration"; 21e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 22e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee private static final boolean enabled; 23e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee private static final Executor snapshotWriter; 24e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee static { 25e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee enabled = "1".equals(SystemProperties.get("persist.sampling_profiler")); 26e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee if (enabled) { 27e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee snapshotWriter = Executors.newSingleThreadExecutor(); 28e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee Log.i(TAG, "Profiler is enabled."); 29e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } else { 30e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee snapshotWriter = null; 31e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee Log.i(TAG, "Profiler is disabled."); 32e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 33e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 34e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 35e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** 36e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * Is profiling enabled? 37e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 38e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee public static boolean isEnabled() { 39e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee return enabled; 40e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 41e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 42e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** 43e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * Starts the profiler if profiling is enabled. 44e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 45e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee public static void start() { 46e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee if (!enabled) return; 47e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee SamplingProfiler.getInstance().start(10); 48e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 49e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 50e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** Whether or not we've created the snapshots dir. */ 51e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee static boolean dirMade = false; 52e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 53e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** Whether or not a snapshot is being persisted. */ 54e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee static volatile boolean pending; 55e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 56e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** 57e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * Writes a snapshot to the SD card if profiling is enabled. 58e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 59e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee public static void writeSnapshot(final String name) { 60e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee if (!enabled) return; 61e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 62eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee /* 63eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee * If we're already writing a snapshot, don't bother enqueing another 64eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee * request right now. This will reduce the number of individual 65eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee * snapshots and in turn the total amount of memory consumed (one big 66eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee * snapshot is smaller than N subset snapshots). 67eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee */ 68e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee if (!pending) { 69e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee pending = true; 70e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee snapshotWriter.execute(new Runnable() { 71e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee public void run() { 72e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee String dir = "/sdcard/snapshots"; 73e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee if (!dirMade) { 74eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee new File(dir).mkdirs(); 75eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee if (new File(dir).isDirectory()) { 76eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee dirMade = true; 77eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee } else { 78eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee Log.w(TAG, "Creation of " + dir + " failed."); 79eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee return; 80eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee } 81e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 82e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee try { 83e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee writeSnapshot(dir, name); 84e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } finally { 85e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee pending = false; 86e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 87e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 88e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee }); 89e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 90e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 91e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 92e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** 93e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * Writes the zygote's snapshot to internal storage if profiling is enabled. 94e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 95e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee public static void writeZygoteSnapshot() { 96e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee if (!enabled) return; 97e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 98e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee String dir = "/data/zygote/snapshots"; 99eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee new File(dir).mkdirs(); 100e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee writeSnapshot(dir, "zygote"); 101e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 102e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 103e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee private static void writeSnapshot(String dir, String name) { 104e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee byte[] snapshot = SamplingProfiler.getInstance().snapshot(); 105e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee if (snapshot == null) { 106e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee return; 107e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 108e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 109e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /* 110e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * We use the current time as a unique ID. We can't use a counter 111e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * because processes restart. This could result in some overlap if 112e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * we capture two snapshots in rapid succession. 113e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 114e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee long start = System.currentTimeMillis(); 115eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee String path = dir + "/" + name.replace(':', '.') + "-" + 116e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee + System.currentTimeMillis() + ".snapshot"; 117e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee try { 118e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee // Try to open the file a few times. The SD card may not be mounted. 119e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee FileOutputStream out; 120e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee int count = 0; 121e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee while (true) { 122e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee try { 123e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee out = new FileOutputStream(path); 124e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee break; 125e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } catch (FileNotFoundException e) { 126e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee if (++count > 3) { 127e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee Log.e(TAG, "Could not open " + path + "."); 128e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee return; 129e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 130eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee 131e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee // Sleep for a bit and then try again. 132e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee try { 133e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee Thread.sleep(2500); 134e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } catch (InterruptedException e1) { /* ignore */ } 135e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 136e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 137e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 138e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee try { 139e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee out.write(snapshot); 140e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } finally { 141e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee out.close(); 142e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 143e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee long elapsed = System.currentTimeMillis() - start; 144e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee Log.i(TAG, "Wrote snapshot for " + name 145e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee + " in " + elapsed + "ms."); 146e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } catch (IOException e) { 147e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee Log.e(TAG, "Error writing snapshot.", e); 148e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 149e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 150e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee} 151