¿Son excesivas DAXPY, DCOPY, DSCAL?

8

He implementado CG en FORTRAN al vincularlo a Intel MKL.

Cuando hay declaraciones como: ( Consulte Wikipedia )

 p=r; 
 x=x+alpha*p
 r=r-alpha*Ap;

o similares en QMR (en una cantidad mucho mayor)

v_tld = r;
y = v_tld;
rho = norm( y );
w_tld = r;
z = w_tld;
xi = norm( z ); (and more)

¿Tiene sentido utilizar implementaciones BLAS Nivel 1 como DAXPY, DCOPY, DSCAL? La motivación para mi pregunta es:

  1. Tengo 2 implementaciones de los algoritmos. Uno en el que solo he vinculado Norms y MatVecs a MKL; copiar, escalar y agregar se realiza mediante las funciones intrínsecas de Fortran y otra donde BLAS realiza todas las subrutinas posibles.

  2. Tenía la idea de que nada puede ser más rápido que BLAS. Pero, resulta que mi código usando las funciones intrínsecas de Fortran corrió 100% más rápido que uno con las subrutinas BLAS Nivel 1 (FWIW, esto no fue un pequeño problema, fue resolver un sistema denso de tamaño 13k x 13k que llenó mis 4 GB de RAM). Estaba ejecutando ambos en 2 hilos (en una máquina de 2 núcleos) ifort QMR.f90 -mklconMKL_DYNAMIC=TRUE

  3. Había hecho una pregunta sobre SO con respecto a la extensión de BLAS, pero a medida que intentaba incluir BLAS Nivel 1 en mi código, mi código se volvía cada vez más lento.

¿Estoy haciendo algo mal o se espera esto?

Además, ¿tiene sentido intentar extender BLAS para hacer operaciones no obvias como y = 2.89*xpor DCOPY(n,2.89*x,1,y,1) or even DSCAL then DCOPY?


Lo que también es interesante es DDOTy DNRM2mejora el rendimiento. Lo atribuí al hecho de que, dado que realizan multiplicaciones de doble precisión, podría ser útil ponerlas en paralelo.

Pregunta complementaria: ¿ Cuándo decide si una operación BLAS Nivel 1 realmente ayudará al rendimiento?

Agregando: Actualmente, estoy corriendo en una computadora portátil i3 2.13 GHz con 4 GB de RAM y información de proceso Debian de 64 bits aquí . Pero obtengo respuestas similares en una estación de trabajo Intel Xeon 12 core con 24 GB de RAM.

Encuesta
fuente
¿En qué hardware estás corriendo?
Pedro
2
No asuma que no hay nada más rápido que BLAS / LAPACK. Están optimizados para la utilidad, no necesariamente para ganar la medalla de oro. Cuando la velocidad es su necesidad, puede probar esto .
Mike Dunlavey, el
DCOPY (n, 2.89 * x, 1, y, 1) no va a hacer lo que quiere. Está completamente mal. La función que desea es DAXPY.
Jeff
MKL_DYNAMIC = TRUE es terrible para el rendimiento. No conozco ningún código científico que se beneficie de esto. Desactívelo y configure el número de hilo a través de MKL_NUM_THREADS / OMP_NUM_THREADS y active OMP_SCHEDULE = STATIC.
Jeff

Respuestas:

6

Si su objetivo es realmente exprimir tanto rendimiento como sea posible, entonces es importante recordar:

  1. Es posible que la biblioteca (BLAS) no haya sido ajustada para su sistema / configuración exacta.
  2. Los desarrolladores de bibliotecas cometen errores.

Una biblioteca BLAS ajustada por el proveedor ciertamente debería ser su enfoque predeterminado, pero si se ha tomado el tiempo de kernels individuales y ha notado que alguna otra implementación es más rápida, entonces, por todos los medios, use la otra implementación. Perder el uso de intrínsecos de vectores posiblemente podría conducir a una gran diferencia de rendimiento.

Es posible que su mejor apuesta para rutinas simples como daxpy y dscal sea ​​un bucle escrito a mano que explote la intrínseca del vector.

Jack Poulson
fuente
Si bien no puedo refutar lógicamente (2), no creo que sea pertinente aquí. DCOPY, DSCAL y DAXPY son casi triviales de implementar correctamente, por lo tanto, dudo que las personas cometan errores. El problema es que su trivialidad se deriva del hecho de que estas funciones alcanzan el límite de hardware muy rápidamente y, por lo tanto, muy pocas optimizaciones son efectivas.
Jeff el
3

Dado el estado de la optimización de los compiladores de hoy en día, no creo que haya mucho vudú en las rutinas BLAS lineales, por ejemplo DAXPY, DCOPYy DSCAL, que su compilador no tiene ya, por ejemplo, SSE-vectorización y desenrollado del bucle.

Si el código es el mismo, la única diferencia entre su rutina y una llamada al BLAS de MKL es la sobrecarga de la llamada de función y cualquier magia adicional que MKL podría estar tratando de hacer allí. Si este es el caso, la diferencia entre su código y el código de MKL debe ser constante, independiente del tamaño del problema / vector.

Esta pregunta tiene ecos interesantes de esta pregunta , que también se usa DAXPYcomo ejemplo.

Pedro
fuente
2

El estándar BLAS en realidad tiene varias comprobaciones de la corrección de los argumentos de la función que son innecesarios en muchas situaciones. Ver esta implementación de referencia de daxpy.f. Además, las constantes como INCXlas conoce habitualmente en tiempo de compilación, pero la implementación no puede asumirlas. BLAS llama a unidades de compilación cruzada, y no conozco ningún compilador que pueda optimizarlas sin activar la optimización completa del programa.

  • Una nota al margen graciosa de esto es que el Compilador Intel ahora reconoce los bucles multiplicados matriz-matriz BLAS 3, y transformará este código en la llamada x equivalente gemm, con suficiente optimización habilitada.
Aron Ahmadia
fuente
¿Ha ejecutado el experimento donde elimina los condicionales en DAXPY para ver si eso tiene algún impacto en el rendimiento? Dudo seriamente que lo haga.
Jeff
No, pero he escrito código de ensamblaje puro y superado el DAXPY proporcionado por el proveedor en BLAS en un par de plataformas :)
Aron Ahmadia
1

Las funciones BLAS1 representan un conjunto de núcleos que tienen un ancho de banda limitado porque su intensidad de cálculo es baja. En particular, estos núcleos hacen O (1) flops por acceso a memoria. Esto significa que en el hardware moderno, se ejecutan a una pequeña fracción del pico y esencialmente no hay nada que pueda hacer al respecto. La mejor implementación de BLAS1 verificará la alineación y el módulo de la longitud del vector FPU y funcionará en el pico de ancho de banda, que es probable que sea del 5-10% del pico de cálculo.

Cuando escribe estas operaciones explícitamente en la fuente, un buen compilador las reconoce de inmediato y presenta una implementación óptima que es equivalente a la BLAS1 mencionada anteriormente. Sin embargo, debido a que el compilador sabe más sobre el contexto, puede evitar ciertas ramas (no es que importen demasiado) y la sobrecarga de las llamadas de función, así como también realizar transformaciones de orden superior en el código que serían bloqueadas por una llamada de función a Una biblioteca opaca.

Hay una variedad de experimentos que puede realizar para determinar qué está afectando realmente el rendimiento de su código. Son bastante obvios, así que no los enumeraré aquí.

Jeff
fuente