1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.test.tilebenchmark; 18 19 import com.test.tilebenchmark.ProfileActivity.ProfileCallback; 20 21 import java.io.File; 22 import java.util.HashMap; 23 import java.util.Map; 24 25 import android.content.res.Resources; 26 import android.os.Bundle; 27 import android.os.Environment; 28 import android.test.ActivityInstrumentationTestCase2; 29 import android.util.Log; 30 import android.webkit.WebSettings; 31 import android.widget.Spinner; 32 33 public class PerformanceTest extends 34 ActivityInstrumentationTestCase2<ProfileActivity> { 35 36 public static class AnimStat { 37 double aggVal = 0; 38 double aggSqrVal = 0; 39 double count = 0; 40 } 41 42 private class StatAggregator extends PlaybackGraphs { 43 private HashMap<String, Double> mDataMap = new HashMap<String, Double>(); 44 private HashMap<String, AnimStat> mAnimDataMap = new HashMap<String, AnimStat>(); 45 private int mCount = 0; 46 47 aggregate()48 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 80 mCount++; 81 for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) { 82 for (int statIndex = 0; statIndex < Stats.length; statIndex++) { 83 String metricLabel = resources.getString( 84 Metrics[metricIndex].getLabelId()); 85 String statLabel = resources.getString( 86 Stats[statIndex].getLabelId()); 87 88 String label = metricLabel + " " + statLabel; 89 double aggVal = mDataMap.containsKey(label) ? mDataMap 90 .get(label) : 0; 91 92 aggVal += mStats[metricIndex][statIndex]; 93 mDataMap.put(label, aggVal); 94 } 95 } 96 97 } 98 99 // build the final bundle of results getBundle()100 public Bundle getBundle() { 101 Bundle b = new Bundle(); 102 int count = (0 == mCount) ? Integer.MAX_VALUE : mCount; 103 for (Map.Entry<String, Double> e : mDataMap.entrySet()) { 104 b.putDouble(e.getKey(), e.getValue() / count); 105 } 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 118 return b; 119 } 120 } 121 122 ProfileActivity mActivity; 123 ProfiledWebView mWeb; 124 Spinner mMovementSpinner; 125 StatAggregator mStats; 126 127 private static final String LOGTAG = "PerformanceTest"; 128 private static final String TEST_LOCATION = "webkit/page_cycler"; 129 private static final String URL_PREFIX = "file://"; 130 private static final String URL_POSTFIX = "/index.html?skip=true"; 131 private static final int MAX_ITERATIONS = 4; 132 private static final String SCROLL_TEST_DIRS[] = { 133 "alexa25_2011" 134 }; 135 private static final String ANIM_TEST_DIRS[] = { 136 "dhtml" 137 }; 138 PerformanceTest()139 public PerformanceTest() { 140 super(ProfileActivity.class); 141 } 142 143 @Override setUp()144 protected void setUp() throws Exception { 145 super.setUp(); 146 mActivity = getActivity(); 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 163 } 164 loadUrl(final String url)165 private boolean loadUrl(final String url) { 166 try { 167 Log.d(LOGTAG, "test starting for url " + url); 168 mActivity.runOnUiThread(new Runnable() { 169 @Override 170 public void run() { 171 mWeb.loadUrl(url); 172 } 173 }); 174 synchronized (mStats) { 175 mStats.wait(); 176 } 177 178 mStats.aggregate(); 179 } catch (InterruptedException e) { 180 e.printStackTrace(); 181 return false; 182 } 183 return true; 184 } 185 validTest(String nextTest)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 runIteration(String[] testDirs)199 private boolean runIteration(String[] testDirs) { 200 File sdFile = Environment.getExternalStorageDirectory(); 201 for (String testDirName : testDirs) { 202 File testDir = new File(sdFile, TEST_LOCATION + "/" + testDirName); 203 Log.d(LOGTAG, "Testing dir: '" + testDir.getAbsolutePath() 204 + "', exists=" + testDir.exists()); 205 206 for (File siteDir : testDir.listFiles()) { 207 if (!siteDir.isDirectory() || !validTest(siteDir.getName())) { 208 continue; 209 } 210 211 if (!loadUrl(URL_PREFIX + siteDir.getAbsolutePath() 212 + URL_POSTFIX)) { 213 return false; 214 } 215 } 216 } 217 return true; 218 } 219 runTestDirs(String[] testDirs)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 pushDoubleBuffering()228 private void pushDoubleBuffering() { 229 getInstrumentation().runOnMainSync(new Runnable() { 230 public void run() { 231 mWeb.setDoubleBuffering(mDoubleBuffering); 232 } 233 }); 234 } 235 setScrollingTestingMode(final boolean scrolled)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 checkMedia()257 private boolean checkMedia() { 258 String state = Environment.getExternalStorageState(); 259 260 if (!Environment.MEDIA_MOUNTED.equals(state) 261 && !Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 262 Log.d(LOGTAG, "ARG Can't access sd card!"); 263 // Can't read the SD card, fail and die! 264 getInstrumentation().sendStatus(1, null); 265 return false; 266 } 267 return true; 268 } 269 testMetrics()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 testMetricsMinimalMemory()279 public void testMetricsMinimalMemory() { 280 mActivity.runOnUiThread(new Runnable() { 281 @Override 282 public void run() { 283 mWeb.setUseMinimalMemory(true); 284 } 285 }); 286 287 setScrollingTestingMode(true); 288 if (checkMedia() && runTestDirs(SCROLL_TEST_DIRS)) { 289 getInstrumentation().sendStatus(0, mStats.getBundle()); 290 } else { 291 getInstrumentation().sendStatus(1, null); 292 } 293 } 294 runAnimationTests()295 private boolean runAnimationTests() { 296 for (int doubleBuffer = 0; doubleBuffer <= 1; doubleBuffer++) { 297 mDoubleBuffering = doubleBuffer == 1; 298 pushDoubleBuffering(); 299 for (mAnimTestNr = 0; mAnimTestNr < ANIM_TESTS.length; mAnimTestNr++) { 300 mAnimTests = ANIM_TESTS[mAnimTestNr]; 301 if (!runTestDirs(ANIM_TEST_DIRS)) { 302 return false; 303 } 304 } 305 } 306 return true; 307 } 308 testAnimations()309 public void testAnimations() { 310 // instead of autoscrolling, load each page until either an timer fires, 311 // or the animation signals complete via javascript 312 setScrollingTestingMode(false); 313 314 if (checkMedia() && runAnimationTests()) { 315 getInstrumentation().sendStatus(0, mStats.getBundle()); 316 } else { 317 getInstrumentation().sendStatus(1, null); 318 } 319 } 320 } 321