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