diff options
author | Siva Velusamy <vsiva@google.com> | 2013-08-29 12:43:36 -0700 |
---|---|---|
committer | Siva Velusamy <vsiva@google.com> | 2013-08-29 12:43:36 -0700 |
commit | 6520376fe9bf47ca34d866c2ecf337ff0d467ec7 (patch) | |
tree | 7a42d562418825652e2db7a7a7a3c5b1d9f65667 /ddms | |
parent | f6ffed5c9269099472d735bf1a3a224a0546fa85 (diff) | |
download | swt-6520376fe9bf47ca34d866c2ecf337ff0d467ec7.tar.gz |
ddms: Add support for sampling profiler
This CL adds supports for sampling based profiling.
When method profiling is initiated, we detect whether sampling
profiling is supported and if so, we show a dialog that allows
users to select the type of profiling to be performed.
The methods to obtain and display trace data is unchanged.
Change-Id: I8ec1a2c2311d6ffa7f73b5690d71e9d2253d09f2
Diffstat (limited to 'ddms')
3 files changed, 199 insertions, 8 deletions
diff --git a/ddms/app/src/main/java/com/android/ddms/UIThread.java b/ddms/app/src/main/java/com/android/ddms/UIThread.java index 1310429..7680f08 100644 --- a/ddms/app/src/main/java/com/android/ddms/UIThread.java +++ b/ddms/app/src/main/java/com/android/ddms/UIThread.java @@ -1719,7 +1719,8 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener { if (data.hasFeature(ClientData.FEATURE_PROFILING)) { mTBProfiling.setEnabled(true); - if (data.getMethodProfilingStatus() == MethodProfilingStatus.ON) { + if (data.getMethodProfilingStatus() == MethodProfilingStatus.TRACER_ON + || data.getMethodProfilingStatus() == MethodProfilingStatus.SAMPLER_ON) { mTBProfiling.setToolTipText("Stop Method Profiling"); mTBProfiling.setImage(mTracingStopImage); } else { @@ -1729,7 +1730,7 @@ public class UIThread implements IUiSelectionListener, IClientChangeListener { } else { mTBProfiling.setEnabled(false); mTBProfiling.setImage(mTracingStartImage); - mTBProfiling.setToolTipText("Start Method Profiling (not supported by this VM)"); + mTBProfiling.setToolTipText("Method Profiling (not supported by this VM)"); } } else { // list is empty, disable these diff --git a/ddms/ddmuilib/src/main/java/com/android/ddmuilib/DevicePanel.java b/ddms/ddmuilib/src/main/java/com/android/ddmuilib/DevicePanel.java index a24b8a0..fb97062 100644 --- a/ddms/ddmuilib/src/main/java/com/android/ddmuilib/DevicePanel.java +++ b/ddms/ddmuilib/src/main/java/com/android/ddmuilib/DevicePanel.java @@ -16,6 +16,7 @@ package com.android.ddmuilib; +import com.android.annotations.NonNull; import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener; @@ -26,7 +27,10 @@ import com.android.ddmlib.ClientData.DebuggerStatus; import com.android.ddmlib.DdmPreferences; import com.android.ddmlib.IDevice; import com.android.ddmlib.IDevice.DeviceState; +import com.android.ddmuilib.vmtrace.VmTraceOptionsDialog; +import com.google.common.base.Throwables; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.ITableLabelProvider; @@ -35,6 +39,7 @@ import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.events.SelectionAdapter; @@ -48,8 +53,10 @@ import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; +import java.io.IOException; import java.util.ArrayList; import java.util.Locale; +import java.util.concurrent.TimeUnit; /** * A display of both the devices and their clients. @@ -310,7 +317,6 @@ public final class DevicePanel extends Panel implements IDebugBridgeChangeListen /** * Creates the {@link DevicePanel} object. - * @param loader * @param advancedPortSupport if true the device panel will add support for selected client port * and display the ports in the ui. */ @@ -447,8 +453,49 @@ public final class DevicePanel extends Panel implements IDebugBridgeChangeListen } public void toggleMethodProfiling() { - if (mCurrentClient != null) { - mCurrentClient.toggleMethodProfiling(); + if (mCurrentClient == null) { + return; + } + + try { + toggleMethodProfiling(mCurrentClient); + } catch (IOException e) { + MessageDialog.openError(mTree.getShell(), "Method Profiling", + "Unexpected I/O error while starting/stopping profiling: " + + Throwables.getRootCause(e).getMessage()); + } + } + + private void toggleMethodProfiling(@NonNull Client client) throws IOException { + ClientData cd = mCurrentClient.getClientData(); + if (cd.getMethodProfilingStatus() == ClientData.MethodProfilingStatus.TRACER_ON) { + mCurrentClient.stopMethodTracer(); + } else if (cd.getMethodProfilingStatus() == ClientData.MethodProfilingStatus.SAMPLER_ON) { + mCurrentClient.stopSamplingProfiler(); + } else { + boolean supportsSampling = cd.hasFeature(ClientData.FEATURE_SAMPLING_PROFILER); + + // default to tracing + boolean shouldUseTracing = true; + int samplingIntervalMicros = 1; + + // if client supports sampling, then ask the user to choose the method + if (supportsSampling) { + VmTraceOptionsDialog dialog = new VmTraceOptionsDialog(mTree.getShell()); + if (dialog.open() == Window.CANCEL) { + return; + } + shouldUseTracing = dialog.shouldUseTracing(); + if (!shouldUseTracing) { + samplingIntervalMicros = dialog.getSamplingIntervalMicros(); + } + } + + if (shouldUseTracing) { + mCurrentClient.startMethodTracer(); + } else { + mCurrentClient.startSamplingProfiler(samplingIntervalMicros, TimeUnit.MICROSECONDS); + } } } @@ -469,8 +516,6 @@ public final class DevicePanel extends Panel implements IDebugBridgeChangeListen * <p/> * This is sent from a non UI thread. * @param bridge the new {@link AndroidDebugBridge} object. - * - * @see IDebugBridgeChangeListener#serverChanged(AndroidDebugBridge) */ @Override public void bridgeChanged(final AndroidDebugBridge bridge) { @@ -563,7 +608,7 @@ public final class DevicePanel extends Panel implements IDebugBridgeChangeListen * @param device the device that was updated. * @param changeMask the mask indicating what changed. * - * @see IDeviceChangeListener#deviceChanged(IDevice) + * @see IDeviceChangeListener#deviceChanged(IDevice,int) */ @Override public void deviceChanged(final IDevice device, int changeMask) { diff --git a/ddms/ddmuilib/src/main/java/com/android/ddmuilib/vmtrace/VmTraceOptionsDialog.java b/ddms/ddmuilib/src/main/java/com/android/ddmuilib/vmtrace/VmTraceOptionsDialog.java new file mode 100644 index 0000000..b3cfb4e --- /dev/null +++ b/ddms/ddmuilib/src/main/java/com/android/ddmuilib/vmtrace/VmTraceOptionsDialog.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ddmuilib.vmtrace; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; + +/** Dialog that allows users to select between method tracing or sampler based profiling. */ +public class VmTraceOptionsDialog extends Dialog { + private static final int DEFAULT_SAMPLING_INTERVAL_US = 1000; + + // Static variables that maintain state across invocations of the dialog + private static boolean sTracingEnabled = true; + private static int sSamplingIntervalUs = DEFAULT_SAMPLING_INTERVAL_US; + + public VmTraceOptionsDialog(Shell parentShell) { + super(parentShell); + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Profiling Options"); + } + + @Override + protected Control createDialogArea(Composite shell) { + int horizontalIndent = 30; + + Composite parent = (Composite) super.createDialogArea(shell); + Composite c = new Composite(parent, SWT.NONE); + c.setLayout(new GridLayout(2, false)); + c.setLayoutData(new GridData(GridData.FILL_BOTH)); + + final Button useTracingButton = new Button(c, SWT.RADIO); + useTracingButton.setText("Trace based profiling"); + useTracingButton.setSelection(sTracingEnabled); + GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING, + GridData.VERTICAL_ALIGN_CENTER, true, true, 2, 1); + useTracingButton.setLayoutData(gd); + + Label l = new Label(c, SWT.NONE); + l.setText("Trace based profiling works by tracing the entry and exit of every method.\n" + + "This gives an accurate view of the execution, but has a high overhead."); + gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING, GridData.VERTICAL_ALIGN_CENTER, true, + true, 2, 1); + gd.horizontalIndent = horizontalIndent; + l.setLayoutData(gd); + + final Button useSamplingButton = new Button(c, SWT.RADIO); + useSamplingButton.setText("Sample based profiling"); + useSamplingButton.setSelection(!sTracingEnabled); + gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING, GridData.VERTICAL_ALIGN_CENTER, true, + true, 2, 1); + useSamplingButton.setLayoutData(gd); + + l = new Label(c, SWT.NONE); + l.setText("Sample based profiling works by interrupting the VM at a given frequency and " + + "collecting the call stacks at that time.\n" + + "This has a much lower overhead, but statistical sampling requires longer runs " + + "to obtain a representative sample."); + gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING, GridData.VERTICAL_ALIGN_CENTER, true, + true, 2, 1); + gd.horizontalIndent = horizontalIndent; + l.setLayoutData(gd); + + l = new Label(c, SWT.NONE); + l.setText("Sampling frequency (microseconds): "); + gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING, GridData.VERTICAL_ALIGN_END, + false, true); + gd.horizontalIndent = horizontalIndent; + l.setLayoutData(gd); + + final Text samplingIntervalTextField = new Text(c, SWT.BORDER); + gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING, GridData.VERTICAL_ALIGN_CENTER, true, + true); + gd.widthHint = 100; + samplingIntervalTextField.setLayoutData(gd); + samplingIntervalTextField.setEnabled(!sTracingEnabled); + samplingIntervalTextField.setText(Integer.toString(sSamplingIntervalUs)); + samplingIntervalTextField.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent modifyEvent) { + int v = getIntegerValue(samplingIntervalTextField.getText()); + getButton(IDialogConstants.OK_ID).setEnabled(v > 0); + sSamplingIntervalUs = v > 0 ? v : DEFAULT_SAMPLING_INTERVAL_US; + } + + private int getIntegerValue(String text) { + try { + return Integer.parseInt(text); + } catch (NumberFormatException e) { + return -1; + } + } + }); + + SelectionAdapter selectionAdapter = new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent event) { + sTracingEnabled = useTracingButton.getSelection(); + samplingIntervalTextField.setEnabled(!sTracingEnabled); + } + }; + useTracingButton.addSelectionListener(selectionAdapter); + useSamplingButton.addSelectionListener(selectionAdapter); + + return c; + } + + public boolean shouldUseTracing() { + return sTracingEnabled; + } + + public int getSamplingIntervalMicros() { + return sSamplingIntervalUs; + } +} |