16

¿Cómo puedo medir la velocidad del código escrito en Java?¿Cómo puedo medir la velocidad del código escrito en Java? (Algoritmos AI)

Estoy planeando desarrollar un software que resuelva el Sudoku utilizando todos los algoritmos de AI y ML actualmente disponibles y compare el tiempo contra el método de la fuerza bruta simple. Necesito medir el tiempo de cada algoritmo, me gustaría pedir sugerencias sobre cuál es la mejor manera de hacerlo. Muy importante, el programa debe ser útil en cualquier máquina independientemente de la potencia/memoria de la CPU.

Gracias.

+1

No relacionado con la pregunta principal, pero tal vez de interés dado que planea escribir software para resolver Sudoku. Eche un vistazo a la solución de Norvig. http://norvig.com/sudoku.html – hashable

+0

+1 gracias, sí. Conozco esta solución. Buenas cosas –

Respuesta

19

Como se sugiere por otros, System.currentTimeMillis() es bastante bueno, pero tenga en cuenta las siguientes salvedades:

  • System.currentTimeMillis() medidas transcurrido el tiempo físico ("tiempo de reloj de pared"), no el tiempo de CPU. Si se están ejecutando otras aplicaciones en la máquina, su código obtendrá menos CPU y su velocidad disminuirá. Por lo tanto, use bench solo en sistemas inactivos.
  • Del mismo modo, una aplicación de subprocesos múltiples en un sistema multinúcleo puede obtener CPU oculta adicional. La medida del tiempo transcurrido no captura la totalidad de la complejidad de las aplicaciones de subprocesos múltiples.
  • Java necesita un poco de "calentamiento". La VM primero interpretará el código (que es lento) y, si un método dado se usa muchas veces, el compilador JIT traducirá el método a código nativo. Solo en ese punto el método alcanzará su velocidad máxima. Recomiendo que realice algunos "bucles vacíos" antes de llamar al System.currentTimeMillis().
  • La precisión de System.currentTimeMillis() es raramente de 1 ms. En muchos sistemas, la precisión no es mejor que 10 ms o incluso más. Además, la JVM algunas veces ejecutará el GC e inducirá pausas notables. Sugiero que organices tu medida en un ciclo e insistas en correr durante al menos unos segundos.

Esto produce el siguiente código:

for (int i = 0; i < 10; i ++) { 
    runMethod(); 
} 
int count = 10; 
for (;;) { 
    long begin = System.currentTimeMillis(); 
    for (int i = 0; i < count; i ++) 
     runMethod(); 
    long end = System.currentTimeMillis(); 
    if ((end - begin) < 10000) { 
     count *= 2; 
     continue; 
    } 
    reportElapsedTime((double)(end - begin)/count); 
} 

Como se puede ver, hay diez primeras carreras "vacías". Luego el programa ejecuta el método en un bucle, tantas veces como sea necesario para que el bucle tome al menos diez segundos. Diez segundos deberían ser suficientes para suavizar las ejecuciones de GC y otras imprecisiones del sistema. Cuando realizo implementaciones de funciones hash de banco, uso dos segundos, y aunque la función en sí no desencadena ninguna asignación de memoria, sigo obteniendo variaciones de hasta un 3%.

+2

Execellent respuesta – whiskeysierra

+0

@Thomas Pornin - muy buen resumen detallado, gracias +1 –

12

lo general el uso

System.currentTimeMillis() 

para calcular los deltas de tiempo:

long start = System.currentTimeMillis(); 
/* do your algorithm iteration */ 
long elapsed = System.currentTimeMillis() - start; 

cuenta que dependiendo del sistema operativo que utiliza la precisión de la funcion podría ser mayor que 1 milisegundo (también décimo de msecs), por lo que tendrá que ajustarlo para que sea útil para su análisis.

EDITAR: también existe la alternativa de hacer lo mismo con System.nanoTime() pero no tiene ninguna garantía de que la precisión sea de nanosegundos.

+0

Gracias Jack, cosas buenas +1 –

5

Ésta es otra manera (con nanosegundos)

long nanos = System.nanoTime(); 
// execute your stuff 
long duration = System.nanoTime() - nanos; 
int seconds = (int) (duration/1000000000); 
int milliseconds = (int) (duration/1000000) % 1000; 
int nanoseconds = (int) (duration % 1000000); 
System.out.printf("%d seconds, %d milliseconds en %d nanoseconds\n", seconds, milliseconds, nanoseconds); 

Los nanos son de pago, pero agradable.

+2

En "la mayoría de las máquinas", los nanos no tienen sentido. –

4

Si está interesado en la precisión de sus mediciones, debe medir el tiempo de CPU, no el "tiempo de reloj de pared". De esta forma, no medirá el tiempo que el sistema operativo usa para hacer otra cosa. Para medir este tiempo quizás pueda mirar Java benchmarking CPU time

4

Aunque todas las respuestas aquí son válidas, propongo que medir el tiempo real puede no ser completamente relevante para su objetivo, que es comparar y contrastar los algoritmos de búsqueda que varían para encontrar el "mejor" En este caso, es mucho más simple contar la cantidad de nodos que busca. Si bien es bueno saber también el tiempo de ejecución, hay mucho ruido involucrado ya que cada algoritmo puede golpear la CPU/caché/memoria/disco de una manera particular. Al medir los nodos, está viendo la medida más importante de cuán bueno es el algoritmo de búsqueda, ya que mientras menos busca, más rápido encontrará la respuesta.

Cuestiones relacionadas