SamplingProfilerIntegration.java revision a9602db3d5a6c9bc5a7a31b4fe3cc141235ad332
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
19db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilsonimport android.content.pm.PackageInfo;
20db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilsonimport android.os.Build;
21db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilsonimport android.os.SystemProperties;
22db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilsonimport android.util.Log;
23a9602db3d5a6c9bc5a7a31b4fe3cc141235ad332Brian Carlstromimport dalvik.system.profiler.AsciiHprofWriter;
24a9602db3d5a6c9bc5a7a31b4fe3cc141235ad332Brian Carlstromimport dalvik.system.profiler.SamplingProfiler;
251751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstromimport java.io.BufferedOutputStream;
26e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.io.File;
27e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.io.FileOutputStream;
28e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.io.IOException;
291751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstromimport java.io.PrintStream;
30e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.util.concurrent.Executor;
31e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leeimport java.util.concurrent.Executors;
32def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstromimport java.util.concurrent.ThreadFactory;
33db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilsonimport java.util.concurrent.atomic.AtomicBoolean;
34db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilsonimport libcore.io.IoUtils;
35e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee
36e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee/**
37e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee * Integrates the framework with Dalvik's sampling profiler.
38e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee */
39e540833fdff4d58e37c9ba859388e24e2945ed45Bob Leepublic class SamplingProfilerIntegration {
40e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee
41e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    private static final String TAG = "SamplingProfilerIntegration";
42e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee
43bde75706592c77379fb6546283e733abaca6fe04Sen Hu    public static final String SNAPSHOT_DIR = "/data/snapshots";
44bde75706592c77379fb6546283e733abaca6fe04Sen Hu
45e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    private static final boolean enabled;
46e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    private static final Executor snapshotWriter;
47def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom    private static final int samplingProfilerMilliseconds;
48def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom    private static final int samplingProfilerDepth;
49bde75706592c77379fb6546283e733abaca6fe04Sen Hu
50bde75706592c77379fb6546283e733abaca6fe04Sen Hu    /** Whether or not a snapshot is being persisted. */
51bde75706592c77379fb6546283e733abaca6fe04Sen Hu    private static final AtomicBoolean pending = new AtomicBoolean(false);
52bde75706592c77379fb6546283e733abaca6fe04Sen Hu
53e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    static {
54def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom        samplingProfilerMilliseconds = SystemProperties.getInt("persist.sys.profiler_ms", 0);
55def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom        samplingProfilerDepth = SystemProperties.getInt("persist.sys.profiler_depth", 4);
56def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom        if (samplingProfilerMilliseconds > 0) {
57def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom            File dir = new File(SNAPSHOT_DIR);
58def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom            dir.mkdirs();
59def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom            // the directory needs to be writable to anybody to allow file writing
60def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom            dir.setWritable(true, false);
61def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom            // the directory needs to be executable to anybody to allow file creation
62def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom            dir.setExecutable(true, false);
63def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom            if (dir.isDirectory()) {
64def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                snapshotWriter = Executors.newSingleThreadExecutor(new ThreadFactory() {
65def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                        public Thread newThread(Runnable r) {
66def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                            return new Thread(r, TAG);
67def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                        }
68def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                    });
69def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                enabled = true;
70def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                Log.i(TAG, "Profiling enabled. Sampling interval ms: "
71def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                      + samplingProfilerMilliseconds);
72def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom            } else {
73def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                snapshotWriter = null;
74def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                enabled = true;
75def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                Log.w(TAG, "Profiling setup failed. Could not create " + SNAPSHOT_DIR);
76def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom            }
77e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee        } else {
78e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee            snapshotWriter = null;
79bde75706592c77379fb6546283e733abaca6fe04Sen Hu            enabled = false;
80def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom            Log.i(TAG, "Profiling disabled.");
81e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee        }
82e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    }
83e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee
841751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom    private static SamplingProfiler INSTANCE;
851751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom
86e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    /**
87e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee     * Is profiling enabled?
88e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee     */
89e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    public static boolean isEnabled() {
90e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee        return enabled;
91e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    }
92e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee
93e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    /**
94e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee     * Starts the profiler if profiling is enabled.
95e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee     */
96e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    public static void start() {
971751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        if (!enabled) {
981751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom            return;
991751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        }
1001751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        ThreadGroup group = Thread.currentThread().getThreadGroup();
1011751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        SamplingProfiler.ThreadSet threadSet = SamplingProfiler.newThreadGroupTheadSet(group);
102def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom        INSTANCE = new SamplingProfiler(samplingProfilerDepth, threadSet);
103def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom        INSTANCE.start(samplingProfilerMilliseconds);
104e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    }
105e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee
106e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    /**
107bde75706592c77379fb6546283e733abaca6fe04Sen Hu     * Writes a snapshot if profiling is enabled.
108e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee     */
109bde75706592c77379fb6546283e733abaca6fe04Sen Hu    public static void writeSnapshot(final String processName, final PackageInfo packageInfo) {
1101751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        if (!enabled) {
1111751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom            return;
1121751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        }
113e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee
114eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee        /*
115bde75706592c77379fb6546283e733abaca6fe04Sen Hu         * If we're already writing a snapshot, don't bother enqueueing another
116eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee         * request right now. This will reduce the number of individual
117eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee         * snapshots and in turn the total amount of memory consumed (one big
118eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee         * snapshot is smaller than N subset snapshots).
119eec2f41d607c3eacba4f7d9cc098b335c7310d23Bob Lee         */
120bde75706592c77379fb6546283e733abaca6fe04Sen Hu        if (pending.compareAndSet(false, true)) {
121e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee            snapshotWriter.execute(new Runnable() {
122e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee                public void run() {
123e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee                    try {
124def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom                        writeSnapshotFile(processName, packageInfo);
125e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee                    } finally {
126bde75706592c77379fb6546283e733abaca6fe04Sen Hu                        pending.set(false);
127e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee                    }
128e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee                }
129e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee            });
130e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee        }
131e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    }
132e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee
133e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    /**
134e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee     * Writes the zygote's snapshot to internal storage if profiling is enabled.
135e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee     */
136e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    public static void writeZygoteSnapshot() {
1371751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        if (!enabled) {
1381751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom            return;
1391751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        }
140def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom        writeSnapshotFile("zygote", null);
1411751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        INSTANCE.shutdown();
1421751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        INSTANCE = null;
143e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    }
144e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee
145bde75706592c77379fb6546283e733abaca6fe04Sen Hu    /**
146bde75706592c77379fb6546283e733abaca6fe04Sen Hu     * pass in PackageInfo to retrieve various values for snapshot header
147bde75706592c77379fb6546283e733abaca6fe04Sen Hu     */
148def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom    private static void writeSnapshotFile(String processName, PackageInfo packageInfo) {
1491751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        if (!enabled) {
150e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee            return;
151e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee        }
1521751086360056bc60d00f2ed2988bc82be9e7bd9Brian Carlstrom        INSTANCE.stop();
153e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee
154e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee        /*
155e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee         * We use the current time as a unique ID. We can't use a counter
156e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee         * because processes restart. This could result in some overlap if
157e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee         * we capture two snapshots in rapid succession.
158e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee         */
159e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee        long start = System.currentTimeMillis();
160bde75706592c77379fb6546283e733abaca6fe04Sen Hu        String name = processName.replaceAll(":", ".");
161def41ec2e88a70e63590117c93476276f8d0bf4cBrian Carlstrom        String path = SNAPSHOT_DIR + "/" + name + "-" +System.currentTimeMillis() + ".snapshot";
162c9ad7c6dbb1d70b831cd79416cbe493ade50ed2cBrian Carlstrom        PrintStream out = null;
163e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee        try {
164c9ad7c6dbb1d70b831cd79416cbe493ade50ed2cBrian Carlstrom            out = new PrintStream(new BufferedOutputStream(new FileOutputStream(path)));
165db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilson            generateSnapshotHeader(name, packageInfo, out);
166a9602db3d5a6c9bc5a7a31b4fe3cc141235ad332Brian Carlstrom            new AsciiHprofWriter(INSTANCE.getHprofData(), out).write();
167db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilson            if (out.checkError()) {
168db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilson                throw new IOException();
169db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilson            }
170bde75706592c77379fb6546283e733abaca6fe04Sen Hu        } catch (IOException e) {
171db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilson            Log.e(TAG, "Error writing snapshot to " + path, e);
172c9ad7c6dbb1d70b831cd79416cbe493ade50ed2cBrian Carlstrom            return;
173bde75706592c77379fb6546283e733abaca6fe04Sen Hu        } finally {
174db35269ae4e6a6572156e39557a993d5b730c167Jesse Wilson            IoUtils.closeQuietly(out);
175bde75706592c77379fb6546283e733abaca6fe04Sen Hu        }
176bde75706592c77379fb6546283e733abaca6fe04Sen Hu        // set file readable to the world so that SamplingProfilerService
177bde75706592c77379fb6546283e733abaca6fe04Sen Hu        // can put it to dropbox
178bde75706592c77379fb6546283e733abaca6fe04Sen Hu        new File(path).setReadable(true, false);
179e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee
180bde75706592c77379fb6546283e733abaca6fe04Sen Hu        long elapsed = System.currentTimeMillis() - start;
181bde75706592c77379fb6546283e733abaca6fe04Sen Hu        Log.i(TAG, "Wrote snapshot for " + name + " in " + elapsed + "ms.");
182bde75706592c77379fb6546283e733abaca6fe04Sen Hu    }
183bde75706592c77379fb6546283e733abaca6fe04Sen Hu
184bde75706592c77379fb6546283e733abaca6fe04Sen Hu    /**
185bde75706592c77379fb6546283e733abaca6fe04Sen Hu     * generate header for snapshots, with the following format (like http header):
186bde75706592c77379fb6546283e733abaca6fe04Sen Hu     *
187bde75706592c77379fb6546283e733abaca6fe04Sen Hu     * Version: <version number of profiler>\n
188bde75706592c77379fb6546283e733abaca6fe04Sen Hu     * Process: <process name>\n
189bde75706592c77379fb6546283e733abaca6fe04Sen Hu     * Package: <package name, if exists>\n
190bde75706592c77379fb6546283e733abaca6fe04Sen Hu     * Package-Version: <version number of the package, if exists>\n
191bde75706592c77379fb6546283e733abaca6fe04Sen Hu     * Build: <fingerprint>\n
192bde75706592c77379fb6546283e733abaca6fe04Sen Hu     * \n
193bde75706592c77379fb6546283e733abaca6fe04Sen Hu     * <the actual snapshot content begins here...>
194bde75706592c77379fb6546283e733abaca6fe04Sen Hu     */
195bde75706592c77379fb6546283e733abaca6fe04Sen Hu    private static void generateSnapshotHeader(String processName, PackageInfo packageInfo,
196c9ad7c6dbb1d70b831cd79416cbe493ade50ed2cBrian Carlstrom            PrintStream out) {
197bde75706592c77379fb6546283e733abaca6fe04Sen Hu        // profiler version
198c9ad7c6dbb1d70b831cd79416cbe493ade50ed2cBrian Carlstrom        out.println("Version: 2");
199c9ad7c6dbb1d70b831cd79416cbe493ade50ed2cBrian Carlstrom        out.println("Process: " + processName);
200c9ad7c6dbb1d70b831cd79416cbe493ade50ed2cBrian Carlstrom        if (packageInfo != null) {
201c9ad7c6dbb1d70b831cd79416cbe493ade50ed2cBrian Carlstrom            out.println("Package: " + packageInfo.packageName);
202c9ad7c6dbb1d70b831cd79416cbe493ade50ed2cBrian Carlstrom            out.println("Package-Version: " + packageInfo.versionCode);
203e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee        }
204c9ad7c6dbb1d70b831cd79416cbe493ade50ed2cBrian Carlstrom        out.println("Build: " + Build.FINGERPRINT);
205bde75706592c77379fb6546283e733abaca6fe04Sen Hu        // single blank line means the end of snapshot header.
206c9ad7c6dbb1d70b831cd79416cbe493ade50ed2cBrian Carlstrom        out.println();
207e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee    }
208e540833fdff4d58e37c9ba859388e24e2945ed45Bob Lee}
209