Summary: We would like to know some numbers on benchmarking `YogaLayout` against other layouts, particularly `LinearLayout`. This implements a `BenchmarkActivity` to fill that need. Reviewed By: emilsjolander Differential Revision: D4565531 fbshipit-source-id: fe1c558beb603c3116ac3d0dd6654b0376dd6b8a
194 lines
4.8 KiB
Java
194 lines
4.8 KiB
Java
// Copyright 2004-present Facebook. All Rights Reserved.
|
|
|
|
package com.facebook.samples.yoga;
|
|
|
|
import java.io.File;
|
|
import java.io.FileWriter;
|
|
import java.io.PrintWriter;
|
|
import java.lang.Math;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.text.DateFormat;
|
|
import java.util.Date;
|
|
|
|
import android.content.Context;
|
|
import android.util.Log;
|
|
import android.os.Environment;
|
|
|
|
import static java.util.Collections.sort;
|
|
|
|
public class BenchmarkAggregator {
|
|
|
|
private final int GRAPH_WIDTH = 30;
|
|
private final int GRAPH_HEIGHT = 6;
|
|
|
|
private List<Long> times;
|
|
private boolean tracing;
|
|
private long lastTraceStart;
|
|
|
|
private boolean statsFresh;
|
|
private long mean;
|
|
private long variance;
|
|
private long stddev;
|
|
private long min;
|
|
private long max;
|
|
private long p10;
|
|
private long p50;
|
|
private long p90;
|
|
|
|
private String name;
|
|
|
|
public BenchmarkAggregator(String name) {
|
|
times = new ArrayList<>();
|
|
tracing = false;
|
|
this.name = name;
|
|
}
|
|
|
|
public void startTrace() {
|
|
if (tracing) {
|
|
throw new RuntimeException("Cannot start trace while running previous one");
|
|
}
|
|
tracing = true;
|
|
lastTraceStart = System.nanoTime();
|
|
}
|
|
|
|
public void endTrace() {
|
|
if (!tracing) {
|
|
throw new RuntimeException("Cannot stop trace if none are running!");
|
|
}
|
|
times.add(System.nanoTime() - lastTraceStart);
|
|
tracing = false;
|
|
statsFresh = false;
|
|
}
|
|
|
|
private void computeStats() {
|
|
if (statsFresh) {
|
|
return;
|
|
}
|
|
|
|
sort(times);
|
|
|
|
min = Long.MAX_VALUE;
|
|
max = -1;
|
|
mean = 0;
|
|
for (long f: times) {
|
|
mean += f;
|
|
if (f < min) {
|
|
min = f;
|
|
}
|
|
if (f > max) {
|
|
max = f;
|
|
}
|
|
}
|
|
mean /= times.size();
|
|
|
|
variance = 0;
|
|
for (long f: times) {
|
|
variance += (f-mean)*(f-mean);
|
|
}
|
|
variance /= times.size();
|
|
stddev = (long) Math.sqrt((double) variance);
|
|
|
|
p10 = times.get(times.size()*10/100);
|
|
p50 = times.get(times.size()*50/100);
|
|
p90 = times.get(times.size()*90/100);
|
|
|
|
statsFresh = true;
|
|
}
|
|
|
|
public String toString() {
|
|
computeStats();
|
|
return String.format(
|
|
"%s:\n" +
|
|
"| %d samples\n" +
|
|
"| Mean %.3f\u00B1%.3fms\n" + // plusminus
|
|
"| Min %.3fms ; Max %.3fms\n" +
|
|
"| p10 %.3fms ; p50 %.3fms ; p90 %.3fms\n" +
|
|
"%s",
|
|
name,
|
|
times.size(),
|
|
mean/10e6,
|
|
stddev/10e6,
|
|
min/10e6,
|
|
max/10e6,
|
|
p10/10e6,
|
|
p50/10e6,
|
|
p90/10e6,
|
|
makeGraph());
|
|
}
|
|
|
|
private String makeGraph() {
|
|
char canvas[][] = new char[GRAPH_HEIGHT][GRAPH_WIDTH];
|
|
for (int i = 0; i < GRAPH_HEIGHT; i++)
|
|
for (int j = 0; j < GRAPH_WIDTH; j++)
|
|
canvas[i][j] = ' ';
|
|
|
|
long bucketSize = (p90 - p10) / GRAPH_WIDTH+1;
|
|
int bucketCount[] = new int[GRAPH_WIDTH];
|
|
for (long time : times) {
|
|
if (time<p90 && time>p10) {
|
|
bucketCount[(int) ((time - p10) / bucketSize)]++;
|
|
}
|
|
}
|
|
|
|
int maxBucket = 0;
|
|
for (int i = 0; i < GRAPH_WIDTH; i++)
|
|
if (bucketCount[i] > maxBucket) {
|
|
maxBucket = bucketCount[i];
|
|
}
|
|
|
|
for (int i = 0; i < GRAPH_HEIGHT; i++)
|
|
for (int j = 0; j < GRAPH_WIDTH; j++)
|
|
if (i < bucketCount[j] * GRAPH_HEIGHT / maxBucket) {
|
|
canvas[i][j] = 'Z';
|
|
}
|
|
|
|
String graph = new String();
|
|
for (int i = 0; i < GRAPH_HEIGHT; i++)
|
|
{
|
|
int percentage = 100 * (GRAPH_HEIGHT - i - 1) * maxBucket / (times.size() * GRAPH_HEIGHT);
|
|
graph += String.format("| %2d%% ", percentage);
|
|
for (int j = 0; j < GRAPH_WIDTH; j++)
|
|
graph += canvas[GRAPH_HEIGHT-1-i][j];
|
|
graph += '\n';
|
|
}
|
|
|
|
graph += "| p10";
|
|
for (int i = 0; i < GRAPH_WIDTH-6; i++)
|
|
graph += " ";
|
|
graph += "p90\n";
|
|
return graph;
|
|
}
|
|
|
|
/**
|
|
* Dumps the collected times to a file on the device. This allows us to grab the raw data
|
|
* and perform more in-depth analysis.
|
|
*/
|
|
public void dump(Context context) {
|
|
String state = Environment.getExternalStorageState();
|
|
if (!Environment.MEDIA_MOUNTED.equals(state)) {
|
|
Log.e("YogaLayoutBenchmark","No external file storage");
|
|
return;
|
|
}
|
|
|
|
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
|
|
String filename = format.format(new Date()) + "_" + name.replace(' ','_');
|
|
File file = new File(context.getExternalFilesDir(
|
|
Environment.DIRECTORY_DOCUMENTS), filename);
|
|
|
|
try {
|
|
PrintWriter printWriter = new PrintWriter(file);
|
|
for (long l : times) {
|
|
printWriter.println(l);
|
|
}
|
|
printWriter.close();
|
|
|
|
Log.i("YogaLayoutBenchmark","Benchmark data saved in "+file.getPath());
|
|
} catch (java.io.IOException e) {
|
|
Log.e("YogaLayoutBenchmark", "Could not save benchmark data", e);
|
|
}
|
|
}
|
|
}
|