Cómo medir la velocidad de ejecución del programa Java

85

¿Cómo se cronometra la ejecución de un programa java? No estoy seguro de qué clase debería usar para hacer esto.

Estoy buscando algo como:

// Some timer starts here
for (int i = 0; i < length; i++) {
  // Do something
}
// End timer here

System.out.println("Total execution time: " + totalExecutionTime);
George Mic
fuente

Respuestas:

139
final long startTime = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
  // Do something
}
final long endTime = System.currentTimeMillis();

System.out.println("Total execution time: " + (endTime - startTime));
bua
fuente
2
realmente debería ser nanoTime en realidad
Eugene
6
No debería ser nanoTime. Vea la respuesta de rhu.
fabspro
4
¿Hay alguna razón en particular por la que utilizó "final" aquí? ¿Qué sería diferente si eliminara esa palabra clave?
dijxtra
9
El uso de @dijxtra finaltiene la ventaja de que no se le puede asignar accidentalmente (así como otras ventajas, como el acceso a clases anónimo, etc.). En este código no haría ninguna diferencia. Es una práctica bastante común hacer todo finaly solo finalunificarlo si es necesario.
wchargin
1
El código que se va a probar, junto con las mediciones de tiempo, se deben ejecutar varias veces y se debe descartar el primer resultado. El primero probablemente incluirá tiempos de carga de clases, etc. Al ejecutarlo varias veces también, por supuesto, obtendrá un promedio que es más útil y confiable.
Arun Ramakrishnan
34

Tenga en cuenta que hay algunos problemas en los System#nanoTime()que no se puede usar de manera confiable en CPU de múltiples núcleos para registrar el tiempo transcurrido ... cada núcleo tiene su propio TSC ( Contador de marca de tiempo ): este contador se usa para obtener el tiempo nano (realmente es el número de ticks desde que arrancó la CPU).

Por lo tanto, a menos que el sistema operativo realice alguna deformación temporal de TSC para mantener los núcleos sincronizados, si un hilo se programa en un núcleo cuando se toma la lectura de tiempo inicial y luego se cambia a un núcleo diferente, el tiempo relativo puede parecer que salta esporádicamente hacia atrás. y adelante.

Observé esto hace algún tiempo en AMD / Solaris, donde los tiempos transcurridos entre dos puntos de tiempo a veces regresaban como valores negativos o números positivos inesperadamente grandes. Había un parche del kernel de Solaris y una configuración de BIOS necesaria para forzar AMD PowerNow! apagado, que pareció resolverlo.

Además, hay (AFAIK) un error no solucionado hasta ahora cuando se usa Java System#nanoTime()en un entorno VirtualBox; causando todo tipo de extraños problemas de subprocesos intermitentes para nosotros, ya que gran parte del java.util.concurrencypaquete depende del nano tiempo.

Ver también:

¿System.nanoTime () es completamente inútil? http://vbox.innotek.de/pipermail/vbox-trac/2010-January/135631.html

rhu
fuente
9

Obtiene la hora actual del sistema, en milisegundos:

final long startTime = System.currentTimeMillis();

Entonces haces lo que vas a hacer:

for (int i = 0; i < length; i++) {
  // Do something
}

Entonces ves cuánto tiempo tomó:

final long elapsedTimeMillis = System.currentTimeMillis() - startTime;
Jonathan Feinberg
fuente
La respuesta de BalusC también es correcta; depende de la resolución del temporizador necesaria y de por qué necesita la sincronización.
Jonathan Feinberg
9

Puede hacer uso de System#nanoTime(). Consígalo antes y después de la ejecución y simplemente haga los cálculos. Se prefiere arriba System#currentTimeMillis()porque tiene una mejor precisión. Dependiendo del hardware y la plataforma utilizada, es posible que obtenga un espacio incorrecto en el tiempo transcurrido. Aquí con Core2Duo en Windows, entre aproximadamente 0 y ~ 15 ms en realidad no se puede calcular nada.

Una herramienta más avanzada es un perfilador .

BalusC
fuente
El temporizador en Windows no tiene una resolución particularmente buena por defecto. También hay un temporizador de alto rendimiento, pero es mucho más difícil de usar incluso desde C y Java no (AFAIK) proporciona acceso a un nivel tan bajo de piratería sin un procesador JNI.
Donal Fellows
1
nanoTime()tiene un problema (al menos en Windows); la marca de tiempo es específica del núcleo del procesador. Tenía un programa que tenía un tiempo de ejecución negativo porque tenía la marca de tiempo de "inicio" en un núcleo y la marca de tiempo de "parada" en otro núcleo.
gustafc
3

Para cosas simples, System.currentTimeMillis () puede funcionar.

De hecho, es tan común que mi IDE esté configurado de modo que al ingresar "t0" me genere la siguiente línea:

final long t0 = System.currentTimeMillis()

Pero para cosas más complicadas, probablemente querrá usar medidas de tiempo estadísticas, como aquí (desplácese un poco hacia abajo y observe las medidas de tiempo expresadas, incluidas las desviaciones estándar, etc.):

http://perf4j.codehaus.org/devguide.html

Sintaxis T3rr0r
fuente
+1 para señalar el código del autogenerador. Utilizo una declaración similar todo el tiempo y no sabía cómo insertar plantillas de código. Acabo de descubrir cómo hacer eso con eclipse, ¡y definitivamente te ayudará!
Jason
Todos los servicios de Codehaus han finalizado. Tu enlace ahora está roto.
naXa
2

Usando AOP / AspectJ y la @Loggableanotación de jcabi-aspectos puede hacerlo de manera fácil y compacta:

@Loggable(Loggable.DEBUG)
public String getSomeResult() {
  // return some value
}

Cada llamada a este método se enviará a la instalación de registro SLF4J con DEBUGnivel de registro. Y cada mensaje de registro incluirá el tiempo de ejecución.

yegor256
fuente
2

Aquí hay algunas formas de encontrar el tiempo de ejecución en Java:

1) System.nanoTime ()

long startTime = System.nanoTime();
.....your code....
long endTime   = System.nanoTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in nanoseconds  : " + totalTime);
System.out.println("Execution time in milliseconds : " + totalTime / 1000000);

2) System.currentTimeMillis ()

long startTime = System.currentTimeMillis();
.....your code....
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds  : " + totalTime);

3) Instant.now ()

long startTime = Instant.now().toEpochMilli();
.....your code....
long endTime = Instant.now().toEpochMilli();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);

o

Instant start = Instant.now();
.....your code....
Instant end = Instant.now();
Duration interval = Duration.between(start, end);
System.out.println("Execution time in seconds: " +interval.getSeconds());

4) Date.getTime ()

long startTime = new Date().getTime();
.....your code....
long endTime = new Date().getTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);
SumiSujith
fuente
1

usar mucho startTime=System.currentTimeMillis() para la hora de inicio, en la parte superior del ciclo

poner long endTime= System.currentTimeMillis(); fuera del final del bucle. Tendrá que restar los valores para obtener el tiempo de ejecución en milisegundos.

Si quiere tiempo en nanosegundos, consulte System.nanoTime()

Jason
fuente
1

Creé una función de orden superior que toma el código que desea medir en / como una lambda:

class Utils {

    public static <T> T timeIt(String msg, Supplier<T> s) {
        long startTime = System.nanoTime();
        T t = s.get();
        long endTime = System.nanoTime();
        System.out.println(msg + ": " + (endTime - startTime) + " ns");
        return t;
    }

    public static void timeIt(String msg, Runnable r) {
       timeIt(msg, () -> {r.run(); return null; });
    }
}

Llámalo así:

Utils.timeIt("code 0", () ->
        System.out.println("Hallo")
);

// in case you need the result of the lambda
int i = Utils.timeIt("code 1", () ->
        5 * 5
);

Salida:

código 0: 180528 ns
código 1: 12003 ns

Un agradecimiento especial a Andy Turner, quien me ayudó a reducir el despido. Vea aquí .

Willi Mentzel
fuente
0

También puede probar Perf4J. Es una forma ordenada de hacer lo que está buscando y ayuda en las estadísticas de rendimiento agregadas como media, mínima, máxima, desviación estándar y transacciones por segundo durante un período de tiempo establecido. Un extracto de http://perf4j.codehaus.org/devguide.html :

StopWatch stopWatch = new LoggingStopWatch();

try {
    // the code block being timed - this is just a dummy example
    long sleepTime = (long)(Math.random() * 1000L);
    Thread.sleep(sleepTime);
    if (sleepTime > 500L) {
        throw new Exception("Throwing exception");
    }

    stopWatch.stop("codeBlock2.success", "Sleep time was < 500 ms");
} catch (Exception e) {
    stopWatch.stop("codeBlock2.failure", "Exception was: " + e);
}

Salida:

INFO: start[1230493236109] time[447] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493236719] time[567] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493237286] time[986] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493238273] time[194] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238467] time[463] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238930] time[310] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239241] time[610] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493239852] time[84] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239937] time[30] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239968] time[852] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
dotrc
fuente
0
public class someClass
{
   public static void main(String[] args) // your app start point
   {
       long start = java.util.Calendar.getInstance().getTimeInMillis();

       ... your stuff ...

       long end = java.util.Calendar.getInstance().getTimeInMillis();
       System.out.println("it took this long to complete this stuff: " + (end - start) + "ms");
   }
}
luis.espinal
fuente
0

Usar System.currentTimeMillis () es la forma correcta de hacer esto. Pero, si usa la línea de comando y desea cronometrar todo el programa de manera aproximada y rápida, piense en:

time java App

lo que le permite no modificar el código y el tiempo de su aplicación.

MarAja
fuente
Esto depende de cómo ejecute el código. Si es un fragmento de código que ejecuta un servidor, entonces incluirá la hora de inicio que es incorrecta.
Arun Ramakrishnan