2011-12-04 19 views
6

¿Cómo se forza la evaluación de la entrada de una función antes de la evaluación comparativa de la función en Criterion? Estoy tratando de comparar algunas funciones, pero me gustaría excluir el tiempo para evaluar el input thunk. El código en cuestión utiliza unboxed vectors para la entrada, que no puede ser deepseq'd para los vectores Int. código Ejemplo fragmento a continuación:Forzar la evaluación de la entrada de función antes de la evaluación comparativa en el Criterio

-- V is Data.Vector.Unboxed 
shortv = V.fromList [1..10] :: V.Vector GHC.Int.Int16 
intv = V.fromList [1..10] :: V.Vector GHC.Int.Int32 

main :: IO() 
main = defaultMain [ 
      bench "encode ShortV" $ whnf encodeInt16V shortv 
      ,bench "encode IntV" $ whnf encodeInt32V intv 
     ] 

Criterio de referencia incluye el tiempo para construir shortv, y Intv entradas cuando la evaluación comparativa anteriormente funciones. Las mediciones de criterio están por debajo de - que mide aproximadamente ~ 400ns para cada función que parece incluir tiempo de construcción de los insumos, así:

benchmarking encode ShortV 
mean: 379.6917 ns, lb 378.0229 ns, ub 382.4529 ns, ci 0.950 
std dev: 10.79084 ns, lb 7.360444 ns, ub 15.89614 ns, ci 0.950 

benchmarking encode IntV 
mean: 392.2736 ns, lb 391.2816 ns, ub 393.4853 ns, ci 0.950 
std dev: 5.565134 ns, lb 4.694539 ns, ub 6.689224 ns, ci 0.950 

Ahora, si la sección principal de código de prueba se modifica para abajo (quitando segunda función de banco) :

main = defaultMain [ 
      bench "encode ShortV" $ whnf encodeInt16V shortv 
     ] 

shortv de entrada parece ser evaluados antes toma como referencia la función encodeInt16V. Ese es el resultado deseado para mí, porque este punto de referencia mide el tiempo para la ejecución de la función, excluyendo el tiempo para construir la entrada. Criterio de salida a continuación:

benchmarking encode ShortV 
mean: 148.8488 ns, lb 148.4714 ns, ub 149.6279 ns, ci 0.950 
std dev: 2.658834 ns, lb 1.621119 ns, ub 5.184792 ns, ci 0.950 

Del mismo modo, si de referencia único punto de referencia "codificar Intv", me sale ~ 150ns tiempo para que uno también.

Sé por la documentación de Criterion que trata de evitar la evaluación perezosa para una evaluación comparativa más precisa. Tiene sentido, y no es realmente un problema aquí. Mi pregunta es cómo construir las entradas shortv e intv para que ya estén evaluadas antes de pasar a la función de banco. En este momento, puedo lograr esto restringiendo DefaultMain para comparar solo una función a la vez (como acabo de mostrar más arriba), pero esa no es una solución ideal.

EDIT1

hay algo más en juego aquí con Criterio de referencia, y parece ocurrir sólo en la matriz de vectores, no listas. Si fuerzo la evaluación completa imprimiendo shortv e intv, el benchmark aún mide el tiempo como ~ 400ns, no ~ 150ns. actualización del código de abajo:

main = do 
    V.forM_ shortv $ \x -> do print x 
    V.forM_ intv $ \x -> do print x 
    defaultMain [ 
      bench "encode ShortV" $ whnf encodeInt16V shortv 
      ,bench "encode IntV" $ whnf encodeInt32V intv 
     ] 

salida Criterio (también, tiene 158,4% los valores extremos que parece incorrecto):

estimating clock resolution... 
mean is 5.121819 us (160001 iterations) 
found 253488 outliers among 159999 samples (158.4%) 
    126544 (79.1%) low severe 
    126944 (79.3%) high severe 
estimating cost of a clock call... 
mean is 47.45021 ns (35 iterations) 
found 5 outliers among 35 samples (14.3%) 
    2 (5.7%) high mild 
    3 (8.6%) high severe 

benchmarking encode ShortV 
mean: 382.1599 ns, lb 381.3501 ns, ub 383.0841 ns, ci 0.950 
std dev: 4.409181 ns, lb 3.828800 ns, ub 5.216401 ns, ci 0.950 

benchmarking encode IntV 
mean: 394.0517 ns, lb 392.4718 ns, ub 396.7014 ns, ci 0.950 
std dev: 10.20773 ns, lb 7.101707 ns, ub 17.53715 ns, ci 0.950 

Respuesta

3

usted podría utilizar evaluate antes de llamar defaultMain para ejecutar los puntos de referencia. No estoy seguro de si es la solución más limpia, pero se vería así:

main = do 
    evaluate shortv 
    evaluate intv 
    defaultMain [..] 
+0

Probado con evaluar, como sugirió, pero no cambió el resultado. Supongo que esto se debe a que evalúa la expresión whnf, not nf. – Sal

+2

No creo que este sea el problema: un 'Vector' en, por ej. 'Int32' es un nuevo tipo alrededor de un' Data.Vector.Primitive.Vector Int32', que contiene solo campos estrictos de 'Int's y' ByteArray'. El último es un tipo de datos alrededor de una primitiva 'ByteArray #', que creo que es estricta. Pero las pruebas deben ser sencillas: simplemente cambie la llamada 'evaluate' a algo que imprime la suma en su lugar. –

+0

Sí, tienes razón. Intenté forM_ con print statement en el vector array, y obtuve el mismo resultado.Hay algo más en juego, y parece muy específico para Vector array. No vi este problema cuando inicialmente escribí funciones con listas. – Sal

Cuestiones relacionadas