blob: dc286df6f0de071111548cf0ba6e46bb10c33571 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.weex.benchmark;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.MatcherAssert.assertThat;
import android.support.annotation.NonNull;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SdkSuppress;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.support.test.espresso.contrib.RecyclerViewActions;
import android.text.TextUtils;
import android.util.Log;
import org.apache.weex.BenchmarkActivity;
import com.taobao.weex.WXEnvironment;
import com.taobao.weex.common.WXPerformance;
import com.taobao.weex.ui.view.listview.WXRecyclerView;
import com.taobao.weex.utils.WXLogUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import org.hamcrest.Matchers;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class BenchmarkTest {
private static final String TAG = "benchmark";
private static final int TIMES = 50;
private static final int FLING_SPEED = 10000;
private static final int SCROLL_SPEED = 5000;
private static final int FRAMES = 120;
private static final long WAIT_TIMEOUT = 10000;
private static final float FPS = 30;
private static final float FIRST_SCREEN_RENDER_TIME = 5000F;
private static List<Long> firstScreenRenderTime = new LinkedList<>();
private static List<Long> firstScreenLayoutTime = new LinkedList<>();
private static List<Long> flingFrameSeconds = new LinkedList<>();
private static List<Long> scrollFrameSeconds = new LinkedList<>();
private static final String DUMP_START = "QueueBufferDuration,\n";
private static final String DUMP_END = "---PROFILEDATA---";
private static final String DUMP_COMMAND = "dumpsys gfxinfo org.apache.weex framestats reset";
@Rule
public ActivityTestRule<BenchmarkActivity> mActivityRule = new ActivityTestRule(BenchmarkActivity.class);
@Rule
public RepeatRule repeatRule = new RepeatRule();
private UiDevice mUiDevice;
@Before
public void init() {
WXEnvironment.isPerf = true;
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
}
@Test
public void testFirstScreenPerformance() {
List<Long> localTotalTime = new ArrayList<>(TIMES);
List<Long> localLayoutTime = new ArrayList<>(TIMES);
for (int i = 0; i < TIMES; i++) {
WXPerformance performance = fetchPerformance();
long currentTime = performance.screenRenderTime;
long layoutTime = performance.cssLayoutTime;
localTotalTime.add(currentTime);
localLayoutTime.add(layoutTime);
Log.d(TAG, "FIRST_SCREEN_RENDER_TIME (activity not kill) " + currentTime + "ms");
Log.d(TAG, "FIRST_SCREEN_LAYOUT_TIME (activity not kill) " + layoutTime + "ms");
}
BoxPlot render = new BoxPlot(localTotalTime);
BoxPlot layout = new BoxPlot(localLayoutTime);
Log.i(TAG, "Average firstScreenRenderTime (activity not kill) " + render.draw());
Log.i(TAG, "Average firstScreenLayoutTime (activity not kill) " + layout.draw());
assertThat(render.getAverage(), Matchers.lessThan(FIRST_SCREEN_RENDER_TIME));
}
@Repeat(TIMES)
@Test
public void testFirstFirstScreenPerformance() {
WXPerformance performance = fetchPerformance();
long currentTime = performance.screenRenderTime;
long layoutTime = performance.cssLayoutTime;
firstScreenRenderTime.add(currentTime);
firstScreenLayoutTime.add(layoutTime);
Log.d(TAG, "FIRST_SCREEN_RENDER_TIME (activity killed) " + currentTime + " ms");
Log.d(TAG, "FIRST_SCREEN_Layout_TIME (activity killed) " + layoutTime + " ms");
}
@Repeat(TIMES)
//@Test
@SdkSuppress(minSdkVersion = 23)
public void testFlingFPS() {
UiObject2 uiObject2 = loadPageForFPS();
if (uiObject2 != null) {
uiObject2.fling(Direction.DOWN, FLING_SPEED);
uiObject2.fling(Direction.DOWN, FLING_SPEED);
uiObject2.fling(Direction.DOWN, FLING_SPEED);
uiObject2.fling(Direction.DOWN, FLING_SPEED);
processGfxInfo(flingFrameSeconds);
}
}
@Repeat(TIMES)
//@Test
@SdkSuppress(minSdkVersion = 23)
public void testScrollFPS() {
UiObject2 uiObject2 = loadPageForFPS();
if (uiObject2 != null) {
uiObject2.scroll(Direction.DOWN, 6, SCROLL_SPEED);
processGfxInfo(scrollFrameSeconds);
}
}
@AfterClass
public static void count() {
BoxPlot boxPlot = new BoxPlot(firstScreenRenderTime);
Log.i(TAG, "Average firstScreenRenderTime (activity killed) " + boxPlot.draw());
assertThat(boxPlot.getAverage(), Matchers.lessThan(FIRST_SCREEN_RENDER_TIME));
BoxPlot layout = new BoxPlot(firstScreenLayoutTime);
Log.i(TAG, "Average firstScreenLayoutTime (activity killed) " + layout.draw());
if (!flingFrameSeconds.isEmpty()) {
BoxPlot flingPlot = new BoxPlot(flingFrameSeconds);
Log.i(TAG, "Average Fling FPS : " + flingPlot.draw());
assertThat(1000 / flingPlot.getMedian(), Matchers.greaterThan(FPS));
}
if (!scrollFrameSeconds.isEmpty()) {
BoxPlot scrollPlot = new BoxPlot(scrollFrameSeconds);
Log.i(TAG, "Average Scroll FPS : " + scrollPlot.draw());
assertThat(1000 / scrollPlot.getMedian(), Matchers.greaterThan(FPS));
}
}
private UiObject2 loadPageForFPS() {
BenchmarkActivity benchmarkActivity = loadWeexPage();
return mUiDevice.wait(Until.findObject(By.desc(BenchmarkActivity.ROOT)), WAIT_TIMEOUT);
}
private void processGfxInfo(List<Long> container) {
try {
String line;
String[] columns;
long timeStart, timeEnd, duration;
String result = mUiDevice.executeShellCommand(DUMP_COMMAND);
result = result.substring(result.indexOf(DUMP_START), result.lastIndexOf(DUMP_END));
result = result.substring(DUMP_START.length());
BufferedReader bufferedReader = new BufferedReader(new StringReader(result));
List<Long> list = createList(bufferedReader);
container.addAll(list);
BoxPlot boxPlot = new BoxPlot(list);
boxPlot.draw();
Log.d(TAG, "FPS : " + boxPlot.getMedian() + " ms");
} catch (IOException e) {
WXLogUtils.e(TAG, WXLogUtils.getStackTrace(e));
}
}
private List<Long> createList(BufferedReader bufferedReader) throws IOException {
String line;
String[] columns;
long timeStart, timeEnd, duration;
List<Long> list = new ArrayList<>(FRAMES);
while (!TextUtils.isEmpty(line = bufferedReader.readLine())) {
columns = line.split(",");
if (Long.parseLong(columns[0]) == 0) {
timeStart = Long.parseLong(columns[1]);
timeEnd = Long.parseLong(columns[columns.length - 1]);
duration = timeEnd - timeStart;
if (duration > 0) {
list.add(TimeUnit.MILLISECONDS.convert(duration, TimeUnit.NANOSECONDS));
}
}
}
return list;
}
private long calcTime() {
BenchmarkActivity benchmarkActivity = mActivityRule.getActivity();
benchmarkActivity.loadWeexPage("http://30.8.53.163:8080/complicated.js");
onView(withClassName(Matchers.is(WXRecyclerView.class.getName()))).perform
(RecyclerViewActions.scrollToPosition(0));
return benchmarkActivity.getWXInstance().getWXPerformance().screenRenderTime;
}
private WXPerformance fetchPerformance() {
return loadWeexPage().getWXInstance().getWXPerformance();
}
@NonNull
private BenchmarkActivity loadWeexPage() {
final BenchmarkActivity benchmarkActivity = mActivityRule.getActivity();
benchmarkActivity.loadWeexPage();
await().atMost(WAIT_TIMEOUT, TimeUnit.MILLISECONDS).until(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return benchmarkActivity.isRenderFinish();
}
});
return benchmarkActivity;
}
}