summaryrefslogtreecommitdiffstats
path: root/tests/TileBenchmark
diff options
context:
space:
mode:
authorChris Craik <ccraik@google.com>2012-01-23 17:29:12 -0800
committerChris Craik <ccraik@google.com>2012-01-24 13:25:49 -0800
commit702c6fdc4799593c16eb0051703e3bd62086ff42 (patch)
treea78f71f31b5c8a6281e2c913d66c79fc49d6ca3c /tests/TileBenchmark
parentd4e34d61d01222ff90684b9a1dc4f9c8be560e7c (diff)
downloadframeworks_base-702c6fdc4799593c16eb0051703e3bd62086ff42.zip
frameworks_base-702c6fdc4799593c16eb0051703e3bd62086ff42.tar.gz
frameworks_base-702c6fdc4799593c16eb0051703e3bd62086ff42.tar.bz2
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
Diffstat (limited to 'tests/TileBenchmark')
-rw-r--r--tests/TileBenchmark/res/values/strings.xml16
-rw-r--r--tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java205
-rw-r--r--tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java107
-rw-r--r--tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java69
-rw-r--r--tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java103
5 files changed, 400 insertions, 100 deletions
diff --git a/tests/TileBenchmark/res/values/strings.xml b/tests/TileBenchmark/res/values/strings.xml
index 5af52dc..6c7055b 100644
--- a/tests/TileBenchmark/res/values/strings.xml
+++ b/tests/TileBenchmark/res/values/strings.xml
@@ -49,8 +49,9 @@
<!-- Drop down menu entry - automatically scroll to the end of the page
with scrollBy() [CHAR LIMIT=15] -->
<string name="movement_auto_scroll">Auto-scroll</string>
- <!-- Drop down menu entry - [CHAR LIMIT=15] -->
- <string name="movement_auto_fling">Auto-fling</string>
+ <!-- Drop down menu entry - automatically record for a set time before
+ stopping [CHAR LIMIT=15] -->
+ <string name="movement_timed">Timed</string>
<!-- Drop down menu entry - manually navigate the page(s), hit 'capture'
button [CHAR LIMIT=15] -->
<string name="movement_manual">Manual</string>
@@ -67,14 +68,21 @@
<!-- 75th percentile - 75% of frames fall below this value [CHAR LIMIT=12]
-->
<string name="percentile_75">75%ile</string>
+ <!-- standard deviation [CHAR LIMIT=12] -->
+ <string name="std_dev">StdDev</string>
+ <!-- mean [CHAR LIMIT=12] -->
+ <string name="mean">mean</string>
+
+
+
<!-- Frame rate [CHAR LIMIT=15] -->
<string name="frames_per_second">Frames/sec</string>
<!-- Portion of viewport covered by good tiles [CHAR LIMIT=15] -->
<string name="viewport_coverage">Coverage</string>
<!-- Milliseconds taken to inval, and re-render the page [CHAR LIMIT=15] -->
<string name="render_millis">RenderMillis</string>
- <!-- Number of rendering stalls while running the test [CHAR LIMIT=15] -->
- <string name="render_stalls">Stalls</string>
+ <!-- Animation Framerate [CHAR LIMIT=15] -->
+ <string name="animation_framerate">AnimFramerate</string>
<!-- Format string for stat value overlay [CHAR LIMIT=15] -->
<string name="format_stat">%4.4f</string>
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java
index cc39b75..6356cc1 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java
@@ -27,17 +27,57 @@ import android.os.Bundle;
import android.os.Environment;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
+import android.webkit.WebSettings;
+import android.widget.Spinner;
public class PerformanceTest extends
ActivityInstrumentationTestCase2<ProfileActivity> {
+ public static class AnimStat {
+ double aggVal = 0;
+ double aggSqrVal = 0;
+ double count = 0;
+ }
+
private class StatAggregator extends PlaybackGraphs {
private HashMap<String, Double> mDataMap = new HashMap<String, Double>();
+ private HashMap<String, AnimStat> mAnimDataMap = new HashMap<String, AnimStat>();
private int mCount = 0;
+
public void aggregate() {
+ boolean inAnimTests = mAnimTests != null;
+ Resources resources = mWeb.getResources();
+ String animFramerateString = resources.getString(R.string.animation_framerate);
+ for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
+ String name = e.getKey();
+ if (inAnimTests) {
+ if (name.equals(animFramerateString)) {
+ // in animation testing phase, record animation framerate and aggregate
+ // stats, differentiating on values of mAnimTestNr and mDoubleBuffering
+ String fullName = ANIM_TEST_NAMES[mAnimTestNr] + " " + name;
+ fullName += mDoubleBuffering ? " tiled" : " webkit";
+
+ if (!mAnimDataMap.containsKey(fullName)) {
+ mAnimDataMap.put(fullName, new AnimStat());
+ }
+ AnimStat statVals = mAnimDataMap.get(fullName);
+ statVals.aggVal += e.getValue();
+ statVals.aggSqrVal += e.getValue() * e.getValue();
+ statVals.count += 1;
+ }
+ } else {
+ double aggVal = mDataMap.containsKey(name)
+ ? mDataMap.get(name) : 0;
+ mDataMap.put(name, aggVal + e.getValue());
+ }
+ }
+
+ if (inAnimTests) {
+ return;
+ }
+
mCount++;
- Resources resources = mView.getResources();
for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
String metricLabel = resources.getString(
@@ -53,34 +93,47 @@ public class PerformanceTest extends
mDataMap.put(label, aggVal);
}
}
- for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
- double aggVal = mDataMap.containsKey(e.getKey())
- ? mDataMap.get(e.getKey()) : 0;
- mDataMap.put(e.getKey(), aggVal + e.getValue());
- }
+
}
+ // build the final bundle of results
public Bundle getBundle() {
Bundle b = new Bundle();
- int count = 0 == mCount ? Integer.MAX_VALUE : mCount;
+ int count = (0 == mCount) ? Integer.MAX_VALUE : mCount;
for (Map.Entry<String, Double> e : mDataMap.entrySet()) {
b.putDouble(e.getKey(), e.getValue() / count);
}
+
+ for (Map.Entry<String, AnimStat> e : mAnimDataMap.entrySet()) {
+ String statName = e.getKey();
+ AnimStat statVals = e.getValue();
+
+ double avg = statVals.aggVal/statVals.count;
+ double stdDev = Math.sqrt((statVals.aggSqrVal / statVals.count) - avg * avg);
+
+ b.putDouble(statName, avg);
+ b.putDouble(statName + " STD DEV", stdDev);
+ }
+
return b;
}
}
ProfileActivity mActivity;
- ProfiledWebView mView;
- StatAggregator mStats = new StatAggregator();
+ ProfiledWebView mWeb;
+ Spinner mMovementSpinner;
+ StatAggregator mStats;
private static final String LOGTAG = "PerformanceTest";
private static final String TEST_LOCATION = "webkit/page_cycler";
private static final String URL_PREFIX = "file://";
private static final String URL_POSTFIX = "/index.html?skip=true";
private static final int MAX_ITERATIONS = 4;
- private static final String TEST_DIRS[] = {
- "alexa25_2011"//, "alexa_us", "android", "dom", "intl2", "moz", "moz2"
+ private static final String SCROLL_TEST_DIRS[] = {
+ "alexa25_2011"
+ };
+ private static final String ANIM_TEST_DIRS[] = {
+ "dhtml"
};
public PerformanceTest() {
@@ -91,7 +144,22 @@ public class PerformanceTest extends
protected void setUp() throws Exception {
super.setUp();
mActivity = getActivity();
- mView = (ProfiledWebView) mActivity.findViewById(R.id.web);
+ mWeb = (ProfiledWebView) mActivity.findViewById(R.id.web);
+ mMovementSpinner = (Spinner) mActivity.findViewById(R.id.movement);
+ mStats = new StatAggregator();
+
+ // use mStats as a condition variable between the UI thread and
+ // this(the testing) thread
+ mActivity.setCallback(new ProfileCallback() {
+ @Override
+ public void profileCallback(RunData data) {
+ mStats.setData(data);
+ synchronized (mStats) {
+ mStats.notify();
+ }
+ }
+ });
+
}
private boolean loadUrl(final String url) {
@@ -100,12 +168,13 @@ public class PerformanceTest extends
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
- mView.loadUrl(url);
+ mWeb.loadUrl(url);
}
});
synchronized (mStats) {
mStats.wait();
}
+
mStats.aggregate();
} catch (InterruptedException e) {
e.printStackTrace();
@@ -114,15 +183,30 @@ public class PerformanceTest extends
return true;
}
- private boolean runIteration() {
+ private boolean validTest(String nextTest) {
+ // if testing animations, test must be in mAnimTests
+ if (mAnimTests == null)
+ return true;
+
+ for (String test : mAnimTests) {
+ if (test.equals(nextTest)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean runIteration(String[] testDirs) {
File sdFile = Environment.getExternalStorageDirectory();
- for (String testDirName : TEST_DIRS) {
+ for (String testDirName : testDirs) {
File testDir = new File(sdFile, TEST_LOCATION + "/" + testDirName);
Log.d(LOGTAG, "Testing dir: '" + testDir.getAbsolutePath()
+ "', exists=" + testDir.exists());
+
for (File siteDir : testDir.listFiles()) {
- if (!siteDir.isDirectory())
+ if (!siteDir.isDirectory() || !validTest(siteDir.getName())) {
continue;
+ }
if (!loadUrl(URL_PREFIX + siteDir.getAbsolutePath()
+ URL_POSTFIX)) {
@@ -133,7 +217,44 @@ public class PerformanceTest extends
return true;
}
- public void testMetrics() {
+ private boolean runTestDirs(String[] testDirs) {
+ for (int i = 0; i < MAX_ITERATIONS; i++)
+ if (!runIteration(testDirs)) {
+ return false;
+ }
+ return true;
+ }
+
+ private void pushDoubleBuffering() {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ public void run() {
+ mWeb.setDoubleBuffering(mDoubleBuffering);
+ }
+ });
+ }
+
+ private void setScrollingTestingMode(final boolean scrolled) {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ public void run() {
+ mMovementSpinner.setSelection(scrolled ? 0 : 2);
+ }
+ });
+ }
+
+
+ private String[] mAnimTests = null;
+ private int mAnimTestNr = -1;
+ private boolean mDoubleBuffering = true;
+ private static final String[] ANIM_TEST_NAMES = {
+ "slow", "fast"
+ };
+ private static final String[][] ANIM_TESTS = {
+ {"scrolling", "replaceimages", "layers5", "layers1"},
+ {"slidingballs", "meter", "slidein", "fadespacing", "colorfade",
+ "mozilla", "movingtext", "diagball", "zoom", "imageslide"},
+ };
+
+ private boolean checkMedia() {
String state = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(state)
@@ -141,27 +262,43 @@ public class PerformanceTest extends
Log.d(LOGTAG, "ARG Can't access sd card!");
// Can't read the SD card, fail and die!
getInstrumentation().sendStatus(1, null);
- return;
+ return false;
}
+ return true;
+ }
- // use mGraphs as a condition variable between the UI thread and
- // this(the testing) thread
- mActivity.setCallback(new ProfileCallback() {
- @Override
- public void profileCallback(RunData data) {
- Log.d(LOGTAG, "test completion callback");
- mStats.setData(data);
- synchronized (mStats) {
- mStats.notify();
+ public void testMetrics() {
+ setScrollingTestingMode(true);
+ if (checkMedia() && runTestDirs(SCROLL_TEST_DIRS)) {
+ getInstrumentation().sendStatus(0, mStats.getBundle());
+ } else {
+ getInstrumentation().sendStatus(1, null);
+ }
+ }
+
+ private boolean runAnimationTests() {
+ for (int doubleBuffer = 0; doubleBuffer <= 1; doubleBuffer++) {
+ mDoubleBuffering = doubleBuffer == 1;
+ pushDoubleBuffering();
+ for (mAnimTestNr = 0; mAnimTestNr < ANIM_TESTS.length; mAnimTestNr++) {
+ mAnimTests = ANIM_TESTS[mAnimTestNr];
+ if (!runTestDirs(ANIM_TEST_DIRS)) {
+ return false;
}
}
- });
+ }
+ return true;
+ }
- for (int i = 0; i < MAX_ITERATIONS; i++)
- if (!runIteration()) {
- getInstrumentation().sendStatus(1, null);
- return;
- }
- getInstrumentation().sendStatus(0, mStats.getBundle());
+ public void testAnimations() {
+ // instead of autoscrolling, load each page until either an timer fires,
+ // or the animation signals complete via javascript
+ setScrollingTestingMode(false);
+
+ if (checkMedia() && runAnimationTests()) {
+ getInstrumentation().sendStatus(0, mStats.getBundle());
+ } else {
+ getInstrumentation().sendStatus(1, null);
+ }
}
}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
index 9ea90f8..a3ae9be 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
@@ -80,7 +80,7 @@ public class PlaybackGraphs {
for (int tileID = 1; tileID < frame.length; tileID++) {
TileData data = frame[tileID];
double coverage = viewportCoverage(frame[0], data);
- total += coverage * (data.isReady ? 1 : 0);
+ total += coverage * (data.isReady ? 100 : 0);
totalCount += coverage;
}
if (totalCount == 0) {
@@ -91,7 +91,7 @@ public class PlaybackGraphs {
@Override
public double getMax() {
- return 1;
+ return 100;
}
@Override
@@ -108,6 +108,9 @@ public class PlaybackGraphs {
}
public static double getPercentile(double sortedValues[], double ratioAbove) {
+ if (sortedValues.length == 0)
+ return -1;
+
double index = ratioAbove * (sortedValues.length - 1);
int intIndex = (int) Math.floor(index);
if (index == intIndex) {
@@ -118,6 +121,31 @@ public class PlaybackGraphs {
+ sortedValues[intIndex + 1] * (alpha);
}
+ public static double getMean(double sortedValues[]) {
+ if (sortedValues.length == 0)
+ return -1;
+
+ double agg = 0;
+ for (double val : sortedValues) {
+ agg += val;
+ }
+ return agg / sortedValues.length;
+ }
+
+ public static double getStdDev(double sortedValues[]) {
+ if (sortedValues.length == 0)
+ return -1;
+
+ double agg = 0;
+ double sqrAgg = 0;
+ for (double val : sortedValues) {
+ agg += val;
+ sqrAgg += val*val;
+ }
+ double mean = agg / sortedValues.length;
+ return Math.sqrt((sqrAgg / sortedValues.length) - (mean * mean));
+ }
+
protected static StatGen[] Stats = new StatGen[] {
new StatGen() {
@Override
@@ -149,6 +177,26 @@ public class PlaybackGraphs {
public int getLabelId() {
return R.string.percentile_75;
}
+ }, new StatGen() {
+ @Override
+ public double getValue(double[] sortedValues) {
+ return getStdDev(sortedValues);
+ }
+
+ @Override
+ public int getLabelId() {
+ return R.string.std_dev;
+ }
+ }, new StatGen() {
+ @Override
+ public double getValue(double[] sortedValues) {
+ return getMean(sortedValues);
+ }
+
+ @Override
+ public int getLabelId() {
+ return R.string.mean;
+ }
},
};
@@ -159,40 +207,47 @@ public class PlaybackGraphs {
}
private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>();
- protected double[][] mStats = new double[Metrics.length][Stats.length];
+ protected final double[][] mStats = new double[Metrics.length][Stats.length];
protected HashMap<String, Double> mSingleStats;
+ private void gatherFrameMetric(int metricIndex, double metricValues[], RunData data) {
+ // create graph out of rectangles, one per frame
+ int lastBar = 0;
+ for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
+ TileData frame[] = data.frames[frameIndex];
+ int newBar = (frame[0].top + frame[0].bottom) / 2;
+
+ MetricGen s = Metrics[metricIndex];
+ double absoluteValue = s.getValue(frame);
+ double relativeValue = absoluteValue / s.getMax();
+ relativeValue = Math.min(1,relativeValue);
+ relativeValue = Math.max(0,relativeValue);
+ int rightPos = (int) (-BAR_WIDTH * metricIndex);
+ int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue));
+
+ ShapeDrawable graphBar = new ShapeDrawable();
+ graphBar.getPaint().setColor(Color.BLUE);
+ graphBar.setBounds(leftPos, lastBar, rightPos, newBar);
+
+ mShapes.add(graphBar);
+ metricValues[frameIndex] = absoluteValue;
+ lastBar = newBar;
+ }
+ }
+
public void setData(RunData data) {
mShapes.clear();
double metricValues[] = new double[data.frames.length];
+ mSingleStats = data.singleStats;
+
if (data.frames.length == 0) {
return;
}
for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
- // create graph out of rectangles, one per frame
- int lastBar = 0;
- for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
- TileData frame[] = data.frames[frameIndex];
- int newBar = (frame[0].top + frame[0].bottom) / 2;
-
- MetricGen s = Metrics[metricIndex];
- double absoluteValue = s.getValue(frame);
- double relativeValue = absoluteValue / s.getMax();
- relativeValue = Math.min(1,relativeValue);
- relativeValue = Math.max(0,relativeValue);
- int rightPos = (int) (-BAR_WIDTH * metricIndex);
- int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue));
-
- ShapeDrawable graphBar = new ShapeDrawable();
- graphBar.getPaint().setColor(Color.BLUE);
- graphBar.setBounds(leftPos, lastBar, rightPos, newBar);
-
- mShapes.add(graphBar);
- metricValues[frameIndex] = absoluteValue;
- lastBar = newBar;
- }
+ // calculate metric based on list of frames
+ gatherFrameMetric(metricIndex, metricValues, data);
// store aggregate statistics per metric (median, and similar)
Arrays.sort(metricValues);
@@ -200,8 +255,6 @@ public class PlaybackGraphs {
mStats[metricIndex][statIndex] =
Stats[statIndex].getValue(metricValues);
}
-
- mSingleStats = data.singleStats;
}
}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
index d38d006..2e77157 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
@@ -22,11 +22,12 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.util.Log;
import android.util.Pair;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
-import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.AdapterView;
@@ -49,6 +50,8 @@ import java.io.ObjectOutputStream;
*/
public class ProfileActivity extends Activity {
+ private static final int TIMED_RECORD_MILLIS = 2000;
+
public interface ProfileCallback {
public void profileCallback(RunData data);
}
@@ -65,6 +68,7 @@ public class ProfileActivity extends Activity {
LoggingWebViewClient mLoggingWebViewClient = new LoggingWebViewClient();
AutoLoggingWebViewClient mAutoLoggingWebViewClient = new AutoLoggingWebViewClient();
+ TimedLoggingWebViewClient mTimedLoggingWebViewClient = new TimedLoggingWebViewClient();
private enum TestingState {
NOT_TESTING,
@@ -93,18 +97,18 @@ public class ProfileActivity extends Activity {
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
String movementStr = parent.getItemAtPosition(position).toString();
- if (movementStr == getResources().getString(
- R.string.movement_auto_scroll)
- || movementStr == getResources().getString(
- R.string.movement_auto_fling)) {
+ if (movementStr == getResources().getString(R.string.movement_auto_scroll)) {
mWeb.setWebViewClient(mAutoLoggingWebViewClient);
mCaptureButton.setEnabled(false);
mVelocitySpinner.setEnabled(true);
- } else if (movementStr == getResources().getString(
- R.string.movement_manual)) {
+ } else if (movementStr == getResources().getString(R.string.movement_manual)) {
mWeb.setWebViewClient(mLoggingWebViewClient);
mCaptureButton.setEnabled(true);
mVelocitySpinner.setEnabled(false);
+ } else if (movementStr == getResources().getString(R.string.movement_timed)) {
+ mWeb.setWebViewClient(mTimedLoggingWebViewClient);
+ mCaptureButton.setEnabled(false);
+ mVelocitySpinner.setEnabled(false);
}
}
@@ -124,16 +128,46 @@ public class ProfileActivity extends Activity {
super.onPageStarted(view, url, favicon);
mUrl.setText(url);
}
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ view.requestFocus();
+ ((ProfiledWebView)view).onPageFinished();
+ }
}
private class AutoLoggingWebViewClient extends LoggingWebViewClient {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ startViewProfiling(true);
+ }
@Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ super.onPageStarted(view, url, favicon);
+ setTestingState(TestingState.PRE_TESTING);
+ }
+ }
+
+ private class TimedLoggingWebViewClient extends LoggingWebViewClient {
+ @Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
- view.requestFocus();
+ startViewProfiling(false);
- startViewProfiling(true);
+ // after a fixed time after page finished, stop testing
+ new CountDownTimer(TIMED_RECORD_MILLIS, TIMED_RECORD_MILLIS) {
+ @Override
+ public void onTick(long millisUntilFinished) {
+ }
+
+ @Override
+ public void onFinish() {
+ mWeb.stopScrollTest();
+ }
+ }.start();
}
@Override
@@ -178,11 +212,13 @@ public class ProfileActivity extends Activity {
mMovementSpinner.setEnabled(false);
break;
case START_TESTING:
+ mCaptureButton.setChecked(true);
mUrl.setBackgroundResource(R.color.background_start_testing);
mInspectButton.setEnabled(false);
mMovementSpinner.setEnabled(false);
break;
case STOP_TESTING:
+ mCaptureButton.setChecked(false);
mUrl.setBackgroundResource(R.color.background_stop_testing);
break;
case SAVED_TESTING:
@@ -195,7 +231,6 @@ public class ProfileActivity extends Activity {
/** auto - automatically scroll. */
private void startViewProfiling(boolean auto) {
// toggle capture button to indicate capture state to user
- mCaptureButton.setChecked(true);
mWeb.startScrollTest(mCallback, auto);
setTestingState(TestingState.START_TESTING);
}
@@ -217,7 +252,7 @@ public class ProfileActivity extends Activity {
public void profileCallback(RunData data) {
new StoreFileTask().execute(new Pair<String, RunData>(
TEMP_FILENAME, data));
- mCaptureButton.setChecked(false);
+ Log.d("ProfileActivity", "stored " + data.frames.length + " frames in file");
setTestingState(TestingState.STOP_TESTING);
}
});
@@ -245,8 +280,8 @@ public class ProfileActivity extends Activity {
// Movement spinner
String content[] = {
getResources().getString(R.string.movement_auto_scroll),
- getResources().getString(R.string.movement_auto_fling),
- getResources().getString(R.string.movement_manual)
+ getResources().getString(R.string.movement_manual),
+ getResources().getString(R.string.movement_timed)
};
adapter = new ArrayAdapter<CharSequence>(this,
android.R.layout.simple_spinner_item, content);
@@ -270,13 +305,7 @@ public class ProfileActivity extends Activity {
});
// Custom profiling WebView
- WebSettings settings = mWeb.getSettings();
- settings.setJavaScriptEnabled(true);
- settings.setSupportZoom(true);
- settings.setEnableSmoothTransition(true);
- settings.setBuiltInZoomControls(true);
- settings.setLoadWithOverviewMode(true);
- settings.setProperty("use_minimal_memory", "false"); // prefetch tiles, as browser does
+ mWeb.init(this);
mWeb.setWebViewClient(new LoggingWebViewClient());
// URL text entry
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
index 83f1668..a706f78 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
@@ -20,21 +20,28 @@ import android.content.Context;
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.util.Log;
+import android.webkit.WebSettings;
import android.webkit.WebView;
+import android.widget.Toast;
+
+import java.util.ArrayList;
import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
import com.test.tilebenchmark.RunData.TileData;
public class ProfiledWebView extends WebView {
+ private static final String LOGTAG = "ProfiledWebView";
+
private int mSpeed;
private boolean mIsTesting = false;
private boolean mIsScrolling = false;
private ProfileCallback mCallback;
private long mContentInvalMillis;
- private boolean mHadToBeForced = false;
private static final int LOAD_STALL_MILLIS = 2000; // nr of millis after load,
// before test is forced
+ private double mLoadTime;
+ private double mAnimationTime;
public ProfiledWebView(Context context) {
super(context);
@@ -53,6 +60,39 @@ public class ProfiledWebView extends WebView {
super(context, attrs, defStyle, privateBrowsing);
}
+ private class JavaScriptInterface {
+ Context mContext;
+
+ /** Instantiate the interface and set the context */
+ JavaScriptInterface(Context c) {
+ mContext = c;
+ }
+
+ /** Show a toast from the web page */
+ public void animationComplete() {
+ Toast.makeText(mContext, "Animation complete!", Toast.LENGTH_SHORT).show();
+ //Log.d(LOGTAG, "anim complete");
+ mAnimationTime = System.currentTimeMillis();
+ }
+ }
+
+ public void init(Context c) {
+ WebSettings settings = getSettings();
+ settings.setJavaScriptEnabled(true);
+ settings.setSupportZoom(true);
+ settings.setEnableSmoothTransition(true);
+ settings.setBuiltInZoomControls(true);
+ settings.setLoadWithOverviewMode(true);
+ settings.setProperty("use_minimal_memory", "false"); // prefetch tiles, as browser does
+ addJavascriptInterface(new JavaScriptInterface(c), "Android");
+ mAnimationTime = 0;
+ mLoadTime = 0;
+ }
+
+ public void onPageFinished() {
+ mLoadTime = System.currentTimeMillis();
+ }
+
@Override
protected void onDraw(android.graphics.Canvas canvas) {
if (mIsTesting && mIsScrolling) {
@@ -72,9 +112,12 @@ public class ProfiledWebView extends WebView {
* scrolling, invalidate all content and redraw it, measuring time taken.
*/
public void startScrollTest(ProfileCallback callback, boolean autoScrolling) {
- mIsScrolling = autoScrolling;
mCallback = callback;
mIsTesting = false;
+ mIsScrolling = false;
+ WebSettings settings = getSettings();
+ settings.setProperty("tree_updates", "0");
+
if (autoScrolling) {
// after a while, force it to start even if the pages haven't swapped
@@ -86,13 +129,18 @@ public class ProfiledWebView extends WebView {
@Override
public void onFinish() {
// invalidate all content, and kick off redraw
+ Log.d("ProfiledWebView",
+ "kicking off test with callback registration, and tile discard...");
registerPageSwapCallback();
discardAllTextures();
invalidate();
-
+ mIsScrolling = true;
mContentInvalMillis = System.currentTimeMillis();
}
}.start();
+ } else {
+ mIsTesting = true;
+ tileProfilingStart();
}
}
@@ -102,13 +150,35 @@ public class ProfiledWebView extends WebView {
*/
@Override
protected void pageSwapCallback(boolean startAnim) {
- mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
- super.pageSwapCallback(startAnim);
- Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis
- + "millis");
- mIsTesting = true;
- invalidate(); // ensure a redraw so that auto-scrolling can occur
- tileProfilingStart();
+ if (!mIsTesting && mIsScrolling) {
+ // kick off testing
+ mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
+ super.pageSwapCallback(startAnim);
+ Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis + "millis");
+ mIsTesting = true;
+ invalidate(); // ensure a redraw so that auto-scrolling can occur
+ tileProfilingStart();
+ }
+ }
+
+ private double animFramerate() {
+ WebSettings settings = getSettings();
+ String updatesString = settings.getProperty("tree_updates");
+ int updates = (updatesString == null) ? -1 : Integer.parseInt(updatesString);
+
+ double animationTime;
+ if (mAnimationTime == 0) {
+ animationTime = System.currentTimeMillis() - mLoadTime;
+ } else {
+ animationTime = mAnimationTime - mLoadTime;
+ }
+
+ return updates * 1000 / animationTime;
+ }
+
+ public void setDoubleBuffering(boolean useDoubleBuffering) {
+ WebSettings settings = getSettings();
+ settings.setProperty("use_double_buffering", useDoubleBuffering ? "true" : "false");
}
/*
@@ -127,11 +197,12 @@ public class ProfiledWebView extends WebView {
// record the time spent (before scrolling) rendering the page
data.singleStats.put(getResources().getString(R.string.render_millis),
(double)mContentInvalMillis);
- // record if the page render timed out
- Log.d("ProfiledWebView", "hadtobeforced = " + mHadToBeForced);
- data.singleStats.put(getResources().getString(R.string.render_stalls),
- mHadToBeForced ? 1.0 : 0.0);
- mHadToBeForced = false;
+
+ // record framerate
+ double framerate = animFramerate();
+ Log.d(LOGTAG, "anim framerate was "+framerate);
+ data.singleStats.put(getResources().getString(R.string.animation_framerate),
+ framerate);
for (int frame = 0; frame < data.frames.length; frame++) {
data.frames[frame] = new TileData[
@@ -159,6 +230,8 @@ public class ProfiledWebView extends WebView {
@Override
public void loadUrl(String url) {
+ mAnimationTime = 0;
+ mLoadTime = 0;
if (!url.startsWith("http://") && !url.startsWith("file://")) {
url = "http://" + url;
}