Funciones de temporización en R [cerrado]

36
  1. Me gustaría medir el tiempo que lleva repetir la ejecución de una función. ¿Son replicate()y usan for-loops equivalentes? Por ejemplo:

    system.time(replicate(1000, f()));
    system.time(for(i in 1:1000){f()});
    

    Cuál es el método preferido.

  2. En la salida de system.time(), ¿es sys+userel tiempo real de CPU para ejecutar el programa? ¿Es elapseduna buena medida del rendimiento del tiempo del programa?

Tim
fuente
3
Solo para el registro, ya que claramente estoy demasiado tarde para cambiar el curso de esta pregunta: este es el tipo de problema que creo que es más adecuado para StackOverflow.
Matt Parker el
2
@Matt Estoy de acuerdo en que las preguntas sobre cómo una vez un programa son adecuados para SO. También estoy de acuerdo en que una interpretación literal de esta pregunta (tomada por varias de las respuestas) la colocaría fuera de tema aquí en CV. Sin embargo, parece haber cierto interés estadístico en el diseño de un experimento de sincronización y en el análisis de los resultados de dicho experimento.
whuber

Respuestas:

19

Para una sincronización efectiva de los programas, especialmente cuando está interesado en comparar soluciones alternativas, ¡necesita un control! Una buena manera es poner el procedimiento que estás cronometrando en una función. Llame a la función dentro de un ciclo de tiempo. Escriba un procedimiento de código auxiliar, esencialmente eliminando todo el código de su función y simplemente regresando de él (pero deje todos los argumentos). Coloque el trozo en su ciclo de tiempo y vuelva a cronometrar. Esto mide todos los gastos generales asociados con el tiempo. Reste el tiempo de resguardo del tiempo del procedimiento para obtener la red: esta debería ser una medida precisa del tiempo real necesario.

Debido a que la mayoría de los sistemas hoy en día pueden interrumpirse de manera perentoria, es importante realizar varias ejecuciones de temporización para verificar la variabilidad. En lugar de hacer una larga carrera de segundos, m ejecuciones de aproximadamente N / m segundos cada una. Es útil hacer esto en un bucle doble todo de una vez. No solo es más fácil de manejar, sino que introduce un poco de correlación negativa en cada serie de tiempo, lo que en realidad mejora las estimaciones.nortemetronorte/ /metro

Al utilizar estos principios básicos de diseño experimental, esencialmente controla las diferencias debidas a la forma en que implementa el código (por ejemplo, la diferencia entre un bucle for y replicate ()). Eso hace que tu problema desaparezca.

whuber
fuente
25

Con respecto a sus dos puntos:

  1. Es estilístico. Me gusta replicate()ya que es funcional.
  2. Tiendo a centrarme elapsed, es decir, el tercer número.

Lo que hago a menudo es

N <- someNumber
mean(replicate( N, system.time( f(...) )[3], trimmed=0.05) )

para obtener una media recortada del 90% de N repeticiones de llamadas f().

(Editado, gracias a Hadley por atrapar un thinko).

Dirk Eddelbuettel
fuente
2
No quiere decir mean(replicate(N, system.time(f(...))[3]), trim = 0.05)?
hadley 01 de
2
Si la llamada f () es larga, entonces está bien. Sin embargo, si la llamada f () es corta, entonces cualquier sobrecarga de la llamada de temporización probablemente aumentará la medición de errores. Con una sola llamada para system.time () durante muchas repeticiones de f () se puede dividir el error de la llamada hasta que tenga un valor infinitesimal (y regrese más rápido).
John
@ John: Gracias pero no entiendo lo que dijiste. Todavía me pregunto cuál es mejor, repitiendo f () dentro o fuera de system.time ()?
Tim
Cada llamada al comando system.time () tiene un tiempo variable que se necesita para llamar que causa una cierta cantidad de error de medición. Esta es una pequeña cantidad. Pero, ¿y si f () es una llamada muy breve? Entonces, este error se puede combinar con el tiempo necesario para llamar a f (). Entonces, cuando llama a f () 1e5 veces dentro de una sola llamada system.time (), el error se divide en 1e5 fragmentos. Cuando llama a system.time () para cada f (), su impacto podría ser significativo si el tiempo para f () es pequeño. Por supuesto, si todo lo que necesita es un tiempo relativo, no importa mucho.
John
Ah, y la segunda parte es que sería más rápido llamar a system.call () una vez.
John
10

También puede cronometrar con pasos de tiempo devueltos por Sys.time; esto, por supuesto, mide el tiempo de pared, por lo que el tiempo de cálculo en tiempo real. Código de ejemplo:

Sys.time()->start;
replicate(N,doMeasuredComputation());
print(Sys.time()-start);

fuente
3

Con respecto a qué métrica de tiempo usar, no puedo agregar a los otros respondedores.

Con respecto a la función a usar, me gusta usar el punto de referencia? Del paquete rbenchmark .

Tal Galili
fuente
1

Ellos hacen cosas diferentes. Mide el tiempo que deseas hacer. replicate () devuelve un vector de resultados de cada ejecución de la función. El bucle for no. Por lo tanto, no son declaraciones equivalentes.

Además, cronometra varias maneras en que desea que se haga algo. Entonces puedes encontrar el método más eficiente.

John
fuente
mod-tip: publique la segunda parte como un comentario a la respuesta de Dirk.