Benchmarks: Unterschied zwischen den Versionen
(Die Seite wurde neu angelegt: „Ich poste mal ein absichtlich stark vereinfachtes und leicht zu bedienendes Benchmarkingsystem. Es basiert nur auf zwei Klassen, nämlich dem eigentlichen System …“) |
K |
||
(5 dazwischenliegende Versionen von 3 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
− | + | [[Kategorie:Tutorials (Java)]] | |
+ | [[Kategorie:Java-Codeschnipsel]] | ||
− | Das System erhebt keinesfalls den Anspruch perfekt implementiert oder jetzt der neue Meilenstein in Sachen benchmarking zu sein. Falls jemandem Fehler auffallen oder konstruktive Kritik besteht, bitte einfach kommentieren. | + | Ich poste mal ein absichtlich stark vereinfachtes und leicht zu bedienendes Benchmarkingsystem. Es basiert nur auf zwei [[Klasse|Klassen]], nämlich dem eigentlichen System namens QuickBench und einer [[Schnittstelle]] namens Bench, das den einzelnen Benchmark darstellt. Ich denke die Benutzung ist wirklich einfach. Benches, die auf einer Objektstruktur arbeiten und mit unterschiedlich vielen [[Objekt|Objekten]] gebencht werden sollen sind ebenso möglich, wie Benches, die nur eine bestimmte Funktion messen sollen, z.B. fib oder fac() und Co. |
+ | |||
+ | Das System erhebt keinesfalls den Anspruch perfekt implementiert oder jetzt der neue Meilenstein in Sachen benchmarking zu sein. Falls jemandem Fehler auffallen oder konstruktive Kritik besteht, bitte einfach im [https://forum.byte-welt.net/c/byte-welt-projekte-projects/wiki Forum] kommentieren. | ||
Das Interface Bench: | Das Interface Bench: | ||
− | + | <syntaxhighlight lang="java"> | |
/* | /* | ||
* Bench.java | * Bench.java | ||
Zeile 48: | Zeile 51: | ||
void execute(long lm); | void execute(long lm); | ||
} | } | ||
− | + | </syntaxhighlight> | |
− | </ | ||
Die abstrakte Klasse Bench: | Die abstrakte Klasse Bench: | ||
− | + | <syntaxhighlight lang="java"> | |
/* | /* | ||
* AbstractBench.java | * AbstractBench.java | ||
Zeile 86: | Zeile 88: | ||
} | } | ||
− | + | </syntaxhighlight> | |
− | </ | ||
Das Benchmarksystem QuickBench: | Das Benchmarksystem QuickBench: | ||
− | + | <syntaxhighlight lang="java"> | |
/* | /* | ||
* QuickBench.java | * QuickBench.java | ||
Zeile 307: | Zeile 308: | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
Ein kleines Beispiel zum Traversieren einer Liste (NxM): | Ein kleines Beispiel zum Traversieren einer Liste (NxM): | ||
− | + | <syntaxhighlight lang="java"> | |
Bench b0 = new Bench() { | Bench b0 = new Bench() { | ||
List<String> l = null; | List<String> l = null; | ||
Zeile 339: | Zeile 340: | ||
} | } | ||
}; | }; | ||
− | </ | + | </syntaxhighlight> |
Benutzung: | Benutzung: | ||
− | + | <syntaxhighlight lang="java"> | |
... | ... | ||
QuickBench.benchNxM(10, 50000, new long[] { 10, 100, 1000 }, new long[] { 10000, 100000 }, | QuickBench.benchNxM(10, 50000, new long[] { 10, 100, 1000 }, new long[] { 10000, 100000 }, | ||
new Bench[] { b0 }); | new Bench[] { b0 }); | ||
... | ... | ||
− | + | </syntaxhighlight> | |
− | </ | ||
Als Ergebnis erhält man folgendes: | Als Ergebnis erhält man folgendes: | ||
Zeile 389: | Zeile 389: | ||
Zwei Beispiele zu NxIntervall (Fibonacci rekursiv und nicht-rekursiv): | Zwei Beispiele zu NxIntervall (Fibonacci rekursiv und nicht-rekursiv): | ||
− | + | <syntaxhighlight lang="java"> | |
/* fibonacci -> recursive */ | /* fibonacci -> recursive */ | ||
static class FibBench_Recursive extends AbstractBench { | static class FibBench_Recursive extends AbstractBench { | ||
Zeile 449: | Zeile 449: | ||
} | } | ||
}; | }; | ||
− | </ | + | </syntaxhighlight> |
Aufruf wie folgt: | Aufruf wie folgt: | ||
− | + | <syntaxhighlight lang="java"> | |
public static void main(String[] args) { | public static void main(String[] args) { | ||
QuickBench.benchNxIntervall(10, 50000, new long[] { 10, 100, 1000}, 1, 25, | QuickBench.benchNxIntervall(10, 50000, new long[] { 10, 100, 1000}, 1, 25, | ||
new Bench[]{new FibBench_Recursive(), new FibBench_NonRecursive()}); | new Bench[]{new FibBench_Recursive(), new FibBench_NonRecursive()}); | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
Als Ergebnis erhält man ungefähr folgende Ausgabe: | Als Ergebnis erhält man ungefähr folgende Ausgabe: | ||
Zeile 479: | Zeile 479: | ||
Max memory: 63MB | Max memory: 63MB | ||
</nowiki> | </nowiki> | ||
+ | |||
+ | {{Fragen stellen}} |
Aktuelle Version vom 28. März 2018, 08:10 Uhr
Ich poste mal ein absichtlich stark vereinfachtes und leicht zu bedienendes Benchmarkingsystem. Es basiert nur auf zwei Klassen, nämlich dem eigentlichen System namens QuickBench und einer Schnittstelle namens Bench, das den einzelnen Benchmark darstellt. Ich denke die Benutzung ist wirklich einfach. Benches, die auf einer Objektstruktur arbeiten und mit unterschiedlich vielen Objekten gebencht werden sollen sind ebenso möglich, wie Benches, die nur eine bestimmte Funktion messen sollen, z.B. fib oder fac() und Co.
Das System erhebt keinesfalls den Anspruch perfekt implementiert oder jetzt der neue Meilenstein in Sachen benchmarking zu sein. Falls jemandem Fehler auffallen oder konstruktive Kritik besteht, bitte einfach im Forum kommentieren.
Das Interface Bench:
/*
* Bench.java
*
* 03.06.2010
*
* (c) fastjack
*/
package blog.benchmarking;
/**
* Diese Schnittstelle beschreibt einen Benchmark.
*
* @author fastjack
* @version 1.0
*/
public interface Bench {
/**
* @return der Name.
*/
String getName();
/**
* setzt den Benchmark und alle Resourcen, die er benutzt in den Urzustand zurück.
*/
void reset();
/**
* Bereitet den Benchmark zur Ausführung vor.
*
* @param lm Parameter anhand dessen der Benchmark vorbereitet wird.
*/
void prepare(long lm);
/**
* Führt den Benchmark aus.
*
* @param lm Parameter anhand dessen der Benchmark ausgeführt wird.
*/
void execute(long lm);
}
Die abstrakte Klasse Bench:
/*
* AbstractBench.java
*
* 06.01.2011
*
* (c) fastjack
*/
package blog.benchmarking;
/**
* Diese Klasse stellt einen abstrakten Benchmark dar.
*
* @author fastjack
* @version 1.0
*/
public abstract class AbstractBench implements Bench {
@Override
public String getName() {
return this.getClass().getSimpleName();
}
@Override
public void prepare(long lm) {
}
@Override
public void reset() {
}
}
Das Benchmarksystem QuickBench:
/*
* QuickBench.java
*
* 03.06.2010
*
* (c) fastjack
*/
package blog.benchmarking;
import java.util.*;
/**
* Diese kleine Klasse soll ein einfaches Benchmarksystem darstellen.
*
* @author fastjack
* @version 1.0
*/
public class QuickBench {
private final static String headerNxMSep = "+---------------------------+----------+-------"
+ "-----+----------+----------+-----------------+-----------------+";
private final static String headerNxM = "| %-25s | %8s | %10s | %8s | %8s | %15s | %15s "
+ "|\n";
private final static String headerNxIntervallSep = "+---------------------------+----------"
+ "+------------+------------+----------+----------+-----------------+-------------"
+ "----+";
private final static String headerNxIntervall = "| %-25s | %8s | %10s | %10s | %8s | %8s | "
+ "%15s | %15s |\n";
private final static String patternNxM = "| %-25s | %,8d | %,10d | %,8d | %,8d | %,15d | "
+ "%,15d |\n";
private final static String patternNxMWNT = "| %-25s | %,8d | %,10d | %,8d | %,8d | %15s | "
+ "%15s |\n";
private final static String patternNxIntervall = "| %-25s | %,8d | %,10d | %,10d | %,8d | "
+ "%,8d | %,15d | %,15d |\n";
private final static String patternNxIntervallWNT = "| %-25s | %,8d | %,10d | %,10d | %,8d "
+ "| %,8d | %15s | %15s |\n";
private QuickBench() {
}
/**
* Führt Benchmarks, die auf Funktionen etc. aufbauen und einen numerischen Parameter
* als Eingabe benötigen, aus. Diese Parameter werden in einem Intervall angegeben. Der
* Benchmark wird zurerst zurückgesetzt aber nicht vorbereitet. Bevor das Benchmarking
* gestartet wird, wird ein warmup zu allen Benchmarks aufgerufen und wie durch den
* Parameter wm angegeben, wiederholt. Die Anzahl an Durchläufen wird im Feld n
* angegeben. Alle Benchmarks werden zu jedem Eintrag e in n i-mal (i <= e) wiederholt,
* jeweils mit einem Wert aus dem dem angegebenen Intervall.
*
* @param minMs minimale Millesekunden, bei denen Nanosekunden angezeigt werden.
* @param wm WarmUp-Iterationen.
* @param n Anzahl an Iterationen.
* @param mmin Minimum des Intervalls.
* @param mmax Maximum des Intervalls.
* @param ba Benchmarks.
*/
public static void benchNxIntervall(long minMs, long wm, long[] n, long mmin, long mmax,
Bench[] ba) {
QuickBench qb = new QuickBench();
qb.warmup(ba, wm);
System.out.println(headerNxIntervallSep);
System.out.printf(headerNxIntervall, "Bench", "Rounds", "min", "max", "ms",
"ms (avg)", "nt", "nt (avg)");
System.out.println(headerNxIntervallSep);
for (int i = 0; i < ba.length; i++) {
Bench b = ba[i];
qb.executeIntervall(b, n, minMs, mmin, mmax);
}
System.out.println(headerNxIntervallSep);
qb.showInfo();
}
/**
* Führt Benchmarks, die z.B. einer Anzahl von Objekten basieren, aus. Der Benchmark
* wird zurerst zurückgesetzt und jeweils zu einem Wert aus m vorbereitet. Bevor das
* Benchmarking gestartet wird, wird ein warmup zu allen Benchmarks aufgerufen und wie durch
* den Parameter wm angegeben, wiederholt. Die Anzahl an Durchläufen wird im Feld n
* angegeben. Die Anzahl der Objekte im Feld m. Alle Benchmarks werden zu jedem Eintrag m0
* in m i-mal (i <= m0) durchlaufen und zu jedem Eintrag n0 in n j-mal (j <= n0)
* zu dem Wert m0 ausgeführt.
*
* @param minMs minimale Millesekunden, bei denen Nanosekunden angezeigt werden.
* @param wm WarmUp-Iterationen.
* @param n Anzahl an Iterationen.
* @param m Anzahl an z.B. Objekten.
* @param ba Benchmarks.
*/
public static void benchNxM(long minMs, long wm, long[] n, long[] m, Bench[] ba) {
QuickBench qb = new QuickBench();
qb.warmup(ba, wm);
System.out.println(headerNxMSep);
System.out.printf(headerNxM, "Bench", "Rounds", "Objects", "ms", "ms (avg)",
"nt", "nt (avg)");
System.out.println(headerNxMSep);
for (int i = 0; i < ba.length; i++) {
Bench b = ba[i];
for (int ii = 0; ii < m.length; ii++) {
qb.execute(b, n, minMs, m[ii]);
}
}
System.out.println(headerNxMSep);
qb.showInfo();
}
/*
* Zeigt Informationen zum System an.
*/
private void showInfo() {
System.out.println("java version " + System.getProperty("java.version"));
System.out.println(System.getProperty("java.runtime.name") + "(build " +
System.getProperty("java.runtime.version") + ")");
System.out.println(System.getProperty("java.vm.name") + "(build "
+ System.getProperty("java.vm.version") + ", "
+ System.getProperty("java.vm.info") + ")");
System.out.println(System.getProperty("os.name") + "("
+ System.getProperty("os.version") + ") " + System.getProperty("os.arch"));
System.out.println("Max memory: " + Runtime.getRuntime().maxMemory() / (1024 * 1024)
+ "MB");
}
/*
* Führt ein warmup zu allen Benchmarks durch. Dabei werden die Benches jeweils mit den
* Werten 1 vorbereitet und ausgeführt.
*
* @param ba Benchmarks.
* @param n Anzahl an Durchläufen zum WarmUp.
*/
private void warmup(Bench[] ba, long n) {
for (int i = 0; i < n; i++) {
for (int ii = 0; ii < ba.length; ii++) {
Bench b = ba[ii];
b.reset();
b.prepare(1);
b.execute(1);
}
}
}
/*
* Führt Benchmarks, die auf Funktionen etc. aufbauen und einen numerischen Parameter
* als Eingabe benötigen, aus. Diese Parameter werden in einem Intervall angegeben. Der
* Benchmark wird zurerst zurückgesetzt aber nicht vorbereitet.
*
* @param b Benchmark.
* @param n Iterationen.
* @param minMs minimale Millesekunden, bei denen Nanosekunden angezeigt werden.
* @param mmin Minimum des Intervalls.
* @param mmax Maximum des Intervalls.
*/
private void executeIntervall(Bench b, long[] n, long minMs, long mmin, long mmax) {
for (int i = 0; i < n.length; i++) {
long ln = n[i];
long ms = 0;
long nt = 0;
long ms0 = 0;
long nt0 = 0;
for (int ii = 0; ii < ln; ii++) {
for (long l = mmin; l < mmax; l++) {
b.reset();
ms0 = -System.currentTimeMillis();
nt0 = -System.nanoTime();
b.execute(l);
nt0 += System.nanoTime();
ms0 += System.currentTimeMillis();
ms += ms0;
nt += nt0;
}
}
if (ms < minMs) {
System.out.printf(patternNxIntervall, b.getName(), ln, mmin, mmax, ms, ms / ln,
nt, (nt / ln));
} else {
System.out.printf(patternNxIntervallWNT, b.getName(), ln, mmin, mmax, ms,
ms / ln, "...", "...");
}
}
}
/*
* Führt Benchmarks zu einem gegebenen Wert aus. Der Benchmark wird zurerst
* zurückgesetzt und zu dem Wert val vorbereitet.
*
* @param b Benchmark.
* @param n Iterationen.
* @param minMs minimale Millesekunden, bei denen Nanosekunden angezeigt werden.
* @param val Wert.
*/
private void execute(Bench b, long[] n, long minMs, long val) {
for (int i = 0; i < n.length; i++) {
long ln = n[i];
long ms = 0;
long nt = 0;
long ms0 = 0;
long nt0 = 0;
for (int ii = 0; ii < ln; ii++) {
b.reset();
b.prepare(val);
ms0 = -System.currentTimeMillis();
nt0 = -System.nanoTime();
b.execute(val);
nt0 += System.nanoTime();
ms0 += System.currentTimeMillis();
ms += ms0;
nt += nt0;
}
if (ms < minMs) {
System.out.printf(patternNxM, b.getName(), ln, val, ms, ms / ln, nt, (nt / ln));
} else {
System.out.printf(patternNxMWNT, b.getName(), ln, val, ms, ms / ln, "...",
"...");
}
}
}
}
Ein kleines Beispiel zum Traversieren einer Liste (NxM):
Bench b0 = new Bench() {
List<String> l = null;
@Override
public String getName() {
return "Traverse";
}
@Override
public void reset() {
l = new ArrayList<String>();
}
@Override
public void prepare(long lm) {
for (int i = 0; i < lm; i++) {
l.add(String.valueOf(i));
}
}
@Override
public void execute(long lm) {
for (int i = 0, n = l.size(); i < n; i++) {
String s = l.get(i);
}
}
};
Benutzung:
...
QuickBench.benchNxM(10, 50000, new long[] { 10, 100, 1000 }, new long[] { 10000, 100000 },
new Bench[] { b0 });
...
Als Ergebnis erhält man folgendes:
+---------------------------+----------+------------+----------+----------+-----------------+-----------------+ | Bench | Rounds | Objects | ms | ms (avg) | nt | nt (avg) | +---------------------------+----------+------------+----------+----------+-----------------+-----------------+ | Traverse ArrayList For | 10 | 10.000 | 0 | 0 | 1.945.638 | 194.563 | | Traverse ArrayList For | 100 | 10.000 | 16 | 0 | ... | ... | | Traverse ArrayList For | 1.000 | 10.000 | 171 | 0 | ... | ... | | Traverse ArrayList For | 10 | 100.000 | 16 | 1 | ... | ... | | Traverse ArrayList For | 100 | 100.000 | 109 | 1 | ... | ... | | Traverse ArrayList For | 1.000 | 100.000 | 1.170 | 1 | ... | ... | +---------------------------+----------+------------+----------+----------+-----------------+-----------------+ java version 1.6.0_16 Java(TM) SE Runtime Environment(build 1.6.0_16-b01) Java HotSpot(TM) Client VM(build 14.2-b01, mixed mode) Windows Vista(6.0) x86 Max memory: 63MB
Legende:
Bench: Name des Benchmarks. Rounds: Anzahl an Durchläufen. Objects: Anzahl an verwendeteten Objekten. ms: Gesamtzeitbedarf in Millisekunden. ms (avg): Durchschnittlicher Zeitbedarf in Millisekunden. nt: Gesamtzeitbedarf in Nanosekunden. Wenn ms > minMs wird hier nichts angezeigt. nt (avg): Durchschnittlicher Zeitbedarf in Nanosekunden. Wenn ms > minMs wird hier nichts angezeigt.
Weitere Beispiele folgen...
Und zwar jetzt:
Zwei Beispiele zu NxIntervall (Fibonacci rekursiv und nicht-rekursiv):
/* fibonacci -> recursive */
static class FibBench_Recursive extends AbstractBench {
private int fib(int a) {
if (a == 1 || a == 2) {
return 1;
} else {
return fib(a - 1) + fib(a - 2);
}
}
@Override
public String getName() {
return "Fibonacci: recursive";
}
@Override
public void prepare(long lm) {
this.fib(1);
this.fib(2);
this.fib(3);
}
@Override
public void execute(long lm) {
this.fib((int) lm);
}
};
/* fibonacci -> non-recursive */
static class FibBench_NonRecursive extends AbstractBench {
private long fib(int a) {
long fib = 1;
for (long fib1 = 1, fib2 = 1, i = 3; i <= a; i++) {
fib = fib1 + fib2;
fib1 = fib2;
fib2 = fib;
}
return fib;
}
@Override
public String getName() {
return "Fibonacci: non-recursive";
}
@Override
public void prepare(long lm) {
this.fib(1);
this.fib(2);
this.fib(3);
}
@Override
public void execute(long lm) {
this.fib((int) lm);
}
};
Aufruf wie folgt:
public static void main(String[] args) {
QuickBench.benchNxIntervall(10, 50000, new long[] { 10, 100, 1000}, 1, 25,
new Bench[]{new FibBench_Recursive(), new FibBench_NonRecursive()});
}
Als Ergebnis erhält man ungefähr folgende Ausgabe:
+---------------------------+----------+------------+------------+----------+----------+-----------------+-----------------+ | Bench | Rounds | min | max | ms | ms (avg) | nt | nt (avg) | +---------------------------+----------+------------+------------+----------+----------+-----------------+-----------------+ | Fibonacci: recursive | 10 | 1 | 25 | 0 | 0 | 8.312.579 | 831.257 | | Fibonacci: recursive | 100 | 1 | 25 | 93 | 0 | ... | ... | | Fibonacci: recursive | 1.000 | 1 | 25 | 812 | 0 | ... | ... | | Fibonacci: non-recursive | 10 | 1 | 25 | 0 | 0 | 25.911 | 2.591 | | Fibonacci: non-recursive | 100 | 1 | 25 | 0 | 0 | 241.581 | 2.415 | | Fibonacci: non-recursive | 1.000 | 1 | 25 | 0 | 0 | 1.974.832 | 1.974 | +---------------------------+----------+------------+------------+----------+----------+-----------------+-----------------+ java version 1.6.0_16 Java(TM) SE Runtime Environment(build 1.6.0_16-b01) Java HotSpot(TM) Client VM(build 14.2-b01, mixed mode) Windows Vista(6.0) x86 Max memory: 63MB
Fragen
Das Thema wurde nicht ausreichend behandelt? Du hast Fragen dazu und brauchst weitere Informationen? Lass Dir von uns helfen!
- Besuche uns im Byte-Welt-Forum
- Besuche unseren Chat
Wir helfen dir gerne!
Dir hat dieser Artikel gefallen? Oder Du hast Fehler entdeckt und möchtest zur Berichtigung beitragen? Prima! Schreibe einen Kommentar!
Du musst angemeldet sein, um einen Kommentar abzugeben.