2015-05-27 16 views
22

Come posso eseguire benchmark JMH all'interno del mio progetto esistente usando i test JUnit? La documentazione ufficiale consiglia di creare un progetto separato, utilizzando il plug-in Maven per il colore e l'avvio di JMH nel metodo main. È necessario e perché è raccomandato?Come eseguire JMH da test JUnit interni?

risposta

44

Ho eseguito JMH all'interno del mio progetto Maven esistente utilizzando JUnit senza apparenti effetti negativi. Non posso rispondere perché gli autori raccomandano di fare le cose in modo diverso. Non ho osservato una differenza nei risultati. JMH lancia una JVM separata per eseguire benchmark per isolarli. Ecco quello che faccio:

  • Aggiungere le dipendenze JMH al POM:

    <dependency> 
        <groupId>org.openjdk.jmh</groupId> 
        <artifactId>jmh-core</artifactId> 
        <version>1.9.3</version> 
        <scope>test</scope> 
    </dependency> 
    <dependency> 
        <groupId>org.openjdk.jmh</groupId> 
        <artifactId>jmh-generator-annprocess</artifactId> 
        <version>1.9.3</version> 
        <scope>test</scope> 
    </dependency> 
    

    Si noti che le ho messo in ambito test.

    In Eclipse, potrebbe essere necessario configurare manualmente il processore di annotazione. NetBeans gestisce questo automaticamente.

  • Crea la tua classe JUnit e JMH. Ho scelto di combinare entrambi in una singola classe, ma dipende da te. Si noti che OptionsBuilder.include è ciò che determina effettivamente quali benchmark verranno eseguiti dal test JUnit!

    public class TestBenchmark { 
    
         @Test public void 
        launchBenchmark() throws Exception { 
    
          Options opt = new OptionsBuilder() 
            // Specify which benchmarks to run. 
            // You can be more specific if you'd like to run only one benchmark per test. 
            .include(this.getClass().getName() + ".*") 
            // Set the following options as needed 
            .mode (Mode.AverageTime) 
            .timeUnit(TimeUnit.MICROSECONDS) 
            .warmupTime(TimeValue.seconds(1)) 
            .warmupIterations(2) 
            .measurementTime(TimeValue.seconds(1)) 
            .measurementIterations(2) 
            .threads(2) 
            .forks(1) 
            .shouldFailOnError(true) 
            .shouldDoGC(true) 
            //.jvmArgs("-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining") 
            //.addProfiler(WinPerfAsmProfiler.class) 
            .build(); 
    
          new Runner(opt).run(); 
         } 
    
        // The JMH samples are the best documentation for how to use it 
        // http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/ 
        @State (Scope.Thread) 
        public static class BenchmarkState 
        { 
         List<Integer> list; 
    
          @Setup (Level.Trial) public void 
         initialize() { 
    
           Random rand = new Random(); 
    
           list = new ArrayList<>(); 
           for (int i : LoopUtils.range (1000)) 
            list.add (rand.nextInt()); 
          } 
        } 
    
         @Benchmark public void 
        benchmark1 (BenchmarkState state, Blackhole bh) { 
    
          List<Integer> list = state.list; 
    
          for (int i = 0; i < 1000; i++) 
           bh.consume (list.get (i)); 
         } 
    } 
    
  • processore annotazione di JMH sembra non funzionare bene con compilazione on-save in NetBeans. Potrebbe essere necessario eseguire un completo Clean and Build ogni volta che si modificano i benchmark. (Qualsiasi suggerimento apprezzato!)

  • Esegui il test launchBenchmark e guarda i risultati!

    ------------------------------------------------------- 
    T E S T S 
    ------------------------------------------------------- 
    Running net.almson.util.TestBenchmark 
    # JMH 1.9.3 (released 12 days ago) 
    # VM invoker: C:\Program Files\Java\jdk1.8.0_45\jre\bin\java.exe 
    # VM options: <none> 
    # Warmup: 2 iterations, 1 s each 
    # Measurement: 2 iterations, 1 s each 
    # Timeout: 10 min per iteration 
    # Threads: 2 threads, will synchronize iterations 
    # Benchmark mode: Average time, time/op 
    # Benchmark: net.almson.util.TestBenchmark.benchmark1 
    
    # Run progress: 0.00% complete, ETA 00:00:04 
    # Fork: 1 of 1 
    # Warmup Iteration 1: 2.984 us/op 
    # Warmup Iteration 2: 3.007 us/op 
    Iteration 1: 2.844 us/op 
    Iteration 2: 2.832 us/op 
    
    
    Result "benchmark1": 
        2.838 us/op 
    
    
    # Run complete. Total time: 00:00:05 
    
    Benchmark     Mode Cnt Score Error Units 
    TestBenchmark.benchmark1 avgt 2 2.838   us/op 
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.255 sec 
    
    Results : 
    
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 
    
  • Runner.run restituisce anche RunResult oggetti su cui è possibile fare affermazioni, ecc

+1

Questo non è un opzione consigliata per eseguire i test sotto JMH. Test unitari e altri IDE interferiscono con le misurazioni. Fallo direttamente dalla riga di comando. –

+0

@IvanVoroshilin L'ho provato in entrambi i modi e non ho visto differenze nei risultati. Hai un consiglio concreto in quali condizioni questo diventa un problema? –

+1

I risultati sono meno affidabili, è solo una raccomandazione. Elimina i fattori esterni. Ciò interferisce con il microbenchmarking. –

Problemi correlati