Skip to content

Commit 702c6fd

Browse files
committed
Allow profiling of animation performance
Also fixes manual testing mode Depends on external/webkit change: https://android-git.corp.google.com/g/#/c/159794/ Change-Id: I169e80f9b5328b1b5a7b0aeaf09652de67febd8d
1 parent d4e34d6 commit 702c6fd

File tree

5 files changed

+400
-100
lines changed

5 files changed

+400
-100
lines changed

tests/TileBenchmark/res/values/strings.xml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@
4949
<!-- Drop down menu entry - automatically scroll to the end of the page
5050
with scrollBy() [CHAR LIMIT=15] -->
5151
<string name="movement_auto_scroll">Auto-scroll</string>
52-
<!-- Drop down menu entry - [CHAR LIMIT=15] -->
53-
<string name="movement_auto_fling">Auto-fling</string>
52+
<!-- Drop down menu entry - automatically record for a set time before
53+
stopping [CHAR LIMIT=15] -->
54+
<string name="movement_timed">Timed</string>
5455
<!-- Drop down menu entry - manually navigate the page(s), hit 'capture'
5556
button [CHAR LIMIT=15] -->
5657
<string name="movement_manual">Manual</string>
@@ -67,14 +68,21 @@
6768
<!-- 75th percentile - 75% of frames fall below this value [CHAR LIMIT=12]
6869
-->
6970
<string name="percentile_75">75%ile</string>
71+
<!-- standard deviation [CHAR LIMIT=12] -->
72+
<string name="std_dev">StdDev</string>
73+
<!-- mean [CHAR LIMIT=12] -->
74+
<string name="mean">mean</string>
75+
76+
77+
7078
<!-- Frame rate [CHAR LIMIT=15] -->
7179
<string name="frames_per_second">Frames/sec</string>
7280
<!-- Portion of viewport covered by good tiles [CHAR LIMIT=15] -->
7381
<string name="viewport_coverage">Coverage</string>
7482
<!-- Milliseconds taken to inval, and re-render the page [CHAR LIMIT=15] -->
7583
<string name="render_millis">RenderMillis</string>
76-
<!-- Number of rendering stalls while running the test [CHAR LIMIT=15] -->
77-
<string name="render_stalls">Stalls</string>
84+
<!-- Animation Framerate [CHAR LIMIT=15] -->
85+
<string name="animation_framerate">AnimFramerate</string>
7886
<!-- Format string for stat value overlay [CHAR LIMIT=15] -->
7987
<string name="format_stat">%4.4f</string>
8088

tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java

Lines changed: 171 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,57 @@
2727
import android.os.Environment;
2828
import android.test.ActivityInstrumentationTestCase2;
2929
import android.util.Log;
30+
import android.webkit.WebSettings;
31+
import android.widget.Spinner;
3032

3133
public class PerformanceTest extends
3234
ActivityInstrumentationTestCase2<ProfileActivity> {
3335

36+
public static class AnimStat {
37+
double aggVal = 0;
38+
double aggSqrVal = 0;
39+
double count = 0;
40+
}
41+
3442
private class StatAggregator extends PlaybackGraphs {
3543
private HashMap<String, Double> mDataMap = new HashMap<String, Double>();
44+
private HashMap<String, AnimStat> mAnimDataMap = new HashMap<String, AnimStat>();
3645
private int mCount = 0;
3746

47+
3848
public void aggregate() {
49+
boolean inAnimTests = mAnimTests != null;
50+
Resources resources = mWeb.getResources();
51+
String animFramerateString = resources.getString(R.string.animation_framerate);
52+
for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
53+
String name = e.getKey();
54+
if (inAnimTests) {
55+
if (name.equals(animFramerateString)) {
56+
// in animation testing phase, record animation framerate and aggregate
57+
// stats, differentiating on values of mAnimTestNr and mDoubleBuffering
58+
String fullName = ANIM_TEST_NAMES[mAnimTestNr] + " " + name;
59+
fullName += mDoubleBuffering ? " tiled" : " webkit";
60+
61+
if (!mAnimDataMap.containsKey(fullName)) {
62+
mAnimDataMap.put(fullName, new AnimStat());
63+
}
64+
AnimStat statVals = mAnimDataMap.get(fullName);
65+
statVals.aggVal += e.getValue();
66+
statVals.aggSqrVal += e.getValue() * e.getValue();
67+
statVals.count += 1;
68+
}
69+
} else {
70+
double aggVal = mDataMap.containsKey(name)
71+
? mDataMap.get(name) : 0;
72+
mDataMap.put(name, aggVal + e.getValue());
73+
}
74+
}
75+
76+
if (inAnimTests) {
77+
return;
78+
}
79+
3980
mCount++;
40-
Resources resources = mView.getResources();
4181
for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
4282
for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
4383
String metricLabel = resources.getString(
@@ -53,34 +93,47 @@ public void aggregate() {
5393
mDataMap.put(label, aggVal);
5494
}
5595
}
56-
for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
57-
double aggVal = mDataMap.containsKey(e.getKey())
58-
? mDataMap.get(e.getKey()) : 0;
59-
mDataMap.put(e.getKey(), aggVal + e.getValue());
60-
}
96+
6197
}
6298

99+
// build the final bundle of results
63100
public Bundle getBundle() {
64101
Bundle b = new Bundle();
65-
int count = 0 == mCount ? Integer.MAX_VALUE : mCount;
102+
int count = (0 == mCount) ? Integer.MAX_VALUE : mCount;
66103
for (Map.Entry<String, Double> e : mDataMap.entrySet()) {
67104
b.putDouble(e.getKey(), e.getValue() / count);
68105
}
106+
107+
for (Map.Entry<String, AnimStat> e : mAnimDataMap.entrySet()) {
108+
String statName = e.getKey();
109+
AnimStat statVals = e.getValue();
110+
111+
double avg = statVals.aggVal/statVals.count;
112+
double stdDev = Math.sqrt((statVals.aggSqrVal / statVals.count) - avg * avg);
113+
114+
b.putDouble(statName, avg);
115+
b.putDouble(statName + " STD DEV", stdDev);
116+
}
117+
69118
return b;
70119
}
71120
}
72121

73122
ProfileActivity mActivity;
74-
ProfiledWebView mView;
75-
StatAggregator mStats = new StatAggregator();
123+
ProfiledWebView mWeb;
124+
Spinner mMovementSpinner;
125+
StatAggregator mStats;
76126

77127
private static final String LOGTAG = "PerformanceTest";
78128
private static final String TEST_LOCATION = "webkit/page_cycler";
79129
private static final String URL_PREFIX = "file://";
80130
private static final String URL_POSTFIX = "/index.html?skip=true";
81131
private static final int MAX_ITERATIONS = 4;
82-
private static final String TEST_DIRS[] = {
83-
"alexa25_2011"//, "alexa_us", "android", "dom", "intl2", "moz", "moz2"
132+
private static final String SCROLL_TEST_DIRS[] = {
133+
"alexa25_2011"
134+
};
135+
private static final String ANIM_TEST_DIRS[] = {
136+
"dhtml"
84137
};
85138

86139
public PerformanceTest() {
@@ -91,7 +144,22 @@ public PerformanceTest() {
91144
protected void setUp() throws Exception {
92145
super.setUp();
93146
mActivity = getActivity();
94-
mView = (ProfiledWebView) mActivity.findViewById(R.id.web);
147+
mWeb = (ProfiledWebView) mActivity.findViewById(R.id.web);
148+
mMovementSpinner = (Spinner) mActivity.findViewById(R.id.movement);
149+
mStats = new StatAggregator();
150+
151+
// use mStats as a condition variable between the UI thread and
152+
// this(the testing) thread
153+
mActivity.setCallback(new ProfileCallback() {
154+
@Override
155+
public void profileCallback(RunData data) {
156+
mStats.setData(data);
157+
synchronized (mStats) {
158+
mStats.notify();
159+
}
160+
}
161+
});
162+
95163
}
96164

97165
private boolean loadUrl(final String url) {
@@ -100,12 +168,13 @@ private boolean loadUrl(final String url) {
100168
mActivity.runOnUiThread(new Runnable() {
101169
@Override
102170
public void run() {
103-
mView.loadUrl(url);
171+
mWeb.loadUrl(url);
104172
}
105173
});
106174
synchronized (mStats) {
107175
mStats.wait();
108176
}
177+
109178
mStats.aggregate();
110179
} catch (InterruptedException e) {
111180
e.printStackTrace();
@@ -114,15 +183,30 @@ public void run() {
114183
return true;
115184
}
116185

117-
private boolean runIteration() {
186+
private boolean validTest(String nextTest) {
187+
// if testing animations, test must be in mAnimTests
188+
if (mAnimTests == null)
189+
return true;
190+
191+
for (String test : mAnimTests) {
192+
if (test.equals(nextTest)) {
193+
return true;
194+
}
195+
}
196+
return false;
197+
}
198+
199+
private boolean runIteration(String[] testDirs) {
118200
File sdFile = Environment.getExternalStorageDirectory();
119-
for (String testDirName : TEST_DIRS) {
201+
for (String testDirName : testDirs) {
120202
File testDir = new File(sdFile, TEST_LOCATION + "/" + testDirName);
121203
Log.d(LOGTAG, "Testing dir: '" + testDir.getAbsolutePath()
122204
+ "', exists=" + testDir.exists());
205+
123206
for (File siteDir : testDir.listFiles()) {
124-
if (!siteDir.isDirectory())
207+
if (!siteDir.isDirectory() || !validTest(siteDir.getName())) {
125208
continue;
209+
}
126210

127211
if (!loadUrl(URL_PREFIX + siteDir.getAbsolutePath()
128212
+ URL_POSTFIX)) {
@@ -133,35 +217,88 @@ private boolean runIteration() {
133217
return true;
134218
}
135219

136-
public void testMetrics() {
220+
private boolean runTestDirs(String[] testDirs) {
221+
for (int i = 0; i < MAX_ITERATIONS; i++)
222+
if (!runIteration(testDirs)) {
223+
return false;
224+
}
225+
return true;
226+
}
227+
228+
private void pushDoubleBuffering() {
229+
getInstrumentation().runOnMainSync(new Runnable() {
230+
public void run() {
231+
mWeb.setDoubleBuffering(mDoubleBuffering);
232+
}
233+
});
234+
}
235+
236+
private void setScrollingTestingMode(final boolean scrolled) {
237+
getInstrumentation().runOnMainSync(new Runnable() {
238+
public void run() {
239+
mMovementSpinner.setSelection(scrolled ? 0 : 2);
240+
}
241+
});
242+
}
243+
244+
245+
private String[] mAnimTests = null;
246+
private int mAnimTestNr = -1;
247+
private boolean mDoubleBuffering = true;
248+
private static final String[] ANIM_TEST_NAMES = {
249+
"slow", "fast"
250+
};
251+
private static final String[][] ANIM_TESTS = {
252+
{"scrolling", "replaceimages", "layers5", "layers1"},
253+
{"slidingballs", "meter", "slidein", "fadespacing", "colorfade",
254+
"mozilla", "movingtext", "diagball", "zoom", "imageslide"},
255+
};
256+
257+
private boolean checkMedia() {
137258
String state = Environment.getExternalStorageState();
138259

139260
if (!Environment.MEDIA_MOUNTED.equals(state)
140261
&& !Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
141262
Log.d(LOGTAG, "ARG Can't access sd card!");
142263
// Can't read the SD card, fail and die!
143264
getInstrumentation().sendStatus(1, null);
144-
return;
265+
return false;
145266
}
267+
return true;
268+
}
146269

147-
// use mGraphs as a condition variable between the UI thread and
148-
// this(the testing) thread
149-
mActivity.setCallback(new ProfileCallback() {
150-
@Override
151-
public void profileCallback(RunData data) {
152-
Log.d(LOGTAG, "test completion callback");
153-
mStats.setData(data);
154-
synchronized (mStats) {
155-
mStats.notify();
270+
public void testMetrics() {
271+
setScrollingTestingMode(true);
272+
if (checkMedia() && runTestDirs(SCROLL_TEST_DIRS)) {
273+
getInstrumentation().sendStatus(0, mStats.getBundle());
274+
} else {
275+
getInstrumentation().sendStatus(1, null);
276+
}
277+
}
278+
279+
private boolean runAnimationTests() {
280+
for (int doubleBuffer = 0; doubleBuffer <= 1; doubleBuffer++) {
281+
mDoubleBuffering = doubleBuffer == 1;
282+
pushDoubleBuffering();
283+
for (mAnimTestNr = 0; mAnimTestNr < ANIM_TESTS.length; mAnimTestNr++) {
284+
mAnimTests = ANIM_TESTS[mAnimTestNr];
285+
if (!runTestDirs(ANIM_TEST_DIRS)) {
286+
return false;
156287
}
157288
}
158-
});
289+
}
290+
return true;
291+
}
159292

160-
for (int i = 0; i < MAX_ITERATIONS; i++)
161-
if (!runIteration()) {
162-
getInstrumentation().sendStatus(1, null);
163-
return;
164-
}
165-
getInstrumentation().sendStatus(0, mStats.getBundle());
293+
public void testAnimations() {
294+
// instead of autoscrolling, load each page until either an timer fires,
295+
// or the animation signals complete via javascript
296+
setScrollingTestingMode(false);
297+
298+
if (checkMedia() && runAnimationTests()) {
299+
getInstrumentation().sendStatus(0, mStats.getBundle());
300+
} else {
301+
getInstrumentation().sendStatus(1, null);
302+
}
166303
}
167304
}

0 commit comments

Comments
 (0)