2016-01-27 20 views
7

Se IIUC ogni fork crea una macchina virtuale separata per il motivo che ciascuna istanza della macchina virtuale potrebbe essere eseguita con leggere differenze nelle istruzioni JIT?Qual è lo scopo di JMH @Fork?

Sono anche curioso di ciò che l'attributo tempo fa nelle annotazioni di seguito:

@Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) 
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) 

TIA, Ole

+0

Penso che risponda alla tua domanda: http://stackoverflow.com/questions/25572778/why-does-jmh-run-different-forks – Tunaki

+0

Quindi IIUC, ogni fork viene eseguito in una VM separata. Lo facciamo perché potrebbe esserci una sottile differenza per ogni VM lanciata che farà sì che il runtime differisca, quindi possiamo tener conto di questo calcolo della varianza? – Ole

+0

Sì, potrebbero esserci differenze tra ogni esecuzione nel modo in cui il JIT si comporta in modo tale da consentire di tenerne conto. Durante l'esecuzione di benchmark, ho visto casi estremamente strani in cui una corsa avrebbe avuto una certa media e un'altra sessione per lo stesso test avrebbe avuto una molto diversa, "semplicemente" perché la JIT gestiva le cose in modo diverso. – Tunaki

risposta

7

La JVM ottimizzare un'applicazione con la creazione di un profilo del comportamento dell'applicazione. Il fork è stato creato per ripristinare questo profilo. In caso contrario, l'esecuzione:

benchmarkFoo(); 
benchmarkBar(); 

potrebbe comportare diverse misure di

benchmarkBar(); 
benchmarkFoo(); 

in quanto il profilo del primo benchmark influenza il secondo.

I tempi determinano la durata della spesa JMH per il riscaldamento o la gestione del benchmark. Se questi tempi sono troppo brevi, la tua VM potrebbe non essere sufficientemente riscaldata o il tuo risultato potrebbe avere una deviazione standard troppo alta.

12

JMH offre la funzionalità della forcella per alcuni motivi. Uno è la separazione del profilo di compilazione come discusso da Rafael sopra. Ma questo comportamento non è controllato dall'annotazione @Forks (a meno che non si scelga 0 fork, il che significa che nessun sottoprocesso è biforcuto per eseguire benchmark). È possibile scegliere di eseguire tutti i benchmark come parte del riscaldamento del benchmark (creando così un profilo misto per il JIT con cui lavorare) usando il controllo della modalità di riscaldamento (-wm).

la realtà è che molte cose possono cospirare per inclinare i risultati in un modo o nell'altro e l'esecuzione di eventuali periodi multipli di riferimento per stabilire run-to-run varianza è una pratica importante che sostiene JMH (e il quadro più arrotolato a mano don' t aiutare con). Motivi per Esegui per eseguire la varianza può includere (ma sono sicuro che c'è di più):

  • inizio CPU a un certo C-state e scalare la frequenza il volto di carico, poi si surriscaldano e scala verso il basso . È possibile controllare questo problema su determinati sistemi operativi.

  • L'allineamento della memoria del processo può comportare differenze nel comportamento del cercapersone.

  • Attività dell'applicazione in background.
  • L'allocazione della CPU da parte del sistema operativo varierà con conseguente serie diverse di CPU utilizzate per ciascuna corsa.
  • Contenuto della cache della pagina e scambio
  • La compilazione JIT viene attivata contemporaneamente e può portare a risultati diversi (questo tenderà ad accadere quando più bit di codice sono in fase di test). Si noti che in genere piccoli benchmark con thread singolo non presentano questo problema.
  • Il comportamento del GC può attivarsi con temporizzazioni leggermente diverse dalla corsa all'esecuzione che portano a risultati diversi.

L'esecuzione del benchmark con almeno alcune forcelle aiuterà a scuotere queste differenze e ti darà un'idea della corsa per eseguire la varianza che vedi nel tuo benchmark. Ti consiglio di iniziare con il valore predefinito di 10 e di ridurlo (o aumentarlo) a livello sperimentale a seconda del benchmark.