SamplingProfilerIntegration.java revision 1751086360056bc60d00f2ed2988bc82be9e7bd9
115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root/* 215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Copyright (C) 2009 The Android Open Source Project 315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * 415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * you may not use this file except in compliance with the License. 615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * You may obtain a copy of the License at 715a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * 815a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * http://www.apache.org/licenses/LICENSE-2.0 915a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * 1015a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * Unless required by applicable law or agreed to in writing, software 1115a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * distributed under the License is distributed on an "AS IS" BASIS, 1215a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1315a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * See the License for the specific language governing permissions and 1415a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root * limitations under the License. 1515a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root */ 1615a4d2ffd04dc6c70f2cd17dae12ac6bc14c69abKenny Root 17e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leepackage com.android.internal.os; 18e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 19e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport dalvik.system.SamplingProfiler; 20e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 211751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstromimport java.io.BufferedOutputStream; 22e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.io.File; 231751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstromimport java.io.FileNotFoundException; 24e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.io.FileOutputStream; 25e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.io.IOException; 261751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstromimport java.io.PrintStream; 27e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.util.concurrent.Executor; 28e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.util.concurrent.Executors; 29e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 30e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport android.util.Log; 31e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport android.os.*; 32e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 33e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee/** 34e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * Integrates the framework with Dalvik's sampling profiler. 35e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 36e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leepublic class SamplingProfilerIntegration { 37e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 38e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee private static final String TAG = "SamplingProfilerIntegration"; 39e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 40e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee private static final boolean enabled; 41e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee private static final Executor snapshotWriter; 42e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee static { 43e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee enabled = "1".equals(SystemProperties.get("persist.sampling_profiler")); 44e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee if (enabled) { 45e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee snapshotWriter = Executors.newSingleThreadExecutor(); 46e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee Log.i(TAG, "Profiler is enabled."); 47e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } else { 48e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee snapshotWriter = null; 49e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee Log.i(TAG, "Profiler is disabled."); 50e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 51e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 52e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 531751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom private static SamplingProfiler INSTANCE; 541751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom 55e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** 56e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * Is profiling enabled? 57e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 58e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee public static boolean isEnabled() { 59e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee return enabled; 60e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 61e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 62e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** 63e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * Starts the profiler if profiling is enabled. 64e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 65e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee public static void start() { 661751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom if (!enabled) { 671751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom return; 681751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom } 691751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom ThreadGroup group = Thread.currentThread().getThreadGroup(); 701751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom SamplingProfiler.ThreadSet threadSet = SamplingProfiler.newThreadGroupTheadSet(group); 711751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom INSTANCE = new SamplingProfiler(4, threadSet); 721751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom INSTANCE.start(10); 73e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 74e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 75e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** Whether or not we've created the snapshots dir. */ 76e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee static boolean dirMade = false; 77e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 78e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** Whether or not a snapshot is being persisted. */ 79e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee static volatile boolean pending; 80e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 81e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** 82e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * Writes a snapshot to the SD card if profiling is enabled. 83e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 84e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee public static void writeSnapshot(final String name) { 851751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom if (!enabled) { 861751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom return; 871751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom } 88e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 89eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee /* 90eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee * If we're already writing a snapshot, don't bother enqueing another 91eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee * request right now. This will reduce the number of individual 92eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee * snapshots and in turn the total amount of memory consumed (one big 93eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee * snapshot is smaller than N subset snapshots). 94eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee */ 95e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee if (!pending) { 96e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee pending = true; 97e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee snapshotWriter.execute(new Runnable() { 98e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee public void run() { 99e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee String dir = "/sdcard/snapshots"; 100e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee if (!dirMade) { 101eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee new File(dir).mkdirs(); 102eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee if (new File(dir).isDirectory()) { 103eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee dirMade = true; 104eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee } else { 105eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee Log.w(TAG, "Creation of " + dir + " failed."); 106eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee return; 107eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee } 108e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 109e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee try { 110e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee writeSnapshot(dir, name); 111e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } finally { 112e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee pending = false; 113e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 114e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 115e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee }); 116e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 117e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 118e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 119e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /** 120e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * Writes the zygote's snapshot to internal storage if profiling is enabled. 121e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 122e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee public static void writeZygoteSnapshot() { 1231751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom if (!enabled) { 1241751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom return; 1251751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom } 126e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 127e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee String dir = "/data/zygote/snapshots"; 128eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee new File(dir).mkdirs(); 129e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee writeSnapshot(dir, "zygote"); 1301751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom INSTANCE.shutdown(); 1311751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom INSTANCE = null; 132e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 133e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 134e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee private static void writeSnapshot(String dir, String name) { 1351751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom if (!enabled) { 136e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee return; 137e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 1381751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom INSTANCE.stop(); 139e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 140e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee /* 141e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * We use the current time as a unique ID. We can't use a counter 142e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * because processes restart. This could result in some overlap if 143e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * we capture two snapshots in rapid succession. 144e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */ 145e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee long start = System.currentTimeMillis(); 1461751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom String path = dir + "/" + name.replace(':', '.') + "-" 147e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee + System.currentTimeMillis() + ".snapshot"; 148eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee 1491751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom // Try to open the file a few times. The SD card may not be mounted. 1501751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom PrintStream out; 1511751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom int count = 0; 1521751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom while (true) { 1531751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom try { 1541751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom out = new PrintStream(new BufferedOutputStream(new FileOutputStream(path))); 1551751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom break; 1561751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom } catch (FileNotFoundException e) { 1571751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom if (++count > 3) { 1581751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom Log.e(TAG, "Could not open " + path + "."); 1591751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom return; 160e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 161e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee 1621751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom // Sleep for a bit and then try again. 1631751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom try { 1641751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom Thread.sleep(2500); 1651751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom } catch (InterruptedException e1) { /* ignore */ } 166e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 1671751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom } 1681751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom 1691751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom try { 1701751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom INSTANCE.writeHprofData(out); 1711751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom } finally { 1721751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom out.close(); 1731751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom } 1741751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom if (out.checkError()) { 1751751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom Log.e(TAG, "Error writing snapshot."); 1761751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom } else { 177e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee long elapsed = System.currentTimeMillis() - start; 178e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee Log.i(TAG, "Wrote snapshot for " + name 1791751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom + " in " + elapsed + "ms."); 180e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 181e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee } 182e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee} 183