2012-03-05 24 views
9

Tengo un archivo de lisp que realiza un montón de muestreo, archivo de E/S y aritmética en un bucle. (Hago particle filtering en el ceceo común.) Estoy compilando mi archivo lisp usando el comando compile-file. También utilizo el (declaim (optimize (speed 3) (debug 0) (safety 0))) al principio de mi archivo Lisp porque quiero tener mis resultados lo más rápido posible.
Uso (time (load "/....../myfile.lisp") y (time (load "/......./myfile.dx64fsl") para medir la velocidad. El problema es que compilar no me aporta ninguna ventaja. No hay mejora ¿Hago algo mal? ¿Hay alguna manera de mejorar las cosas? La velocidad es el criterio más importante, así que puedo sacrificar mucho para obtener una respuesta rápida. No tengo idea sobre este tipo de problemas por lo que cualquier ayuda sería apreciada.
Además, cuando aumento el número de partículas (cada partícula es un vector de tamaño ~ 40) para dar como 10000, el código se vuelve muy lento, por lo que también puede haber problemas de memoria.
Muchas gracias de antemano.Common Lisp Tiempo de compilación y ejecución

editar: Este es el perfil de resultados con 1000 partículas y 50 iteraciones.

(LOAD "/.../myfile.dx64fsl") took 77,488,810 microseconds (77.488810 seconds) to run 
        with 8 available CPU cores. 
During that period, 44,925,468 microseconds (44.925470 seconds) were spent in user mode 
        32,005,440 microseconds (32.005440 seconds) were spent in system mode 
2,475,291 microseconds (2.475291 seconds) was spent in GC. 
1,701,028,429 bytes of memory allocated. 
1,974 minor page faults, 0 major page faults, 0 swaps. 
; Warning: Function CREATE-MY-DBN has been redefined, so times may be inaccurate. 
;   MONITOR it again to record calls to the new definition. 
; While executing: MONITOR::MONITOR-INFO-VALUES, in process repl-thread(10). 


                   Cons 
          %  %       Per  Total  Total 
Function     Time Cons Calls Sec/Call  Call  Time  Cons 
------------------------------------------------------------------------------------------ 
SAMPLE:     25.61 26.14 2550000 0.000005  174 13.526 443040000 
DISCRETE-PARENTS:   19.66 3.12 4896000 0.000002  11 10.384 52800000 
LINEAR-GAUSSIAN-MEAN:  8.86 3.12 1632000 0.000003  32  4.679 52800000 
DISCRETE-PARENT-VALUES:  7.47 12.33 3264000 0.000001  64  3.946 208896000 
LIST-DIFFERENCE:   6.41 25.69 6528000 0.000001  67  3.384 435392000 
CONTINUOUS-PARENTS:   6.33 0.00 1632000 0.000002  0  3.343   0 
PF-STEP:     5.17 0.23  48 0.056851 80080  2.729  3843840 
CONTINUOUS-PARENT-VALUES: 4.13 7.20 1632000 0.000001  75  2.184 122048000 
TABLE-LOOKUP:    3.85 8.39 2197000 0.000001  65  2.035 142128000 
PHI-INVERSE:    3.36 0.00 1479000 0.000001  0  1.777   0 
PHI-INTEGRAL:    3.32 1.38 2958000 0.000001  8  1.755 23344000 
PARENT-VALUES:    2.38 10.65 1122000 0.000001  161  1.259 180528016 
CONDITIONAL-PROBABILITY: 1.41 0.00 255000 0.000003  0  0.746   0 
------------------------------------------------------------------------------------------ 
TOTAL:      97.96 98.24 30145048      51.746 1664819856 
Estimated monitoring overhead: 21.11 seconds 
Estimated total monitoring overhead: 23.93 seconds 

con 10000 partículas y 50 iteraciones:

(LOAD "/.../myfile.dx64fsl") took 809,931,702 microseconds (809.931700 seconds) to run 
        with 8 available CPU cores. 
During that period, 476,627,937 microseconds (476.627930 seconds) were spent in user mode 
        328,716,555 microseconds (328.716550 seconds) were spent in system mode 
54,274,625 microseconds (54.274624 seconds) was spent in GC. 
16,973,590,588 bytes of memory allocated. 
10,447 minor page faults, 417 major page faults, 0 swaps. 
; Warning: Funtion CREATE-MY-DBN has been redefined, so times may be inaccurate. 
;   MONITOR it again to record calls to the new definition. 
; While executing: MONITOR::MONITOR-INFO-VALUES, in process repl-thread(10). 


                   Cons  
          %  %       Per  Total  Total 
Function     Time Cons Calls Sec/Call  Call  Time  Cons 
------------------------------------------------------------------------------------------- 
SAMPLE:     25.48 26.11 25500000 0.000006  174 144.211 4430400000 
DISCRETE-PARENTS:   18.41 3.11 48960000 0.000002  11 104.179 528000000 
LINEAR-GAUSSIAN-MEAN:  8.61 3.11 16320000 0.000003  32 48.751 528000000 
LIST-DIFFERENCE:   7.57 25.66 65280000 0.000001  67 42.823 4353920000 
DISCRETE-PARENT-VALUES:  7.50 12.31 32640000 0.000001  64 42.456 2088960000 
CONTINUOUS-PARENTS:   5.83 0.00 16320000 0.000002   0 32.980   0 
PF-STEP:     5.05 0.23  48 0.595564 800080 28.587 38403840 
TABLE-LOOKUP:    4.52 8.38 21970000 0.000001  65 25.608 1421280000 
CONTINUOUS-PARENT-VALUES: 4.25 7.19 16320000 0.000001  75 24.041 1220480000 
PHI-INTEGRAL:    3.15 1.38 29580000 0.000001   8 17.849 233440000 
PHI-INVERSE:    3.12 0.00 14790000 0.000001   0 17.641   0 
PARENT-VALUES:    2.87 10.64 11220000 0.000001  161 16.246 1805280000 
CONDITIONAL-PROBABILITY: 1.36 0.00 2550000 0.000003   0  7.682   0 
------------------------------------------------------------------------------------------- 
TOTAL:      97.71 98.12 301450048      553.053 16648163840 
Estimated monitoring overhead: 211.08 seconds 
Estimated total monitoring overhead: 239.13 seconds 
+0

Entonces, ¿su archivo contiene más que solo definiciones de funciones? es decir, realmente ejecuta una de las funciones ¿verdad? –

+0

De hecho, tengo muchas funciones definidas en algún directorio.Primero lo cargo. Luego, en mi archivo, en un bucle llamo a una de las funciones definidas para obtener los resultados, que son la media y la varianza de las variables de consulta que tengo. Utilizo las otras funciones para construir mi red bayesiana al principio y luego llamo a una sola función cada vez en un bucle para hacer una inferencia. – YBE

+0

¿Debería compilar esos otros archivos? –

Respuesta

4

Las cosas aritméticas típicas en Common Lisp pueden ser lentas. Mejorarlo es posible, pero necesita un poco de conocimiento.

Razones:

  • números de Common Lisp no son lo que la máquina ofrece (bignums, racional, complejo, ...)
  • cambio automático de fixnum a bignum y la espalda
  • operaciones matemáticas genéricos
  • etiquetado utiliza los bits del tamaño de palabra
  • Consing de números

Una cosa que puede ver en la salida de generación de perfiles es que genera 1,7 GB de basura. Esta es una sugerencia típica de que las operaciones de su número son contras. Deshacerse de eso a menudo no es tan fácil. Es solo una suposición de mi parte, que estas son operaciones numéricas.

Ken Anderson (por desgracia murió hace unos años) tiene un consejo en su sitio web para mejorar el software numérico: http://openmap.bbn.com/~kanderso/performance/

Una solución habitual es dar el código a algún desarrollador Lisp experimentados, sabe un poco de el compilador usó y/u optimizaciones.

1

varios puntos:

  1. intenta mover el archivo de E/S fuera del bucle si es posible; leer los datos en la memoria en lote antes de la iteración. La E/S de archivo tiene varias magnitudes más lentas que el acceso a la memoria.

  2. Pruebe SBCL si la velocidad de ejecución es importante para usted.

  3. El aumento de diez veces en su entrada da como resultado aproximadamente diez veces el aumento del tiempo de ejecución, que es lineal, por lo que su algoritmo parece estar bien; solo necesito trabajar en tu factor constante.

  4. Aproveche el flujo de trabajo de Lisp: edite la función, compile la función y ejecute la prueba en lugar de editar el archivo, compilar el archivo y probar. La diferencia se intensificará cuando sus proyectos crezcan (o cuando pruebe con SBCL, lo que llevará más tiempo analizar/optimizar sus programas para producir código más rápido).

+0

He reemplazado E/S de archivo con la asignación de las salidas a un vector. Sin embargo, no cambió nada sustancial. Si puede verificar los perfiles anteriores, verá que la mayoría del tiempo lo toman 'sample' y' pf-step'. Puedo intentar paralelizar la 'muestra'. Si tiene más consejos, me gustaría escucharlos. Muchas gracias por la respuesta. – YBE

4

En primer lugar, nunca se vez declaran (speed 3) junto con (safety 0) en el nivel superior, es decir, a nivel mundial. Este va a tarde o temprano volver y morder la cabeza. En estos niveles, la mayoría de los compiladores de ceceo realizan menos comprobaciones de seguridad que los compiladores C. Por instinto, algunos ceceos dejan de buscar señales de interrupción en el código (safety 0). A continuación, (safety 0) muy raramente dan ganancias notables. Declararía (speed 3)(safety 1)(debug 1) en funciones activas, posiblemente yendo a (debug 0) si esto trae una ganancia notable.

De lo contrario, sin mirar realmente el código real, es un poco difícil encontrar sugerencias. Mirando desde el tiempo() parece que la presión del GC es algo alta. Asegúrese de utilizar aritmética de código abierto en las funciones de acceso rápido y no inutilice flotadores o entradas innecesariamente. Use (disassemble 'my-expensive-function) para observar de cerca el código que generó el compilador. SBCL proporcionará muchos resultados útiles al compilar con alta prioridad en velocidad y puede valer la pena tratar de eliminar algunas de estas advertencias.

También es importante que utilice una estructura de datos rápida para representar partículas, utilizando matrices instantiatiable y macrología si es necesario.

1
Welcome to Clozure Common Lisp Version 1.7-r14925M (DarwinX8664)! 
? (inspect 'print) 
[0]  PRINT 
[1]  Type: SYMBOL 
[2]  Class: #<BUILT-IN-CLASS SYMBOL> 
     Function 
[3]  EXTERNAL in package: #<Package "COMMON-LISP"> 
[4]  Print name: "PRINT" 
[5]  Value: #<Unbound> 
[6]  Function: #<Compiled-function PRINT #x30000011C9DF> 
[7]  Arglist: (CCL::OBJECT &OPTIONAL STREAM) 
[8]  Plist: NIL 

Inspect> (defun test (x) (+ x 1)) 
TEST 
Inspect> (inspect 'test) 
[0]  TEST 
[1]  Type: SYMBOL 
[2]  Class: #<BUILT-IN-CLASS SYMBOL> 
     Function 
[3]  INTERNAL in package: #<Package "COMMON-LISP-USER"> 
[4]  Print name: "TEST" 
[5]  Value: #<Unbound> 
[6]  Function: #<Compiled-function TEST #x302000C5EFFF> 
[7]  Arglist: (X) 
[8]  Plist: NIL 
Inspect> 

Tenga en cuenta que las pruebas # 'print y #' se enumeran como 'compiled'. Esto significa que la única diferencia de rendimiento entre cargar un archivo .lisp y cargar un archivo compilado es el tiempo de compilación. Lo cual supongo que no es el cuello de botella en su escenario. Por lo general, no lo es, a menos que esté usando un conjunto de macros, y realizar una transformación de código es el objetivo principal de su programa.

Esta es una de las razones principales por las que nunca trato con archivos lisp compilados. Solo cargué todas las bibliotecas/paquetes compartidos que necesito en mi archivo principal, y luego cargo algunas funciones/archivos específicos de .lisp cuando estoy trabajando en un proyecto en particular. Y, al menos para SBCL y CCL para mí, todo aparece como 'compilado'.

+0

Ese es realmente el caso. Mi archivo .dx64fsl lleva a un poco más de tiempo que la versión .lisp. Esa diferencia entonces es el tiempo de compilación. ¿Tienes alguna idea sobre hacer mi código más rápido? Te agradecería si puedes compartir algunos consejos. – YBE

+0

¿Hay alguna función que se llame repetidamente, que tenga las mismas entradas, una y otra vez? Si es así, puede memorizar esas funciones. He usado el defun-memo de Norvig (memoria automática) antes. –

+0

'pf-step' se llama en el ciclo en cada iteración. Utiliza los resultados de la última iteración para actualizarse. Sin embargo, llama a varias otras funciones como 'sample',' linear-gaussian-mean' que son solo muestras aleatorias de una distribución. Van a ver los valores de los padres de un nodo específico y, dados esos valores, generan una muestra. – YBE

2

Si todos los códigos contenidos en "myfile.lisp" son las partes en las que realiza los cálculos, no, compilar ese archivo no mejorará notablemente su tiempo de ejecución. La diferencia entre los dos casos probablemente sea "compilamos algunos bucles", llamando funciones compiladas o interpretadas en ambos casos.

Para obtener mejoras de la compilación, también debe compilar el código que se llama. También es posible que necesite escribir y anotar su código, para permitir que su compilador optimice mejor. SBCL tiene un buen compilador de diagnósticos para las anotaciones perdidas (hasta el punto de que la gente se queja de que es demasiado detallado al compilar).

En lo que respecta al tiempo de carga, puede ser que la carga de un archivo compilado tarde más (hay una gran cantidad de enlaces esencialmente dinámicos, si no se cambia el código con frecuencia, sino cambiando los datos que procesa, puede ser una ventaja preparar un nuevo archivo central con su código de filtrado de partículas que ya está en el núcleo).