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