Updated the Android benchmark with more accurate timing and better results output. Also fixed walking the tree to use a consistent order to make comparison between the device and emulator easier.

git-svn-id: https://zxing.googlecode.com/svn/trunk@644 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
dswitkin 2008-10-27 16:30:36 +00:00
parent a1deb27f46
commit 21e7813a60
3 changed files with 40 additions and 28 deletions

View file

@ -24,7 +24,6 @@ import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import com.google.zxing.BarcodeFormat;
import java.util.Vector; import java.util.Vector;
@ -82,11 +81,7 @@ public class BenchmarkActivity extends Activity {
for (int x = 0; x < items.size(); x++) { for (int x = 0; x < items.size(); x++) {
BenchmarkItem item = items.get(x); BenchmarkItem item = items.get(x);
if (item != null) { if (item != null) {
BarcodeFormat format = item.getFormat(); Log.v(TAG, item.toString());
Log.v(TAG, (item.getDecoded() ? "DECODED: " : "FAILED: ") + item.getPath());
Log.v(TAG, " Ran " + item.getCount() + " tests on " +
(format != null ? format.toString() : "unknown") + " format with an average of " +
item.getAverageMilliseconds() + " ms");
count++; count++;
} }
} }

View file

@ -28,14 +28,13 @@ public class BenchmarkItem {
public BenchmarkItem(String path, int runs) { public BenchmarkItem(String path, int runs) {
mPath = path; mPath = path;
assert(runs > 0);
mTimes = new int[runs]; mTimes = new int[runs];
mPosition = 0; mPosition = 0;
mDecoded = false; mDecoded = false;
mFormat = null; mFormat = null;
} }
// I'm storing these separately instead of as a running total so I can add features like
// calculating the min and max later, or ignoring outliers.
public void addResult(int milliseconds) { public void addResult(int milliseconds) {
mTimes[mPosition] = milliseconds; mTimes[mPosition] = milliseconds;
mPosition++; mPosition++;
@ -49,16 +48,40 @@ public class BenchmarkItem {
mFormat = format; mFormat = format;
} }
public String getPath() { @Override
return mPath; public String toString() {
StringBuffer result = new StringBuffer();
result.append(mDecoded ? ("DECODED " + mFormat.toString() + ": ") : "FAILED: ");
result.append(mPath);
result.append(" (");
result.append(getAverageTime());
result.append(" ms average)\n ");
int size = mTimes.length;
for (int x = 0; x < size; x++) {
result.append(mTimes[x]);
result.append(" ");
}
return result.toString();
} }
public int getAverageMilliseconds() { /**
* Calculates the average time but throws out the maximum as an outlier first.
*
* @return The average decoding time in milliseconds.
*/
private int getAverageTime() {
int size = mTimes.length; int size = mTimes.length;
int total = 0; int total = 0;
int max = mTimes[0];
for (int x = 0; x < size; x++) { for (int x = 0; x < size; x++) {
total += mTimes[x]; int time = mTimes[x];
total += time;
if (time > max) {
max = time;
}
} }
total -= max;
size--;
if (size > 0) { if (size > 0) {
return total / size; return total / size;
} else { } else {
@ -66,16 +89,4 @@ public class BenchmarkItem {
} }
} }
public int getCount() {
return mTimes.length;
}
public boolean getDecoded() {
return mDecoded;
}
public BarcodeFormat getFormat() {
return mFormat;
}
} }

View file

@ -16,6 +16,7 @@
package com.google.zxing.client.androidtest; package com.google.zxing.client.androidtest;
import android.os.Debug;
import android.os.Message; import android.os.Message;
import android.util.Log; import android.util.Log;
import com.google.zxing.MultiFormatReader; import com.google.zxing.MultiFormatReader;
@ -24,7 +25,7 @@ import com.google.zxing.Result;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.util.Date; import java.util.Arrays;
import java.util.Vector; import java.util.Vector;
final class BenchmarkThread extends Thread { final class BenchmarkThread extends Thread {
@ -45,6 +46,8 @@ final class BenchmarkThread extends Thread {
public void run() { public void run() {
mMultiFormatReader = new MultiFormatReader(); mMultiFormatReader = new MultiFormatReader();
mMultiFormatReader.setHints(null); mMultiFormatReader.setHints(null);
// Try to get in a known state before starting the benchmark
System.gc();
Vector<BenchmarkItem> items = new Vector<BenchmarkItem>(); Vector<BenchmarkItem> items = new Vector<BenchmarkItem>();
walkTree(mPath, items); walkTree(mPath, items);
@ -58,6 +61,7 @@ final class BenchmarkThread extends Thread {
File file = new File(path); File file = new File(path);
if (file.isDirectory()) { if (file.isDirectory()) {
String[] files = file.list(); String[] files = file.list();
Arrays.sort(files);
for (int x = 0; x < files.length; x++) { for (int x = 0; x < files.length; x++) {
walkTree(file.getAbsolutePath() + "/" + files[x], items); walkTree(file.getAbsolutePath() + "/" + files[x], items);
} }
@ -80,21 +84,23 @@ final class BenchmarkThread extends Thread {
BenchmarkItem item = new BenchmarkItem(path, RUNS); BenchmarkItem item = new BenchmarkItem(path, RUNS);
for (int x = 0; x < RUNS; x++) { for (int x = 0; x < RUNS; x++) {
Date startDate = new Date();
boolean success; boolean success;
Result result = null; Result result = null;
// Using this call instead of getting the time should eliminate a lot of variability due to
// scheduling and what else is happening in the system.
long now = Debug.threadCpuTimeNanos();
try { try {
result = mMultiFormatReader.decodeWithState(source); result = mMultiFormatReader.decodeWithState(source);
success = true; success = true;
} catch (ReaderException e) { } catch (ReaderException e) {
success = false; success = false;
} }
Date endDate = new Date(); now = Debug.threadCpuTimeNanos() - now;
if (x == 0) { if (x == 0) {
item.setDecoded(success); item.setDecoded(success);
item.setFormat(result != null ? result.getBarcodeFormat() : null); item.setFormat(result != null ? result.getBarcodeFormat() : null);
} }
item.addResult((int) (endDate.getTime() - startDate.getTime())); item.addResult((int) (now / 1000));
} }
return item; return item;
} }