From 6ec0b7e21d0f6fdee9f24d91b33c0c71e50cafc4 Mon Sep 17 00:00:00 2001 From: Shukang Zhou Date: Tue, 24 Jan 2017 15:30:29 -0800 Subject: [PATCH] [Frameworks] Add an 'am' cmd option to enable streaming in profiling. Add option '--streaming' to 'am start' and 'am profile' commands. If the option is given, the output of method trace profiling will be streamed into the specified file, so the output is no longer limited by the buffer size. Test: m -j48 test-art-host; m -j48 ART_TEST_TRACE=true ART_TEST_TRACE_STREAM=true test-art-host; I also tested manually. Tried all 8 combinations of sampling/instrumention streaming/non-streaming 'am start --start-profiler' / 'am profile start' The output files are all in expected shape. Bug: 33300765 Merged-In: I8a5136a1c7330c8260b7c6c8da63f42a73aee275 Change-Id: I8a5136a1c7330c8260b7c6c8da63f42a73aee275 --- cmds/am/src/com/android/commands/am/Am.java | 22 +++++++++++++++---- core/java/android/app/ActivityThread.java | 6 ++++- core/java/android/app/ProfilerInfo.java | 9 +++++++- core/java/android/os/Debug.java | 4 ++-- .../server/am/ActivityManagerService.java | 10 +++++++-- .../server/am/ActivityStackSupervisor.java | 3 ++- 6 files changed, 43 insertions(+), 11 deletions(-) diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index d6c00589e7c2a..a66b0b9ddec9c 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -110,6 +110,7 @@ public class Am extends BaseCommand { private String mProfileFile; private int mSamplingInterval; private boolean mAutoStop; + private boolean mStreaming; // Streaming the profiling output to a file. private int mStackId; /** @@ -127,7 +128,7 @@ public class Am extends BaseCommand { pw.println( "usage: am [subcommand] [options]\n" + "usage: am start [-D] [-N] [-W] [-P ] [--start-profiler ]\n" + - " [--sampling INTERVAL] [-R COUNT] [-S]\n" + + " [--sampling INTERVAL] [--streaming] [-R COUNT] [-S]\n" + " [--track-allocation] [--user | current] \n" + " am startservice [--user | current] \n" + " am stopservice [--user | current] \n" + @@ -138,7 +139,8 @@ public class Am extends BaseCommand { " am instrument [-r] [-e ] [-p ] [-w]\n" + " [--user | current]\n" + " [--no-window-animation] [--abi ] \n" + - " am profile start [--user current] [--sampling INTERVAL] \n" + + " am profile start [--user current] [--sampling INTERVAL]\n"+ + " [--streaming] \n" + " am profile stop [--user current] []\n" + " am dumpheap [--user current] [-n] \n" + " am set-debug-app [-w] [--persistent] \n" + @@ -191,6 +193,8 @@ public class Am extends BaseCommand { " --start-profiler : start profiler and send results to \n" + " --sampling INTERVAL: use sample profiling with INTERVAL microseconds\n" + " between samples (use with --start-profiler)\n" + + " --streaming: stream the profiling output to the specified file (use\n" + + " with --start-profiler)\n" + " -P : like above, but profiling stops when app goes idle\n" + " -R: repeat the activity launch times. Prior to each repeat,\n" + " the top activity will be finished.\n" + @@ -250,6 +254,9 @@ public class Am extends BaseCommand { " may be either a process name or pid. Options are:\n" + " --user | current: When supplying a process name,\n" + " specify user of process to profile; uses current user if not specified.\n" + + " --sampling INTERVAL: use sample profiling with INTERVAL microseconds\n" + + " between samples\n" + + " --streaming: stream the profiling output to the specified file\n" + "\n" + "am dumpheap: dump the heap of a process. The given argument may\n" + " be either a process name or pid. Options are:\n" + @@ -483,6 +490,7 @@ public class Am extends BaseCommand { mProfileFile = null; mSamplingInterval = 0; mAutoStop = false; + mStreaming = false; mUserId = defUser; mStackId = INVALID_STACK_ID; @@ -503,6 +511,8 @@ public class Am extends BaseCommand { mAutoStop = false; } else if (opt.equals("--sampling")) { mSamplingInterval = Integer.parseInt(nextArgRequired()); + } else if (opt.equals("--streaming")) { + mStreaming = true; } else if (opt.equals("-R")) { mRepeat = Integer.parseInt(nextArgRequired()); } else if (opt.equals("-S")) { @@ -615,7 +625,8 @@ public class Am extends BaseCommand { System.err.println("Consider using a file under /data/local/tmp/"); return; } - profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop); + profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop, + mStreaming); } IActivityManager.WaitResult result = null; @@ -973,6 +984,7 @@ public class Am extends BaseCommand { int userId = UserHandle.USER_CURRENT; int profileType = 0; mSamplingInterval = 0; + mStreaming = false; String process = null; @@ -986,6 +998,8 @@ public class Am extends BaseCommand { userId = parseUserArg(nextArgRequired()); } else if (opt.equals("--wall")) { wall = true; + } else if (opt.equals("--streaming")) { + mStreaming = true; } else if (opt.equals("--sampling")) { mSamplingInterval = Integer.parseInt(nextArgRequired()); } else { @@ -1037,7 +1051,7 @@ public class Am extends BaseCommand { System.err.println("Consider using a file under /data/local/tmp/"); return; } - profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false); + profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false, mStreaming); } try { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 2d22f26069f33..cae4be69c0fea 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -534,6 +534,7 @@ public final class ActivityThread { ParcelFileDescriptor profileFd; int samplingInterval; boolean autoStopProfiler; + boolean streamingOutput; boolean profiling; boolean handlingProfiling; public void setProfiler(ProfilerInfo profilerInfo) { @@ -559,6 +560,7 @@ public final class ActivityThread { profileFd = fd; samplingInterval = profilerInfo.samplingInterval; autoStopProfiler = profilerInfo.autoStopProfiler; + streamingOutput = profilerInfo.streamingOutput; } public void startProfiling() { if (profileFd == null || profiling) { @@ -567,7 +569,8 @@ public final class ActivityThread { try { int bufferSize = SystemProperties.getInt("debug.traceview-buffer-size-mb", 8); VMDebug.startMethodTracing(profileFile, profileFd.getFileDescriptor(), - bufferSize * 1024 * 1024, 0, samplingInterval != 0, samplingInterval); + bufferSize * 1024 * 1024, 0, samplingInterval != 0, samplingInterval, + streamingOutput); profiling = true; } catch (RuntimeException e) { Slog.w(TAG, "Profiling failed on path " + profileFile); @@ -5109,6 +5112,7 @@ public final class ActivityThread { mProfiler.profileFd = data.initProfilerInfo.profileFd; mProfiler.samplingInterval = data.initProfilerInfo.samplingInterval; mProfiler.autoStopProfiler = data.initProfilerInfo.autoStopProfiler; + mProfiler.streamingOutput = data.initProfilerInfo.streamingOutput; } // send up app name; do this *before* waiting for debugger diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java index cea7c3cbe8c3f..f3fe6778375bc 100644 --- a/core/java/android/app/ProfilerInfo.java +++ b/core/java/android/app/ProfilerInfo.java @@ -39,11 +39,16 @@ public class ProfilerInfo implements Parcelable { /* Automatically stop the profiler when the app goes idle. */ public final boolean autoStopProfiler; - public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop) { + /* Indicates whether to stream the profiling info to the out file continuously. */ + public final boolean streamingOutput; + + public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop, + boolean streaming) { profileFile = filename; profileFd = fd; samplingInterval = interval; autoStopProfiler = autoStop; + streamingOutput = streaming; } public int describeContents() { @@ -64,6 +69,7 @@ public class ProfilerInfo implements Parcelable { } out.writeInt(samplingInterval); out.writeInt(autoStopProfiler ? 1 : 0); + out.writeInt(streamingOutput ? 1 : 0); } public static final Parcelable.Creator CREATOR = @@ -82,5 +88,6 @@ public class ProfilerInfo implements Parcelable { profileFd = in.readInt() != 0 ? ParcelFileDescriptor.CREATOR.createFromParcel(in) : null; samplingInterval = in.readInt(); autoStopProfiler = in.readInt() != 0; + streamingOutput = in.readInt() != 0; } } diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 175d883da29de..210ddb6cd3970 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -1119,8 +1119,8 @@ public final class Debug * @hide */ public static void startMethodTracing(String traceName, FileDescriptor fd, - int bufferSize, int flags) { - VMDebug.startMethodTracing(traceName, fd, bufferSize, flags, false, 0); + int bufferSize, int flags, boolean streamOutput) { + VMDebug.startMethodTracing(traceName, fd, bufferSize, flags, false, 0, streamOutput); } /** diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index bc0390119a1df..b6ca24a118fd8 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1381,6 +1381,7 @@ public final class ActivityManagerService extends ActivityManagerNative ParcelFileDescriptor mProfileFd; int mSamplingInterval = 0; boolean mAutoStopProfiler = false; + boolean mStreamingOutput = false; int mProfileType = 0; final ProcessMap> mMemWatchProcesses = new ProcessMap<>(); String mMemWatchDumpProcName; @@ -6571,12 +6572,14 @@ public final class ActivityManagerService extends ActivityManagerNative ParcelFileDescriptor profileFd = null; int samplingInterval = 0; boolean profileAutoStop = false; + boolean profileStreamingOutput = false; if (mProfileApp != null && mProfileApp.equals(processName)) { mProfileProc = app; profileFile = mProfileFile; profileFd = mProfileFd; samplingInterval = mSamplingInterval; profileAutoStop = mAutoStopProfiler; + profileStreamingOutput = mStreamingOutput; } boolean enableTrackAllocation = false; if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) { @@ -6606,7 +6609,8 @@ public final class ActivityManagerService extends ActivityManagerNative profileFd = profileFd.dup(); } ProfilerInfo profilerInfo = profileFile == null ? null - : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop); + : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop, + profileStreamingOutput); thread.bindApplication(processName, appInfo, providers, app.instrumentationClass, profilerInfo, app.instrumentationArguments, app.instrumentationWatcher, app.instrumentationUiAutomationConnection, testMode, @@ -12039,6 +12043,7 @@ public final class ActivityManagerService extends ActivityManagerNative mProfileFd = profilerInfo.profileFd; mSamplingInterval = profilerInfo.samplingInterval; mAutoStopProfiler = profilerInfo.autoStopProfiler; + mStreamingOutput = profilerInfo.streamingOutput; mProfileType = 0; } } @@ -14920,7 +14925,7 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(" mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc); pw.println(" mProfileFile=" + mProfileFile + " mProfileFd=" + mProfileFd); pw.println(" mSamplingInterval=" + mSamplingInterval + " mAutoStopProfiler=" - + mAutoStopProfiler); + + mAutoStopProfiler + " mStreamingOutput=" + mStreamingOutput); pw.println(" mProfileType=" + mProfileType); } } @@ -21438,6 +21443,7 @@ public final class ActivityManagerService extends ActivityManagerNative mProfileFile = null; mProfileType = 0; mAutoStopProfiler = false; + mStreamingOutput = false; mSamplingInterval = 0; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index c6ab9186456d8..2262697e34618 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1296,7 +1296,8 @@ public final class ActivityStackSupervisor implements DisplayListener { } profilerInfo = new ProfilerInfo(profileFile, profileFd, - mService.mSamplingInterval, mService.mAutoStopProfiler); + mService.mSamplingInterval, mService.mAutoStopProfiler, + mService.mStreamingOutput); } } }