aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java176
-rw-r--r--ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/BugReportParserTest.java51
-rw-r--r--eclipse/dictionary.txt1
3 files changed, 221 insertions, 7 deletions
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java
index 32fdcd9..c063818 100644
--- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java
+++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/SysinfoPanel.java
@@ -18,14 +18,17 @@ package com.android.ddmuilib;
import com.android.ddmlib.AdbCommandRejectedException;
import com.android.ddmlib.Client;
+import com.android.ddmlib.ClientData;
import com.android.ddmlib.IShellOutputReceiver;
import com.android.ddmlib.Log;
import com.android.ddmlib.ShellCommandUnresponsiveException;
import com.android.ddmlib.TimeoutException;
+import com.android.ddmuilib.SysinfoPanel.BugReportParser.GfxProfileData;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
@@ -39,6 +42,8 @@ import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.experimental.chart.swt.ChartComposite;
@@ -48,6 +53,7 @@ import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -63,6 +69,12 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver {
private Combo mDisplayMode;
private DefaultPieDataset mDataset;
+ private DefaultCategoryDataset mBarDataSet;
+
+ private StackLayout mStackLayout;
+ private Composite mChartComposite;
+ private Composite mPieChartComposite;
+ private Composite mStackedBarComposite;
// The bugreport file to process
private File mDataFile;
@@ -72,19 +84,23 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver {
// Selects the current display: MODE_CPU, etc.
private int mMode = 0;
+ private String mGfxPackageName;
private static final int MODE_CPU = 0;
private static final int MODE_MEMINFO = 1;
+ private static final int MODE_GFXINFO = 2;
// argument to dumpsys; section in the bugreport holding the data
private static final String DUMP_COMMAND[] = {
"dumpsys cpuinfo",
"cat /proc/meminfo ; procrank",
+ "dumpsys gfxinfo",
};
private static final String CAPTIONS[] = {
"CPU load",
"Memory usage",
+ "Frame Render Time",
};
/**
@@ -102,6 +118,8 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver {
readCpuDataset(br);
} else if (mMode == MODE_MEMINFO) {
readMeminfoDataset(br);
+ } else if (mMode == MODE_GFXINFO) {
+ readGfxInfoDataset(br);
}
br.close();
} catch (IOException e) {
@@ -146,6 +164,11 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver {
private void loadFromDevice() {
clearDataSet();
+ final String command = getDumpsysCommand(mMode);
+ if (command == null) {
+ return;
+ }
+
Thread t = new Thread(new Runnable() {
@Override
public void run() {
@@ -155,7 +178,7 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver {
// Hack to add bugreport-style section header for meminfo
mTempStream.write("------ MEMORY INFO ------\n".getBytes());
}
- getCurrentDevice().executeShellCommand(DUMP_COMMAND[mMode], SysinfoPanel.this);
+ getCurrentDevice().executeShellCommand(command, SysinfoPanel.this);
} catch (IOException e) {
Log.e("DDMS", e);
} catch (TimeoutException e) {
@@ -170,6 +193,31 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver {
t.start();
}
+ private String getDumpsysCommand(int mode) {
+ if (mode == MODE_GFXINFO) {
+ Client c = getCurrentClient();
+ if (c == null) {
+ return null;
+ }
+
+ ClientData cd = c.getClientData();
+ if (cd == null) {
+ return null;
+ }
+
+ mGfxPackageName = cd.getClientDescription();
+ if (mGfxPackageName == null) {
+ return null;
+ }
+
+ return "dumpsys gfxinfo " + mGfxPackageName;
+ } else if (mode < DUMP_COMMAND.length) {
+ return DUMP_COMMAND[mode];
+ }
+
+ return null;
+ }
+
/**
* Initializes temporary output file for executeShellCommand().
*
@@ -265,11 +313,42 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver {
mLabel = new Label(top, SWT.NONE);
mLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ mChartComposite = new Composite(top, SWT.NONE);
+ mChartComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
+ mStackLayout = new StackLayout();
+ mChartComposite.setLayout(mStackLayout);
+
+ mPieChartComposite = createPieChartComposite(mChartComposite);
+ mStackedBarComposite = createStackedBarComposite(mChartComposite);
+
+ mStackLayout.topControl = mPieChartComposite;
+
+ return top;
+ }
+
+ private Composite createStackedBarComposite(Composite chartComposite) {
+ mBarDataSet = new DefaultCategoryDataset();
+ JFreeChart chart = ChartFactory.createStackedBarChart("Per Frame Rendering Time",
+ "Frame #", "Time (ms)", mBarDataSet, PlotOrientation.VERTICAL,
+ true /* legend */, true /* tooltips */, false /* urls */);
+
+ ChartComposite c = newChartComposite(chart, chartComposite);
+ c.setLayoutData(new GridData(GridData.FILL_BOTH));
+ return c;
+ }
+
+ private Composite createPieChartComposite(Composite chartComposite) {
mDataset = new DefaultPieDataset();
JFreeChart chart = ChartFactory.createPieChart("", mDataset, false
/* legend */, true/* tooltips */, false /* urls */);
- ChartComposite chartComposite = new ChartComposite(top,
+ ChartComposite c = newChartComposite(chart, chartComposite);
+ c.setLayoutData(new GridData(GridData.FILL_BOTH));
+ return c;
+ }
+
+ private ChartComposite newChartComposite(JFreeChart chart, Composite parent) {
+ return new ChartComposite(parent,
SWT.BORDER, chart,
ChartComposite.DEFAULT_HEIGHT,
ChartComposite.DEFAULT_HEIGHT,
@@ -285,8 +364,6 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver {
true, // print
false, // zoom
true);
- chartComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
- return top;
}
@Override
@@ -351,6 +428,60 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver {
}
};
+ /** Components of the time it takes to draw a single frame. */
+ public static final class GfxProfileData {
+ /** draw time (time spent building display lists) in ms */
+ final double draw;
+
+ /** process time (time spent by Android's 2D renderer to execute display lists) (ms) */
+ final double process;
+
+ /** execute time (time spent to send frame to the compositor) in ms */
+ final double execute;
+
+ public GfxProfileData(double draw, double process, double execute) {
+ this.draw = draw;
+ this.process = process;
+ this.execute = execute;
+ }
+ }
+
+ public static List<GfxProfileData> parseGfxInfo(BufferedReader br) throws IOException {
+ Pattern headerPattern = Pattern.compile("\\s+Draw\\s+Process\\s+Execute");
+
+ String line = null;
+ while ((line = br.readLine()) != null) {
+ Matcher m = headerPattern.matcher(line);
+ if (m.find()) {
+ break;
+ }
+ }
+
+ if (line == null) {
+ return Collections.emptyList();
+ }
+
+ // parse something like: " 0.85 1.10 0.61\n", 3 doubles basically
+ Pattern dataPattern =
+ Pattern.compile("(\\d*\\.\\d+)\\s+(\\d*\\.\\d+)\\s+(\\d*\\.\\d+)");
+
+ List<GfxProfileData> data = new ArrayList<BugReportParser.GfxProfileData>(128);
+ while ((line = br.readLine()) != null) {
+ Matcher m = dataPattern.matcher(line);
+ if (!m.find()) {
+ break;
+ }
+
+ double draw = safeParseDouble(m.group(1));
+ double process = safeParseDouble(m.group(2));
+ double execute = safeParseDouble(m.group(3));
+
+ data.add(new GfxProfileData(draw, process, execute));
+ }
+
+ return data;
+ }
+
/**
* Processes wakelock information from bugreport. Updates mDataset with the
* new data.
@@ -665,27 +796,58 @@ public class SysinfoPanel extends TablePanel implements IShellOutputReceiver {
}
private void readCpuDataset(BufferedReader br) throws IOException {
- updateDataSet(BugReportParser.readCpuDataset(br), "");
+ updatePieDataSet(BugReportParser.readCpuDataset(br), "");
}
private void readMeminfoDataset(BufferedReader br) throws IOException {
- updateDataSet(BugReportParser.readMeminfoDataset(br), "PSS in kB");
+ updatePieDataSet(BugReportParser.readMeminfoDataset(br), "PSS in kB");
+ }
+
+ private void readGfxInfoDataset(BufferedReader br) throws IOException {
+ updateBarChartDataSet(BugReportParser.parseGfxInfo(br),
+ mGfxPackageName == null ? "" : mGfxPackageName);
}
private void clearDataSet() {
mLabel.setText("");
mDataset.clear();
+ mBarDataSet.clear();
}
- private void updateDataSet(final List<BugReportParser.DataValue> data, final String label) {
+ private void updatePieDataSet(final List<BugReportParser.DataValue> data, final String label) {
Display.getDefault().syncExec(new Runnable() {
@Override
public void run() {
mLabel.setText(label);
+ mStackLayout.topControl = mPieChartComposite;
+ mChartComposite.layout();
+
for (BugReportParser.DataValue d : data) {
mDataset.setValue(d.name, d.value);
}
}
});
}
+
+ private void updateBarChartDataSet(final List<GfxProfileData> gfxProfileData,
+ final String label) {
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ mLabel.setText(label);
+ mStackLayout.topControl = mStackedBarComposite;
+ mChartComposite.layout();
+
+ for (int i = 0; i < gfxProfileData.size(); i++) {
+ GfxProfileData d = gfxProfileData.get(i);
+ String frameNumber = Integer.toString(i);
+
+ mBarDataSet.addValue(d.draw, "Draw", frameNumber);
+ mBarDataSet.addValue(d.process, "Process", frameNumber);
+ mBarDataSet.addValue(d.execute, "Execute", frameNumber);
+ }
+ }
+ });
+ }
+
}
diff --git a/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/BugReportParserTest.java b/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/BugReportParserTest.java
index 5a69ca5..7894965 100644
--- a/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/BugReportParserTest.java
+++ b/ddms/libs/ddmuilib/tests/src/com/android/ddmuilib/BugReportParserTest.java
@@ -18,6 +18,7 @@ package com.android.ddmuilib;
import com.android.ddmuilib.SysinfoPanel.BugReportParser;
import com.android.ddmuilib.SysinfoPanel.BugReportParser.DataValue;
+import com.android.ddmuilib.SysinfoPanel.BugReportParser.GfxProfileData;
import junit.framework.TestCase;
@@ -134,4 +135,54 @@ public class BugReportParserTest extends TestCase {
assertEquals(6, data.size());
}
+
+ public void testParseGfxInfo() throws IOException {
+ String gfxinfo =
+ "Applications Graphics Acceleration Info:\n" +
+ "Uptime: 78455570 Realtime: 78455565\n" +
+ "\n" +
+ "** Graphics info for pid 20517 [com.android.launcher] **\n" +
+ "\n" +
+ "Recent DisplayList operations\n" +
+ " DrawDisplayList\n" +
+ " <snip>\n" +
+ " RestoreToCount\n" +
+ "\n" +
+ "Caches:\n" +
+ "Current memory usage / total memory usage (bytes):\n" +
+ " TextureCache 4663920 / 25165824\n" +
+ " <snip>\n" +
+ " FontRenderer 0 262144 / 262144\n" +
+ "Other:\n" +
+ " FboCache 2 / 16\n" +
+ " PatchCache 9 / 512\n" +
+ "Total memory usage:\n" +
+ " 13274756 bytes, 12.66 MB\n" +
+ "\n" +
+ "Profile data in ms:\n" +
+ "\n" +
+ " com.android.launcher/com.android.launcher2.Launcher/android.view.ViewRootImpl@4265d918\n" +
+ " Draw Process Execute\n" +
+ " 0.85 1.10 0.61\n" +
+ " 54.45 0.85 0.52\n" +
+ " 1.04 2.17 0.73\n" +
+ " 0.15 0.46 1.01\n" +
+ "\n" +
+ "View hierarchy:\n" +
+ "\n" +
+ " com.android.launcher/com.android.launcher2.Launcher/android.view.ViewRootImpl@4265d918\n" +
+ " 276 views, 27.16 kB of display lists, 228 frames rendered\n" +
+ "\n" +
+ "\n" +
+ "Total ViewRootImpl: 1\n" +
+ "Total Views: 276\n" +
+ "Total DisplayList: 27.16 kB\n";
+
+ BufferedReader br = new BufferedReader(new StringReader(gfxinfo));
+ List<GfxProfileData> gfxProfile = BugReportParser.parseGfxInfo(br);
+
+ assertEquals(4, gfxProfile.size());
+ assertEquals(0.85, gfxProfile.get(0).draw);
+ assertEquals(1.01, gfxProfile.get(3).execute);
+ }
}
diff --git a/eclipse/dictionary.txt b/eclipse/dictionary.txt
index 7d6f931..530aeda 100644
--- a/eclipse/dictionary.txt
+++ b/eclipse/dictionary.txt
@@ -55,6 +55,7 @@ colspan
combo
combobox
combos
+compositor
config
configs
configurability