Resurrect SamplingProfilerIntegration

1.) Change from samples per second (persist.sys.profiler_hz) to
    interval between samples (persist.sys.profiler_ms) to match
    underlying SamplingProfiler API.  This allows samples to be taken
    less often than a second, which allows lower overhead for always
    on profiling.

2.) Add persist.sys.profiler_depth to control the number of frames
    kept. Currently defaults to 4 which is the default hprof depth,
    but often 12 is necessary even in benchmarks to get a good idea
    where time is being spent.

3.) Moved SNAPSHOT_DIR creation to initialization time instead of
    checking it on every sample.

4.) Used ThreadFactory to provide human readable name to writeSnapshot
    Executor thread.

5.) Fixed bug where writeZygoteSnapshot was calling wrong variant of
    writeSnapshot causing profiling to prevent zygote startup. Renamed
    underling private writeSnapshot to writeSnapshotFile to try to
    prevent future confusion.

Change-Id: Ifcfc343816b19f13a6eef2cbf25cde334d8adc3b
This commit is contained in:
Brian Carlstrom
2010-12-01 15:40:38 -08:00
parent 4449e4b6e2
commit def41ec2e8

View File

@ -27,6 +27,7 @@ import java.io.PrintStream;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.ThreadFactory;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.util.Log; import android.util.Log;
@ -43,27 +44,40 @@ public class SamplingProfilerIntegration {
private static final boolean enabled; private static final boolean enabled;
private static final Executor snapshotWriter; private static final Executor snapshotWriter;
private static final int samplingProfilerHz; private static final int samplingProfilerMilliseconds;
private static final int samplingProfilerDepth;
/** Whether or not we've created the snapshots dir. */
private static boolean dirMade = false;
/** Whether or not a snapshot is being persisted. */ /** Whether or not a snapshot is being persisted. */
private static final AtomicBoolean pending = new AtomicBoolean(false); private static final AtomicBoolean pending = new AtomicBoolean(false);
static { static {
samplingProfilerHz = SystemProperties.getInt("persist.sys.profiler_hz", 0); samplingProfilerMilliseconds = SystemProperties.getInt("persist.sys.profiler_ms", 0);
// Disabling this for now, as it crashes when enabled server-side. So adding samplingProfilerDepth = SystemProperties.getInt("persist.sys.profiler_depth", 4);
// a new property ("REALLY") for those wanting to test and fix it. if (samplingProfilerMilliseconds > 0) {
boolean really = SystemProperties.getInt("persist.sys.profiler_hz_REALLY", 0) > 0; File dir = new File(SNAPSHOT_DIR);
if (samplingProfilerHz > 0 && really) { dir.mkdirs();
snapshotWriter = Executors.newSingleThreadExecutor(); // the directory needs to be writable to anybody to allow file writing
enabled = true; dir.setWritable(true, false);
Log.i(TAG, "Profiler is enabled. Sampling Profiler Hz: " + samplingProfilerHz); // the directory needs to be executable to anybody to allow file creation
dir.setExecutable(true, false);
if (dir.isDirectory()) {
snapshotWriter = Executors.newSingleThreadExecutor(new ThreadFactory() {
public Thread newThread(Runnable r) {
return new Thread(r, TAG);
}
});
enabled = true;
Log.i(TAG, "Profiling enabled. Sampling interval ms: "
+ samplingProfilerMilliseconds);
} else {
snapshotWriter = null;
enabled = true;
Log.w(TAG, "Profiling setup failed. Could not create " + SNAPSHOT_DIR);
}
} else { } else {
snapshotWriter = null; snapshotWriter = null;
enabled = false; enabled = false;
Log.i(TAG, "Profiler is disabled."); Log.i(TAG, "Profiling disabled.");
} }
} }
@ -85,8 +99,8 @@ public class SamplingProfilerIntegration {
} }
ThreadGroup group = Thread.currentThread().getThreadGroup(); ThreadGroup group = Thread.currentThread().getThreadGroup();
SamplingProfiler.ThreadSet threadSet = SamplingProfiler.newThreadGroupTheadSet(group); SamplingProfiler.ThreadSet threadSet = SamplingProfiler.newThreadGroupTheadSet(group);
INSTANCE = new SamplingProfiler(4, threadSet); // TODO parameter for depth INSTANCE = new SamplingProfiler(samplingProfilerDepth, threadSet);
INSTANCE.start(1000/samplingProfilerHz); INSTANCE.start(samplingProfilerMilliseconds);
} }
/** /**
@ -106,25 +120,8 @@ public class SamplingProfilerIntegration {
if (pending.compareAndSet(false, true)) { if (pending.compareAndSet(false, true)) {
snapshotWriter.execute(new Runnable() { snapshotWriter.execute(new Runnable() {
public void run() { public void run() {
if (!dirMade) {
File dir = new File(SNAPSHOT_DIR);
dir.mkdirs();
// the directory needs to be writable to anybody
dir.setWritable(true, false);
// the directory needs to be executable to anybody
// don't know why yet, but mode 723 would work, while
// mode 722 throws FileNotFoundExecption at line 151
dir.setExecutable(true, false);
if (new File(SNAPSHOT_DIR).isDirectory()) {
dirMade = true;
} else {
Log.w(TAG, "Creation of " + SNAPSHOT_DIR + " failed.");
pending.set(false);
return;
}
}
try { try {
writeSnapshot(SNAPSHOT_DIR, processName, packageInfo); writeSnapshotFile(processName, packageInfo);
} finally { } finally {
pending.set(false); pending.set(false);
} }
@ -140,7 +137,7 @@ public class SamplingProfilerIntegration {
if (!enabled) { if (!enabled) {
return; return;
} }
writeSnapshot("zygote", null); writeSnapshotFile("zygote", null);
INSTANCE.shutdown(); INSTANCE.shutdown();
INSTANCE = null; INSTANCE = null;
} }
@ -148,7 +145,7 @@ public class SamplingProfilerIntegration {
/** /**
* pass in PackageInfo to retrieve various values for snapshot header * pass in PackageInfo to retrieve various values for snapshot header
*/ */
private static void writeSnapshot(String dir, String processName, PackageInfo packageInfo) { private static void writeSnapshotFile(String processName, PackageInfo packageInfo) {
if (!enabled) { if (!enabled) {
return; return;
} }
@ -161,7 +158,7 @@ public class SamplingProfilerIntegration {
*/ */
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
String name = processName.replaceAll(":", "."); String name = processName.replaceAll(":", ".");
String path = dir + "/" + name + "-" +System.currentTimeMillis() + ".snapshot"; String path = SNAPSHOT_DIR + "/" + name + "-" +System.currentTimeMillis() + ".snapshot";
PrintStream out = null; PrintStream out = null;
try { try {
out = new PrintStream(new BufferedOutputStream(new FileOutputStream(path))); out = new PrintStream(new BufferedOutputStream(new FileOutputStream(path)));