2013-10-05 10 views
6

Io uso jmh (http://openjdk.java.net/projects/code-tools/jmh/) per confrontare un metodo. Inoltre ho il set di parametri che voglio usare come argomenti per eseguire questo metodo. È possibile generare un metodo per ogni particolare valore del parametro (con annotazione @GenerateMicroBenchmark)?Come generare metodi nei benchmark jmh?

Ora uso l'attuazione simile, ma non è così conveniente, a causa della devo scrivere un sacco di codice uniforme a mano:

interface State { 
    int action(); 
    void prepare(); 
} 

class Method { 
    ...; 
    toString() { return "State1_" + param; } 
} 

{ 
    Method[] states; 
    curState = -1; 
    count = 0; 
    int[] params = {1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000}; 
    for (int param: params) { 
     states[count++] = new Method(param); 
    } 
} 

@Setup(Level.Invocation) 
public void prepareState() { 
    if (curState != -1) { 
    states[curState].prepare(); 
    } 
} 

@GenerateMicroBenchmark 
public int param_1000() { 
    curState = 0; 
    return states[curState].action(); 
} 

@GenerateMicroBenchmark 
public int param_2000() { 
    curState = 1; 
    return states[curState].action(); 
} 

@GenerateMicroBenchmark 
public int param_3000() { 
    curState = 2; 
    return states[curState].action(); 
} 
... 
@GenerateMicroBenchmark 
public int param_12000() { 
    curState = 11; 
    return states[curState].action(); 
} 

risposta

3

I benchmark di solito non si prestano per il riutilizzo senza qualche grave rottura. La maggior parte dei tentativi che ho visto in cui le persone cercavano di semplificare i loro benchmark li ha rotti alla credenza. Ad esempio, l'uso di matrici qui potrebbe compensare i risultati per nano-benchmark (ad es. Se action() è piccolo). Level.Invocation è di solito una cattiva idea, come indicato in its Javadoc.

La linea di fondo è, solo perché è consentito un utilizzo da parte dell'API, non significa necessariamente che è necessario utilizzarlo. Ecco cosa si dovrebbe fare, invece:

@State(Scope.Thread) 
class MyBenchmark { 
    Method[] states; 

    @Setup 
    public void setup() { 
     int[] params = {1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000}; 
     int count = 0; 
     for (int param: params) { 
      states[count++] = new Method(param); 
     } 
    } 

    int doWork(int idx) { 
     states[idx].prepare(); 
     return states[idx].action(); 
    } 

    @GenerateMicroBenchmark 
    public int param_1000() { 
     doWork(0); 
    } 

    ... 

    @GenerateMicroBenchmark 
    public int param_12000() { 
     doWork(11); 
    } 
} 

... o anche:

@State(Scope.Thread) 
class MyBenchmark { 
    Method p1000, p2000, ..., p12000; 

    @Setup 
    public void setup() { 
     p1000 = new Method(p1000); 
     p2000 = new Method(p2000); 
     ... 
     p12000 = new Method(p12000); 
    } 

    @GenerateMicroBenchmark 
    public int param_1000() { 
     p1000.prepare(); 
     return p1000.action(); 
    } 

    ... 

    @GenerateMicroBenchmark 
    public int param_12000() { 
     p12000.prepare(); 
     return p12000.action(); 
    } 
} 

L'alternativa sarebbe accettando il parametro dall'esterno, e l'utilizzo di API Java per manipolare il parametro. A titolo di esempio:

@State(Scope.Thread) 
class MyBenchmark { 
    final int param = Integer.getInteger("param", 1000); 

    Method m; 

    @Setup 
    public void setup() { 
     m = new Method(param); 
    } 

    @GenerateMicroBenchmark 
    public int work() { 
     m.prepare(); 
     return m.action(); 
    } 

    public static void main(String[] args) throws RunnerException { 
     Options opts = new OptionsBuilder() 
       .include(".*") 
       .jvmArgs("-Dparam=2000") 
       .build(); 

     RunResult runResult = new Runner(opts).runSingle(); 
     Result result = runResult.getPrimaryResult(); 

     System.out.println(); 
     System.out.println("API replied benchmark score: " + result.getScore() + " " + result.getScoreUnit() + " over " + result.getStatistics().getN() + " iterations"); 
    } 
}