La conclusión aquí:
¿Cuánto mejor son realmente los compiladores de Fortran?
es que gfortran y gcc son tan rápidos para un código simple. Entonces quería probar algo más complicado. Tomé el ejemplo de tiroteo de la norma espectral. Primero precalculo la matriz 2D A (:, :), y luego calculo la norma. (Creo que esta solución no está permitida en el tiroteo). He implementado la versión Fortran y C. Aquí está el código:
https://github.com/certik/spectral_norm
Las versiones más rápidas de gfortran son spectral_norm2.f90 y spectral_norm6.f90 (una usa el matmul incorporado y dot_product de Fortran, la otra implementa estas dos funciones en el código, sin diferencia de velocidad). El código C / C ++ más rápido que pude escribir es spectral_norm7.cpp. Los tiempos a partir de la versión git 457d9d9 en mi computadora portátil son:
$ time ./spectral_norm6 5500
1.274224153
real 0m2.675s
user 0m2.520s
sys 0m0.132s
$ time ./spectral_norm7 5500
1.274224153
real 0m2.871s
user 0m2.724s
sys 0m0.124s
Entonces la versión de gfortran es un poco más rápida. ¿Porqué es eso? Si envía una solicitud de extracción con una implementación de C más rápida (o simplemente pega un código), actualizaré el repositorio.
En Fortran paso una matriz 2D, mientras que en CI uso una matriz 1D. Siéntase libre de usar una matriz 2D o cualquier otra forma que le parezca adecuada.
En cuanto a los compiladores, comparemos gcc vs gfortran, icc vs ifort, etc. (A diferencia de la página de tiroteo, que compara ifort vs gcc.)
Actualización : usando la versión 179dae2, que mejora matmul3 () en mi versión C, ahora son tan rápidos:
$ time ./spectral_norm6 5500
1.274224153
real 0m2.669s
user 0m2.500s
sys 0m0.144s
$ time ./spectral_norm7 5500
1.274224153
real 0m2.665s
user 0m2.472s
sys 0m0.168s
La versión vectorizada de Pedro a continuación es más rápida:
$ time ./spectral_norm8 5500
1.274224153
real 0m2.523s
user 0m2.336s
sys 0m0.156s
Finalmente, como laxxy informa a continuación para los compiladores Intel, no parece haber una gran diferencia allí e incluso el código Fortran más simple (spectral_norm1) se encuentra entre los más rápidos.
Respuestas:
En primer lugar, ¡gracias por publicar esta pregunta / desafío! Como descargo de responsabilidad, soy un programador nativo de C con algo de experiencia en Fortran, y me siento como en casa en C, por lo que me centraré solo en mejorar la versión C. ¡Invito a todos los piratas de Fortran a probar también!
Solo para recordarles a los recién llegados de qué se trata: la premisa básica en este hilo era que gcc / fortran e icc / ifort deberían, dado que tienen los mismos back-end respectivamente, producir código equivalente para el mismo programa (semánticamente idéntico), independientemente de que sea en C o Fortran. La calidad del resultado depende solo de la calidad de las implementaciones respectivas.
Jugué un poco con el código y en mi computadora (ThinkPad 201x, Intel Core i5 M560, 2.67 GHz), usando
gcc
4.6.1 y los siguientes indicadores de compilación:También seguí adelante y escribí una versión SIMD-vectorizada en lenguaje C del código C ++
spectral_norm_vec.c
:Las tres versiones fueron compiladas con las mismas banderas y la misma
gcc
versión. Tenga en cuenta que envolví la llamada a la función principal en un bucle de 0..9 para obtener tiempos más precisos.Entonces, con indicadores de compilador "mejores", la versión de C ++ supera a la versión de Fortran y los bucles vectorizados codificados a mano solo proporcionan una mejora marginal. Un vistazo rápido al ensamblador para la versión C ++ muestra que los bucles principales también se han vectorizado, aunque se han desenrollado de forma más agresiva.
También eché un vistazo al ensamblador generado por
gfortran
y aquí está la gran sorpresa: sin vectorización. Atribuyo el hecho de que es solo un poco más lento al problema de que el ancho de banda es limitado, al menos en mi arquitectura. Para cada una de las multiplicaciones de la matriz, se atraviesan 230 MB de datos, lo que prácticamente inunda todos los niveles de caché. Si utiliza un valor de entrada más pequeño, por ejemplo100
, las diferencias de rendimiento aumentan considerablemente.Como nota al margen, en lugar de obsesionarse con las banderas de vectorización, alineación y compilación, la optimización más obvia sería calcular las primeras iteraciones en aritmética de precisión simple, hasta que tengamos ~ 8 dígitos del resultado. Las instrucciones de precisión simple no solo son más rápidas, sino que la cantidad de memoria que debe moverse también se reduce a la mitad.
fuente
gcc
/gfortran
estás usando? En los hilos anteriores, diferentes versiones dieron resultados significativamente diferentes.matmul2
en la versión Fortran es semánticamente equivalente amatmul3
en mi versión C. Las dos versiones son realmente ahora mismo y por lo tantogcc
/gfortran
debe producir los mismos resultados para ambos, por ejemplo, nadie front-end / idioma es mejor que el otro, en este caso.gcc
solo tiene la ventaja de que podríamos explotar las instrucciones vectorizadas si así lo decidiéramos.vector_size
atributo para hacer que el código sea independiente de la plataforma, es decir, el uso de esta sintaxisgcc
debería poder generar código vectorizado para otras plataformas, por ejemplo, usando AltiVec en la arquitectura IBM Power.La respuesta del usuario 389 ha sido eliminada, pero permítanme decir que estoy firmemente en su campo: no veo lo que aprendemos al comparar micro-puntos de referencia en diferentes idiomas. No me sorprende tanto que C y Fortran obtengan el mismo rendimiento en este punto de referencia dado lo corto que es. Pero el punto de referencia también es aburrido, ya que se puede escribir fácilmente en ambos idiomas en un par de docenas de líneas. Desde el punto de vista del software, ese no es un caso representativo: deberíamos preocuparnos por el software que tiene 10,000 o 100,000 líneas de código y cómo los compiladores lo hacen. Por supuesto, a esa escala, uno descubrirá rápidamente otras cosas: que el lenguaje A requiere 10,000 líneas mientras que el lenguaje B requiere 50,000. O al revés, dependiendo de lo que quieras hacer. Y de repente '
En otras palabras, no me importa mucho que tal vez mi aplicación podría ser un 50% más rápida si la desarrollé en Fortran 77 si en cambio solo me tomaría 1 mes para que funcione correctamente, mientras que me llevaría 3 meses en F77. El problema con la pregunta aquí es que se centra en un aspecto (núcleos individuales) que, en mi opinión, no es relevante en la práctica.
fuente
Resulta que puedo escribir un código Python (usando numpy para hacer las operaciones BLAS) más rápido que el código Fortran compilado con el compilador gfortran de mi sistema.
foo1.py:
y sn6a.f90, un spectral_norm6.f90 muy ligeramente modificado:
fuente
Lo comprobé con compiladores Intel. Con 11.1 (-fast, lo que implica -O3), y con 12.0 (-O2), los más rápidos son 1,2,6,7 y 8 (es decir, los códigos "más simples" de Fortran y C, y el C vectorizado a mano) - estos son indistinguibles entre sí a ~ 1.5s. Las pruebas 3 y 5 (con la matriz como función) son más lentas; # 4 No pude compilar.
En particular, si compila con 12.0 y -O3, en lugar de -O2, los primeros 2 ("más simples") códigos Fortran se ralentizan MUCHO (1.5 -> 10.2 segundos) - esta no es la primera vez que veo algo así esto, pero este puede ser el ejemplo más dramático. Si este sigue siendo el caso en la versión actual, creo que sería una buena idea informarlo a Intel, ya que claramente hay algo que va muy mal con sus optimizaciones en este caso bastante simple.
De lo contrario, estoy de acuerdo con Jonathan en que este no es un ejercicio particularmente informativo :)
fuente