2011-09-13 18 views
8

consideran este bloque de código:¿Por qué utilizar funciones definidas en el mismo módulo más rápido que la misma función definida en otro?

isPrime primes' n = foldr (\p r -> p * p > n || (n `rem` p /= 0 && r)) True primes' 

primes = 2 : filter (isPrime primes) [3..] 

main = putStrLn $ show $ sum $ takeWhile (< 1000000) primes 

que calcula la suma de todos los números primos inferiores a un millón. Se necesitan 0,468 segundos para imprimir el resultado en mi máquina. Pero si las definiciones de isPrime y primes se extraen en otro módulo, el costo de tiempo es 1.23 segundos, es casi 3 veces más lento.

Por supuesto que puedo copiar/pegar las difusiones donde sea que se requiera, pero también tengo curiosidad sobre por qué esto está sucediendo y cómo resolverlo.


[Editar] estoy usando GHC 7.0.3 (Windows 7 + MinGW). El código está escrito en EclipseFP (usa Scion como back-end IDE) y está integrado en un archivo ejecutable con -O2 flags.

También probé la construcción del paquete fuera del IDE:

executable test 
    hs-source-dirs: src 
    main-is:   Main.hs 
    build-depends: base >= 4 
    ghc-options:  -O2 
    other-modules: Primes 

executable test2 
    hs-source-dirs: src2 
    main-is:   Main.hs 
    build-depends: base >= 4 
    ghc-options:  -O2 

Aquí está el resultado:

$ time test/test 
37550402023 

real 0m1.296s 
user 0m0.000s 
sys  0m0.031s 

$ time test2/test2 
37550402023 

real 0m0.520s 
user 0m0.015s 
sys  0m0.015s 

Respuesta

7

Puedo reproducir esto si pongo isPrime y primes en diferentes módulos. (Si están en el mismo módulo, pero todavía están separados de main, no veo ninguna diferencia).

La adición de {-# INLINE isPrime #-} ofrece el mismo rendimiento que tener los tres en un módulo, por lo que parece que GHC necesitaba un empujón para hacer la alineación de módulos cruzados en este caso.

Este es el GHC 7.0.2, Ubuntu 11.04, 64 bits

+0

¡funciona! ¡Gracias! – claude

+5

GHC realizará una alineación muy agresiva dentro de un módulo, especialmente si la función que se va a insertar no se exporta. Es mucho menos entusiasta para alinear funciones a través de los límites del módulo, a menos que INLINE de forma manual. –

1

¿Está ejecutando esto dentro GHCi o compilación a través de GHC? Acabo de probar un experimento, mantener todas las definiciones en el mismo archivo, mover las primeras dos y compilar a través de GHC con el indicador -O encendido y apagado. No hay una diferencia perceptible entre las diferentes combinaciones en mi máquina (todas funcionan solo unos pocos milisegundos durante 1 segundo, usando GHC 7).

+0

¿Utiliza '' -O' o -O2'? En mi humilde opinión, la segunda bandera activa muchas optimizaciones que pueden verse afectadas por el movimiento del código. – fuz

+0

Información de entorno de compilación agregada a la publicación original, ¡gracias! – claude

+0

@FUZxxl De hecho, intenté con ambos. No hay diferencia perceptible en ninguno de los casos. La ejecución más rápida general fue sin indicadores de optimización pasados ​​a GHC, pero estamos hablando de una extensión general de aproximadamente 100 ms en tiempo de ejecución entre todas las cobminaciones en mi máquina. –

Cuestiones relacionadas