The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 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.android.dumprendertree; |
| 18 | |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 19 | import com.android.dumprendertree.forwarder.AdbUtils; |
| 20 | import com.android.dumprendertree.forwarder.ForwardServer; |
| 21 | |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 22 | import android.app.Instrumentation; |
Guang Zhu | 0006952 | 2010-12-06 11:17:38 -0800 | [diff] [blame] | 23 | import android.content.Context; |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 24 | import android.content.Intent; |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 25 | import android.os.Bundle; |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 26 | import android.os.Debug; |
Christian Mehlmauer | 8b85dce | 2010-07-19 20:11:27 +0200 | [diff] [blame] | 27 | import android.os.Environment; |
Guang Zhu | 40656be | 2009-06-30 11:56:13 -0700 | [diff] [blame] | 28 | import android.os.Process; |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 29 | import android.test.ActivityInstrumentationTestCase2; |
Guang Zhu | 40656be | 2009-06-30 11:56:13 -0700 | [diff] [blame] | 30 | import android.util.Log; |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 31 | |
Guang Zhu | 0006952 | 2010-12-06 11:17:38 -0800 | [diff] [blame] | 32 | import java.io.File; |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 33 | import java.io.FileOutputStream; |
| 34 | import java.io.IOException; |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 35 | import java.io.InputStream; |
| 36 | import java.io.OutputStream; |
| 37 | import java.io.PrintStream; |
Guang Zhu | 5794f23 | 2011-01-25 15:43:57 -0800 | [diff] [blame] | 38 | import java.util.concurrent.CountDownLatch; |
| 39 | import java.util.concurrent.TimeUnit; |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 40 | import java.util.regex.Matcher; |
| 41 | import java.util.regex.Pattern; |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 42 | |
| 43 | public class LoadTestsAutoTest extends ActivityInstrumentationTestCase2<TestShellActivity> { |
| 44 | |
| 45 | private final static String LOGTAG = "LoadTest"; |
Christian Mehlmauer | 8b85dce | 2010-07-19 20:11:27 +0200 | [diff] [blame] | 46 | private final static String LOAD_TEST_RESULT = |
| 47 | Environment.getExternalStorageDirectory() + "/load_test_result.txt"; |
Guang Zhu | 5794f23 | 2011-01-25 15:43:57 -0800 | [diff] [blame] | 48 | private final static int MAX_GC_WAIT_SEC = 10; |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 49 | private final static int LOCAL_PORT = 17171; |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 50 | private boolean mFinished; |
| 51 | static final String LOAD_TEST_RUNNER_FILES[] = { |
| 52 | "run_page_cycler.py" |
Guang Zhu | 4010ac3 | 2009-04-29 14:49:03 -0700 | [diff] [blame] | 53 | }; |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 54 | private ForwardServer mForwardServer; |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 55 | |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 56 | public LoadTestsAutoTest() { |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 57 | super(TestShellActivity.class); |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 58 | } |
| 59 | |
| 60 | // This function writes the result of the layout test to |
| 61 | // Am status so that it can be picked up from a script. |
| 62 | public void passOrFailCallback(String file, boolean result) { |
| 63 | Instrumentation inst = getInstrumentation(); |
| 64 | Bundle bundle = new Bundle(); |
| 65 | bundle.putBoolean(file, result); |
| 66 | inst.sendStatus(0, bundle); |
| 67 | } |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 68 | |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 69 | private String setUpForwarding(String forwardInfo, String suite, String iteration) throws IOException { |
| 70 | // read forwarding information first |
| 71 | Pattern forwardPattern = Pattern.compile("(.*):(\\d+)/(.*)/"); |
| 72 | Matcher matcher = forwardPattern.matcher(forwardInfo); |
| 73 | if (!matcher.matches()) { |
| 74 | throw new RuntimeException("Invalid forward information"); |
| 75 | } |
| 76 | String host = matcher.group(1); |
| 77 | int port = Integer.parseInt(matcher.group(2)); |
| 78 | mForwardServer = new ForwardServer(LOCAL_PORT, AdbUtils.resolve(host), port); |
| 79 | mForwardServer.start(); |
| 80 | return String.format("http://127.0.0.1:%d/%s/%s/start.html?auto=1&iterations=%s", |
| 81 | LOCAL_PORT, matcher.group(3), suite, iteration); |
| 82 | } |
| 83 | |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 84 | // Invokes running of layout tests |
| 85 | // and waits till it has finished running. |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 86 | public void runPageCyclerTest() throws IOException { |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 87 | LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation(); |
| 88 | |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 89 | if (runner.mPageCyclerSuite != null) { |
| 90 | // start forwarder to use page cycler suites hosted on external web server |
| 91 | if (runner.mPageCyclerForwardHost == null) { |
| 92 | throw new RuntimeException("no forwarder information provided"); |
| 93 | } |
| 94 | runner.mTestPath = setUpForwarding(runner.mPageCyclerForwardHost, |
| 95 | runner.mPageCyclerSuite, runner.mPageCyclerIteration); |
| 96 | Log.d(LOGTAG, "using path: " + runner.mTestPath); |
| 97 | } |
| 98 | |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 99 | if (runner.mTestPath == null) { |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 100 | throw new RuntimeException("No test specified"); |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 101 | } |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 102 | |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 103 | TestShellActivity activity = (TestShellActivity) getActivity(); |
| 104 | |
Guang Zhu | 2a197b1 | 2009-05-18 14:37:23 -0700 | [diff] [blame] | 105 | Log.v(LOGTAG, "About to run tests, calling gc first..."); |
Guang Zhu | 40656be | 2009-06-30 11:56:13 -0700 | [diff] [blame] | 106 | freeMem(); |
Guang Zhu | 2a197b1 | 2009-05-18 14:37:23 -0700 | [diff] [blame] | 107 | |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 108 | // Run tests |
Guang Zhu | 5dc4f21 | 2009-10-29 18:24:54 -0700 | [diff] [blame] | 109 | runTestAndWaitUntilDone(activity, runner.mTestPath, runner.mTimeoutInMillis, |
| 110 | runner.mGetDrawTime, runner.mSaveImagePath); |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 111 | |
Guang Zhu | 889181d | 2009-07-09 12:55:15 -0700 | [diff] [blame] | 112 | activity.clearCache(); |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 113 | if (mForwardServer != null) { |
| 114 | mForwardServer.stop(); |
| 115 | mForwardServer = null; |
| 116 | } |
Guang Zhu | 1f6c72b | 2009-07-17 14:22:24 -0700 | [diff] [blame] | 117 | try { |
| 118 | Thread.sleep(5000); |
| 119 | } catch (InterruptedException e) { |
| 120 | } |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 121 | dumpMemoryInfo(); |
| 122 | |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 123 | // Kill activity |
| 124 | activity.finish(); |
| 125 | } |
| 126 | |
Guang Zhu | 40656be | 2009-06-30 11:56:13 -0700 | [diff] [blame] | 127 | private void freeMem() { |
Guang Zhu | 3974be6 | 2011-01-18 18:04:34 -0800 | [diff] [blame] | 128 | Log.v(LOGTAG, "freeMem: calling gc..."); |
Guang Zhu | 5794f23 | 2011-01-25 15:43:57 -0800 | [diff] [blame] | 129 | final CountDownLatch latch = new CountDownLatch(1); |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 130 | @SuppressWarnings("unused") |
Guang Zhu | 5794f23 | 2011-01-25 15:43:57 -0800 | [diff] [blame] | 131 | Object dummy = new Object() { |
Guang Zhu | f6d1b3f | 2011-04-26 16:41:13 -0700 | [diff] [blame] | 132 | // this object instance is used to track gc |
Guang Zhu | 5794f23 | 2011-01-25 15:43:57 -0800 | [diff] [blame] | 133 | @Override |
| 134 | protected void finalize() throws Throwable { |
| 135 | latch.countDown(); |
| 136 | super.finalize(); |
| 137 | } |
| 138 | }; |
| 139 | dummy = null; |
| 140 | System.gc(); |
| 141 | try { |
| 142 | if (!latch.await(MAX_GC_WAIT_SEC, TimeUnit.SECONDS)) { |
| 143 | Log.w(LOGTAG, "gc did not happen in 10s"); |
| 144 | } |
| 145 | } catch (InterruptedException e) { |
| 146 | //ignore |
| 147 | } |
Guang Zhu | 40656be | 2009-06-30 11:56:13 -0700 | [diff] [blame] | 148 | } |
| 149 | |
| 150 | private void printRow(PrintStream ps, String format, Object...objs) { |
| 151 | ps.println(String.format(format, objs)); |
| 152 | } |
| 153 | |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 154 | private void dumpMemoryInfo() { |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 155 | try { |
Guang Zhu | 40656be | 2009-06-30 11:56:13 -0700 | [diff] [blame] | 156 | freeMem(); |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 157 | Log.v(LOGTAG, "Dumping memory information."); |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 158 | |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 159 | FileOutputStream out = new FileOutputStream(LOAD_TEST_RESULT, true); |
| 160 | PrintStream ps = new PrintStream(out); |
| 161 | |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 162 | ps.print("\n\n\n"); |
Guang Zhu | 40656be | 2009-06-30 11:56:13 -0700 | [diff] [blame] | 163 | ps.println("** MEMINFO in pid " + Process.myPid() |
| 164 | + " [com.android.dumprendertree] **"); |
| 165 | String formatString = "%17s %8s %8s %8s %8s"; |
| 166 | |
| 167 | long nativeMax = Debug.getNativeHeapSize() / 1024; |
| 168 | long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024; |
| 169 | long nativeFree = Debug.getNativeHeapFreeSize() / 1024; |
| 170 | Runtime runtime = Runtime.getRuntime(); |
| 171 | long dalvikMax = runtime.totalMemory() / 1024; |
| 172 | long dalvikFree = runtime.freeMemory() / 1024; |
| 173 | long dalvikAllocated = dalvikMax - dalvikFree; |
| 174 | |
| 175 | |
| 176 | Debug.MemoryInfo memInfo = new Debug.MemoryInfo(); |
| 177 | Debug.getMemoryInfo(memInfo); |
| 178 | |
| 179 | final int nativeShared = memInfo.nativeSharedDirty; |
| 180 | final int dalvikShared = memInfo.dalvikSharedDirty; |
| 181 | final int otherShared = memInfo.otherSharedDirty; |
| 182 | |
| 183 | final int nativePrivate = memInfo.nativePrivateDirty; |
| 184 | final int dalvikPrivate = memInfo.dalvikPrivateDirty; |
| 185 | final int otherPrivate = memInfo.otherPrivateDirty; |
| 186 | |
| 187 | printRow(ps, formatString, "", "native", "dalvik", "other", "total"); |
| 188 | printRow(ps, formatString, "size:", nativeMax, dalvikMax, "N/A", nativeMax + dalvikMax); |
| 189 | printRow(ps, formatString, "allocated:", nativeAllocated, dalvikAllocated, "N/A", |
| 190 | nativeAllocated + dalvikAllocated); |
| 191 | printRow(ps, formatString, "free:", nativeFree, dalvikFree, "N/A", |
| 192 | nativeFree + dalvikFree); |
| 193 | |
| 194 | printRow(ps, formatString, "(Pss):", memInfo.nativePss, memInfo.dalvikPss, |
| 195 | memInfo.otherPss, memInfo.nativePss + memInfo.dalvikPss + memInfo.otherPss); |
| 196 | |
| 197 | printRow(ps, formatString, "(shared dirty):", nativeShared, dalvikShared, otherShared, |
| 198 | nativeShared + dalvikShared + otherShared); |
| 199 | printRow(ps, formatString, "(priv dirty):", nativePrivate, dalvikPrivate, otherPrivate, |
| 200 | nativePrivate + dalvikPrivate + otherPrivate); |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 201 | ps.print("\n\n\n"); |
| 202 | ps.flush(); |
| 203 | ps.close(); |
| 204 | out.flush(); |
| 205 | out.close(); |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 206 | } catch (IOException e) { |
| 207 | Log.e(LOGTAG, e.getMessage()); |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 208 | } |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 209 | } |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 210 | |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 211 | // A convenient method to be called by another activity. |
Guang Zhu | 5dc4f21 | 2009-10-29 18:24:54 -0700 | [diff] [blame] | 212 | private void runTestAndWaitUntilDone(TestShellActivity activity, String url, int timeout, |
| 213 | boolean getDrawTime, String saveImagePath) { |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 214 | activity.setCallback(new TestShellCallback() { |
| 215 | public void finished() { |
| 216 | synchronized (LoadTestsAutoTest.this) { |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 217 | mFinished = true; |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 218 | LoadTestsAutoTest.this.notifyAll(); |
| 219 | } |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 220 | } |
Guang Zhu | 40656be | 2009-06-30 11:56:13 -0700 | [diff] [blame] | 221 | |
Guang Zhu | 4010ac3 | 2009-04-29 14:49:03 -0700 | [diff] [blame] | 222 | public void timedOut(String url) { |
| 223 | } |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 224 | }); |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 225 | |
| 226 | mFinished = false; |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 227 | Intent intent = new Intent(Intent.ACTION_VIEW); |
| 228 | intent.setClass(activity, TestShellActivity.class); |
| 229 | intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); |
| 230 | intent.putExtra(TestShellActivity.TEST_URL, url); |
| 231 | intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout); |
| 232 | intent.putExtra(TestShellActivity.RESULT_FILE, LOAD_TEST_RESULT); |
Guang Zhu | 5dc4f21 | 2009-10-29 18:24:54 -0700 | [diff] [blame] | 233 | intent.putExtra(TestShellActivity.GET_DRAW_TIME, getDrawTime); |
| 234 | if (saveImagePath != null) |
| 235 | intent.putExtra(TestShellActivity.SAVE_IMAGE, saveImagePath); |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 236 | activity.startActivity(intent); |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 237 | |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 238 | // Wait until done. |
| 239 | synchronized (this) { |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 240 | while(!mFinished) { |
| 241 | try { |
| 242 | this.wait(); |
| 243 | } catch (InterruptedException e) { } |
| 244 | } |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 245 | } |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | public void copyRunnerAssetsToCache() { |
| 249 | try { |
Guang Zhu | 0006952 | 2010-12-06 11:17:38 -0800 | [diff] [blame] | 250 | Context targetContext = getInstrumentation().getTargetContext(); |
| 251 | File cacheDir = targetContext.getCacheDir(); |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 252 | |
| 253 | for( int i=0; i< LOAD_TEST_RUNNER_FILES.length; i++) { |
Guang Zhu | 0006952 | 2010-12-06 11:17:38 -0800 | [diff] [blame] | 254 | InputStream in = targetContext.getAssets().open( |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 255 | LOAD_TEST_RUNNER_FILES[i]); |
| 256 | OutputStream out = new FileOutputStream( |
Guang Zhu | 0006952 | 2010-12-06 11:17:38 -0800 | [diff] [blame] | 257 | new File(cacheDir, LOAD_TEST_RUNNER_FILES[i])); |
Guang Zhu | b933f669 | 2009-05-05 01:02:14 -0700 | [diff] [blame] | 258 | |
| 259 | byte[] buf = new byte[2048]; |
| 260 | int len; |
| 261 | |
| 262 | while ((len = in.read(buf)) >= 0 ) { |
| 263 | out.write(buf, 0, len); |
| 264 | } |
| 265 | out.close(); |
| 266 | in.close(); |
| 267 | } |
| 268 | }catch (IOException e) { |
| 269 | e.printStackTrace(); |
| 270 | } |
| 271 | |
| 272 | } |
| 273 | |
The Android Open Source Project | ba87e3e | 2009-03-13 13:04:22 -0700 | [diff] [blame] | 274 | } |