¿Cuánto mejor son realmente los compiladores de Fortran?

74

Esta pregunta es una extensión de dos discusiones que surgieron recientemente en las respuestas a " C ++ vs Fortran for HPC ". Y es un poco más un desafío que una pregunta ...

Uno de los argumentos más escuchados a favor de Fortran es que los compiladores son simplemente mejores. Como la mayoría de los compiladores de C / Fortran comparten el mismo back-end, el código generado para programas semánticamente equivalentes en ambos idiomas debe ser idéntico. Sin embargo, se podría argumentar que C / Fortran es más / menos fácil de optimizar para el compilador.

Así que decidí probar una prueba simple: obtuve una copia de daxpy.f y daxpy.c y los compilé con gfortran / gcc.

Ahora daxpy.c es solo una traducción f2c de daxpy.f (código generado automáticamente, feo como diablos), así que tomé ese código y lo limpié un poco (conozca daxpy_c), lo que básicamente significaba volver a escribir el bucle más interno como

for ( i = 0 ; i < n ; i++ )
    dy[i] += da * dx[i];

Finalmente, lo reescribí (ingrese daxpy_cvec) usando la sintaxis vectorial de gcc:

#define vector(elcount, type)  __attribute__((vector_size((elcount)*sizeof(type)))) type
vector(2,double) va = { da , da }, *vx, *vy;

vx = (void *)dx; vy = (void *)dy;
for ( i = 0 ; i < (n/2 & ~1) ; i += 2 ) {
    vy[i] += va * vx[i];
    vy[i+1] += va * vx[i+1];
    }
for ( i = n & ~3 ; i < n ; i++ )
    dy[i] += da * dx[i];

Tenga en cuenta que uso vectores de longitud 2 (eso es todo lo que permite SSE2) y que proceso dos vectores a la vez. Esto se debe a que en muchas arquitecturas, podemos tener más unidades de multiplicación que elementos vectoriales.

Todos los códigos se compilaron usando gfortran / gcc versión 4.5 con las marcas "-O3 -Wall -msse2 -march = native -ffast-math -fomit-frame-pointer -malign-double -fstrict-aliasing". En mi computadora portátil (CPU Intel Core i5, M560, 2.67GHz) obtuve la siguiente salida:

pedro@laika:~/work/fvsc$ ./test 1000000 10000
timing 1000000 runs with a vector of length 10000.
daxpy_f took 8156.7 ms.
daxpy_f2c took 10568.1 ms.
daxpy_c took 7912.8 ms.
daxpy_cvec took 5670.8 ms.

Entonces, el código Fortran original lleva un poco más de 8.1 segundos, la traducción automática del mismo toma 10.5 segundos, la implementación ingenua de C lo hace en 7.9 y el código explícitamente vectorizado lo hace en 5.6, marginalmente menos.

Eso es Fortran siendo un poco más lento que la implementación de C ingenua y 50% más lento que la implementación de C vectorizada.

Así que aquí está la pregunta: soy un programador nativo de C y estoy bastante seguro de que hice un buen trabajo con ese código, pero el código Fortran se tocó por última vez en 1993 y, por lo tanto, podría estar un poco desactualizado. Dado que no me siento tan cómodo codificando en Fortran como otros aquí, ¿alguien puede hacer un mejor trabajo, es decir, más competitivo en comparación con cualquiera de las dos versiones C?

Además, ¿alguien puede probar esta prueba con icc / ifort? La sintaxis vectorial probablemente no funcionará, pero me gustaría ver cómo se comporta allí la ingenua versión C. Lo mismo ocurre con cualquiera con xlc / xlf por ahí.

He subido las fuentes y un Makefile aquí . Para obtener tiempos precisos, configure CPU_TPS en test.c a la cantidad de Hz en su CPU. Si encuentra alguna mejora en alguna de las versiones, ¡publíquela aquí!

Actualizar:

Agregué el código de prueba de stali a los archivos en línea y lo completé con una versión C. Modifiqué los programas para hacer 1'000'000 bucles en vectores de longitud 10'000 para que sean consistentes con la prueba anterior (y porque mi máquina no podía asignar vectores de longitud 1'000'000'000, como en el original de stali código). Como los números ahora son un poco más pequeños, utilicé la opción -par-threshold:50para que el compilador sea más propenso a paralelizarse. La versión icc / ifort utilizada es 12.1.2 20111128 y los resultados son los siguientes

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./icctest_c
3.27user 0.00system 0:03.27elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./icctest_f
3.29user 0.00system 0:03.29elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./icctest_c
4.89user 0.00system 0:02.60elapsed 188%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./icctest_f
4.91user 0.00system 0:02.60elapsed 188%CPU

En resumen, los resultados son, a todos los efectos prácticos, idénticos para las versiones C y Fortran, y ambos códigos se paralelizan automáticamente. ¡Tenga en cuenta que los tiempos rápidos en comparación con la prueba anterior se deben al uso de la aritmética de coma flotante de precisión simple!

Actualizar:

Aunque realmente no me gusta a dónde va la carga de la prueba aquí, he vuelto a codificar el ejemplo de multiplicación de matriz de stali en C y lo agregué a los archivos en la web . Estos son los resultados del bucle triple para una y dos CPU:

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_f 2500
 triple do time   3.46421700000000     
3.63user 0.06system 0:03.70elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_c 2500
triple do time 3.431997791385768
3.58user 0.10system 0:03.69elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_f 2500
 triple do time   5.09631900000000     
5.26user 0.06system 0:02.81elapsed 189%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_c 2500
triple do time 2.298916975280899
4.78user 0.08system 0:02.62elapsed 184%CPU

Tenga cpu_timeen cuenta que en Fortran mide el tiempo de CPU y no el tiempo del reloj de pared, así que terminé las llamadas timepara compararlas con 2 CPU. No hay una diferencia real entre los resultados, excepto que la versión C funciona un poco mejor en dos núcleos.

Ahora para el matmulcomando, por supuesto solo en Fortran ya que este intrínseco no está disponible en C:

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_f 2500
 matmul    time   23.6494780000000     
23.80user 0.08system 0:23.91elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_f 2500
 matmul    time   26.6176640000000     
26.75user 0.10system 0:13.62elapsed 197%CPU

Guau. Eso es absolutamente terrible. ¿Alguien puede descubrir lo que estoy haciendo mal o explicar por qué este intrínseco sigue siendo algo bueno?

No agregué las dgemmllamadas al punto de referencia, ya que son llamadas de biblioteca a la misma función en el Intel MKL.

Para las pruebas futuras, puede alguien sugerir un ejemplo conocido a ser más lenta en C que en Fortran?

Actualizar

Para verificar la afirmación de stali de que lo matmulintrínseco es "un orden de magnitud" más rápido que el producto de matriz explícito en matrices más pequeñas, modifiqué su propio código para multiplicar matrices de tamaño 100x100 usando ambos métodos, 10'000 veces cada una. Los resultados, en una y dos CPU, son los siguientes:

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_f 10000 100
 matmul    time   3.61222500000000     
 triple do time   3.54022200000000     
7.15user 0.00system 0:07.16elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_f 10000 100
 matmul    time   4.54428400000000     
 triple do time   4.31626900000000     
8.86user 0.00system 0:04.60elapsed 192%CPU

Actualizar

Grisu tiene razón al señalar que, sin optimizaciones, gcc convierte las operaciones en números complejos en llamadas a funciones de la biblioteca, mientras que gfortran las incluye en unas pocas instrucciones.

El compilador de C generará el mismo código compacto si la opción -fcx-limited-rangeestá configurada, es decir, se le indica al compilador que ignore los posibles sobre / subflujos en los valores intermedios. Esta opción está configurada de forma predeterminada en gfortran y puede dar lugar a resultados incorrectos. Forzar -fno-cx-limited-rangeen gfortran no cambió nada.

Por lo tanto, este es en realidad un argumento en contra del uso de gfortran para cálculos numéricos: las operaciones con valores complejos pueden desbordarse / desbordarse incluso si los resultados correctos están dentro del rango de punto flotante. Este es en realidad un estándar de Fortran. En gcc, o en C99 en general, el valor predeterminado es hacer las cosas estrictamente (leer IEEE-754 compatible) a menos que se especifique lo contrario.

Recordatorio: tenga en cuenta que la pregunta principal era si los compiladores de Fortran producen un código mejor que los compiladores de C. Este no es el lugar para discusiones sobre los méritos generales de un idioma sobre otro. Lo que realmente me interesaría es si alguien puede encontrar una manera de convencer a gfortran para que produzca un daxpy tan eficiente como el de C usando la vectorización explícita, ya que esto ejemplifica los problemas de tener que confiar en el compilador exclusivamente para la optimización SIMD, o un caso en el que un compilador Fortran supera a su contraparte C.

Pedro
fuente
Un problema de tiempo es que si su procesador realiza el modo paso a paso / turbo de frecuencia, estos resultados podrían estar en todo el mapa.
Bill Barth
1
Su daxpy_c.c está actualizando x con un múltiplo de x y no toca y en absoluto. Es posible que desee arreglar eso para que sea justo ...
Jack Poulson
1
@JackPoulson: Buena captura, reparó y actualizó los resultados.
Pedro
2
Además, estoy bastante seguro de que la diferencia se debe completamente a que el desenrollado manual en la versión Fortran confunde al compilador. Cuando lo reemplazo con el mismo bucle simple que pones en tu versión C, el rendimiento entre los dos es casi idéntico. Sin el cambio, la versión Fortran fue más lenta con los compiladores Intel.
Jack Poulson
1
@permeakra: En realidad, el estándar C99 especifica la restrictpalabra clave que le dice al compilador exactamente eso: suponer que una matriz no se superpone con ninguna otra estructura de datos.
Pedro

Respuestas:

37

La diferencia en sus tiempos parece deberse al desenrollado manual del daxpy Fortran de paso de unidad . Los siguientes tiempos están en un Xeon X5650 de 2.67 GHz, usando el comando

./test 1000000 10000

Compiladores Intel 11.1

Fortran con desenrollado manual: 8.7 segundos
Fortran sin desenrollado manual: 5.8 segundos
C sin desenrollado manual: 5.8 segundos

Compiladores GNU 4.1.2

Fortran con desenrollado manual: 8.3 seg.
Fortran sin desenrollado manual: 13.5 seg.
C sin desenrollado manual: 13.6 seg.
C con atributos vectoriales: 5.8 seg.

Compiladores GNU 4.4.5

Fortran con desenrollado manual: 8.1 segundos
Fortran sin desenrollado manual: 7.4 segundos
C sin desenrollado manual: 8.5 segundos
C con atributos vectoriales: 5.8 segundos

Conclusiones

  • El desenrollado manual ayudó a los compiladores Fortran de GNU 4.1.2 en esta arquitectura, pero perjudica la versión más reciente (4.4.5) y el compilador Intel Fortran.
  • El compilador GNU 4.4.5 C es mucho más competitivo con Fortran que para la versión 4.2.1.
  • Los intrínsecos vectoriales permiten que el rendimiento de GCC coincida con los compiladores de Intel.

¿Es hora de probar rutinas más complicadas como dgemv y dgemm?

Jack Poulson
fuente
Gracias por los resultados! ¿Qué versión de gcc estabas usando y puedes ser un poco más específico con respecto a la CPU?
Pedro
2
Su compilador es más antiguo que su CPU ... ¿Puede probar con gcc-4.5?
Pedro
1
Solo lo intenté. La versión vectorizada con GCC 4.4.5 coincide exactamente con los resultados de Intel 11.1.
Jack Poulson
1
Acabo de instalar gcc / gfortran versión 4.4.5 y no puedo reproducir las diferencias sin desenrollar. De hecho, en el ensamblador generado para ambos casos, el bucle más interno es idéntico, excepto por los nombres de registro utilizados, que son intercambiables. ¿Puedes volver a ejecutar tus pruebas solo para estar seguro?
Pedro
44
¿Podemos decir que esto resuelve el viejo debate "seguimos usando fortran porque es más eficaz", para que finalmente podamos tirarlo al contenedor de basura?
Stefano Borini
16

Llego tarde a esta fiesta, así que es difícil para mí seguir todo lo anterior. La pregunta es grande, y creo que si estás interesado, podría dividirse en pedazos más pequeños. Una cosa que me interesó fue simplemente el rendimiento de sus daxpyvariantes, y si Fortran es más lento que C en este código muy simple.

Al ejecutar tanto en mi computadora portátil (Macbook Pro, Intel Core i7, 2.66 GHz), el rendimiento relativo de su versión C vectorizada a mano y la versión Fortran no vectorizada a mano dependen del compilador utilizado (con sus propias opciones):

Compiler     Fortran time     C time
GCC 4.6.1    5408.5 ms        5424.0 ms
GCC 4.5.3    7889.2 ms        5532.3 ms
GCC 4.4.6    7735.2 ms        5468.7 ms

Entonces, parece que GCC mejoró en la vectorización del bucle en la rama 4.6 de lo que era antes.


En el debate general, creo que uno puede escribir código rápido y optimizado tanto en C como en Fortran, casi como en lenguaje ensamblador. Sin embargo, señalaré una cosa: al igual que cuando el ensamblador es más tedioso de escribir que C pero le da un control más preciso sobre lo que ejecuta la CPU, C tiene un nivel más bajo que Fortran. Por lo tanto, le brinda más control sobre los detalles, lo que puede ayudar a optimizar, donde la sintaxis estándar de Fortran (o sus extensiones de proveedor) pueden carecer de funcionalidad. Un caso es el uso explícito de tipos de vectores, otro es la posibilidad de especificar la alineación de variables a mano, algo de lo que Fortran es incapaz.

F'x
fuente
bienvenido a scicomp! Estoy de acuerdo en que las versiones del compilador son tan importantes como el lenguaje en este caso. ¿Querías decir 'de' en lugar de 'apagado en tu última oración?
Aron Ahmadia
9

La forma en que escribiría AXPY en Fortran es ligeramente diferente. Es la traducción exacta de las matemáticas.

m_blas.f90

 module blas

   interface axpy
     module procedure saxpy,daxpy
   end interface

 contains

   subroutine daxpy(x,y,a)
     implicit none
     real(8) :: x(:),y(:),a
     y=a*x+y
   end subroutine daxpy

   subroutine saxpy(x,y,a)
     implicit none
     real(4) :: x(:),y(:),a
     y=a*x+y
   end subroutine saxpy

 end module blas

Ahora llamemos a la rutina anterior en un programa.

test.f90

 program main

   use blas
   implicit none

   real(4), allocatable :: x(:),y(:)
   real(4) :: a
   integer :: n

   n=1000000000
   allocate(x(n),y(n))
   x=1.0
   y=2.0
   a=5.0
   call axpy(x,y,a)
   deallocate(x,y)

 end program main

Ahora compilemos y ejecútelo ...

login1$ ifort -fast -parallel m_blas.f90 test.f90
ipo: remark #11000: performing multi-file optimizations
ipo: remark #11005: generating object file /tmp/ipo_iforttdqZSA.o

login1$ export OMP_NUM_THREADS=1
login1$ time ./a.out 
real    0 m 4.697 s
user    0 m 1.972 s
sys     0 m 2.548 s

login1$ export OMP_NUM_THREADS=2
login1$ time ./a.out 
real    0 m 2.657 s
user    0 m 2.060 s
sys     0 m 2.744 s

Tenga en cuenta que no estoy usando ningún bucle o ninguna directiva explícita de OpenMP . ¿Sería esto posible en C (es decir, sin uso de bucles y auto-paralelización)? No uso C, así que no lo sé.

stali
fuente
La paralelización automática es una característica de los compiladores de Intel (tanto Fortran como C), y no del lenguaje. Por lo tanto, el equivalente en C también debe ser paralelo. Solo por curiosidad, ¿cómo funciona para un n = 10000 más moderado?
Pedro
3
Ese era todo el punto. Autopar es más fácil en Fortran debido a que Fortran (a diferencia de C) admite operaciones de matriz completa como matmult, transposición, etc. Por lo tanto, la optimización del código es más fácil para los compiladores de Fortran. GFortran (que ha utilizado) no tiene los recursos de desarrollador para optimizar el compilador de Fortran, ya que su objetivo principal es implementar el estándar Fortran 2003 en lugar de la optimización.
stali
Uhmm ... El compilador Intel C / C ++ icctambién realiza paralelización automática. He agregado un archivo icctest.ca las otras fuentes. ¿Puede compilarlo con las mismas opciones que utilizó anteriormente, ejecutarlo e informar los tiempos? Tuve que agregar una declaración printf a mi código para evitar que gcc optimizara todo. ¡Esto es solo un truco rápido y espero que esté libre de errores!
Pedro
Descargué los últimos compiladores icc / ifort y realicé las pruebas yo mismo. La pregunta se ha actualizado para incluir estos nuevos resultados, es decir, que la autovectorización de Intel funciona tanto en Fortran como en C.
Pedro
1
Gracias. Sí, noté que hay poca diferencia quizás porque los bucles son simples y las operaciones son de Nivel 1 BLAS. Pero como dije antes debido a la capacidad de Fortran para realizar operaciones de matriz completa y el uso de palabras clave como PURE / ELEMENTAL, hay más espacio para la optimización del compilador. Cómo los compiladores usan esta información y qué hace realmente es algo diferente. También puedes probar matmul si quieres bpaste.net/show/23035
stali
6

Creo que no solo es interesante cómo un compilador optimiza el código para el hardware moderno. Especialmente entre GNU C y GNU Fortran, la generación de código puede ser muy diferente.

Consideremos otro ejemplo para mostrar las diferencias entre ellos.

Usando números complejos, el compilador GNU C produce una gran sobrecarga para operaciones aritméticas casi muy básicas en un número complejo. El compilador Fortran ofrece un código mucho mejor. Echemos un vistazo al siguiente pequeño ejemplo en Fortran:

COMPLEX*16 A,B,C
C=A*B

da (gfortran -g -o complex.fo -c complex.f95; objdump -d -S complex.fo):

C=A*B
  52:   dd 45 e0                fldl   -0x20(%ebp)
  55:   dd 45 e8                fldl   -0x18(%ebp)
  58:   dd 45 d0                fldl   -0x30(%ebp)
  5b:   dd 45 d8                fldl   -0x28(%ebp)
  5e:   d9 c3                   fld    %st(3)
  60:   d8 ca                   fmul   %st(2),%st
  62:   d9 c3                   fld    %st(3)
  64:   d8 ca                   fmul   %st(2),%st
  66:   d9 ca                   fxch   %st(2)
  68:   de cd                   fmulp  %st,%st(5)
  6a:   d9 ca                   fxch   %st(2)
  6c:   de cb                   fmulp  %st,%st(3)
  6e:   de e9                   fsubrp %st,%st(1)
  70:   d9 c9                   fxch   %st(1)
  72:   de c2                   faddp  %st,%st(2)
  74:   dd 5d c0                fstpl  -0x40(%ebp)
  77:   dd 5d c8                fstpl  -0x38(%ebp)

Cuáles son los códigos de máquina de 39 bytes. Cuando consideramos lo mismo en C

 double complex a,b,c; 
 c=a*b; 

y eche un vistazo a la salida (hecho de la misma manera que arriba), obtenemos:

  41:   8d 45 b8                lea    -0x48(%ebp),%eax
  44:   dd 5c 24 1c             fstpl  0x1c(%esp)
  48:   dd 5c 24 14             fstpl  0x14(%esp)
  4c:   dd 5c 24 0c             fstpl  0xc(%esp)
  50:   dd 5c 24 04             fstpl  0x4(%esp)
  54:   89 04 24                mov    %eax,(%esp)
  57:   e8 fc ff ff ff          call   58 <main+0x58>
  5c:   83 ec 04                sub    $0x4,%esp
  5f:   dd 45 b8                fldl   -0x48(%ebp)
  62:   dd 5d c8                fstpl  -0x38(%ebp)
  65:   dd 45 c0                fldl   -0x40(%ebp)
  68:   dd 5d d0                fstpl  -0x30(%ebp)

También son códigos de máquina de 39 bytes, pero el paso 57 de la función se refiere, realiza la parte adecuada del trabajo y realiza la operación deseada. Entonces tenemos un código de máquina de 27 bytes para ejecutar la operación múltiple. La función detrás es muldc3 proporcionada por libgcc_s.soy tiene una huella de 1375 bytes en el código de máquina. Esto ralentiza drásticamente el código y proporciona una salida interesante cuando se utiliza un generador de perfiles.

Cuando implementamos los ejemplos BLAS anteriores zaxpyy realizamos la misma prueba, el compilador Fortran debería dar mejores resultados que el compilador C.

(Utilicé GCC 4.4.3 para este experimento, pero noté este comportamiento que otros GCC lanzan).

Entonces, en mi opinión, no solo pensamos en la paralelización y la vectorización cuando pensamos en cuál es el mejor compilador, también tenemos que ver cómo se traducen las cosas básicas al código del ensamblador. Si esta traducción da un código incorrecto, la optimización solo puede usar esto como entrada.

MK aka Grisu
fuente
1
Acabo de inventar un ejemplo en la línea de su código, complex.cy lo agregué al código en línea. Tuve que agregar toda la entrada / salida para asegurarme de que nada esté optimizado. Solo recibo una llamada __muldc3si no la uso -ffast-math. Con -O2 -ffast-mathyo obtengo 9 líneas de ensamblador en línea. ¿Puedes confirmar esto?
Pedro
He encontrado una causa más específica para la diferencia en el ensamblador generado y he agregado esto a mi pregunta anterior.
Pedro
El uso de -O2 lleva al compilador a calcular todo lo que es posible en tiempo de ejecución, por eso a veces se pierden tales construcciones. La opción -ffast-math no debe usarse en computación científica cuando desee confiar en los resultados.
MK aka Grisu
1
Bueno, por ese argumento (no -ffast-math) no deberías usar Fortran para tus cálculos de valores complejos. Como describo en la actualización de mi pregunta, -ffast-matho, más en general, -fcx-limited-rangeobliga a gcc a usar los mismos cálculos de rango restringido que no son IEEE que son estándar en Fortran. Entonces, si desea la gama completa de valores complejos y los Inf y NaN correctos, no debe usar Fortran ...
Pedro
2
@Pedro: si quieres que GCC se comporte como GFortran wrt. multiplicación y división complejas, debe usar las reglas -fcx-fortran-rules.
Janneb
4

Amigos

Esta discusión me pareció muy interesante, pero me sorprendió ver que reordenar los bucles en el ejemplo de Matmul cambió la imagen. No tengo un compilador de inteligencia disponible en mi máquina actual, así que estoy usando gfortran, pero reescribo los bucles en mm_test.f90 para

call cpu_time(start)  
do r=1,runs  
  mat_c=0.0d0  
     do j=1,n  
        do k=1,n  
  do i=1,n  
           mat_c(i,j)=mat_c(i,j)+mat_a(i,k)*mat_b(k,j)  
        end do  
     end do  
  end do  
end do  
call cpu_time(finish)  

Cambié los resultados completos de mi máquina.

Los resultados de sincronización de la versión anterior fueron:

#time ./mm_test_f 10000 100
 matmul    time   6.3620000000000001     
 triple do time   21.420999999999999     

mientras que con los bucles triples reorganizados como se indica anteriormente:

#time ./mm_test_f 10000 100
 matmul    time   6.3929999999999998     
 triple do time   3.9190000000000005    

Esto es gcc / gfortran 4.7.2 20121109 en una CPU Intel (R) Core (TM) i7-2600K a 3.40GHz

Las banderas del compilador utilizadas fueron las del Makefile que obtuve aquí ...

Schatzi
fuente
3
Eso no es sorprendente, ya que el almacenamiento de la matriz en la memoria favorece un orden, es decir, si las filas se almacenan contiguamente, es mejor recorrer las filas más internas, ya que puede cargar cada fila una vez en la memoria local rápida en comparación con la carga repetida (una porción de ) para acceder a un solo elemento. Ver stackoverflow.com/questions/7395556 .
Christian Clason
Supongo que me sorprendió que el "matmul intrínseco" no estuviera codificado para hacer las cosas de esta manera. Es sustancialmente más rápido con el triple do ordenado de la segunda manera. Parece estar en este conjunto de compiladores, ya que las versiones anteriores de gfortran a las que puedo llegar eran más "planas" en su sincronización, no importaba de qué manera hiciste el multitiempo, tomó casi el mismo tiempo.
Schatzi
-2

No son los lenguajes los que hacen que el código se ejecute más rápido, aunque sí ayudan. Es el compilador, la CPU y el sistema operativo los que hacen que los códigos se ejecuten más rápido. Comparar idiomas es simplemente un nombre inapropiado, inútil y sin sentido. No tiene ningún sentido porque está comparando dos variables: el idioma y el compilador. Si un código se ejecuta más rápido, no sabe cuánto es el idioma o cuánto es el compilador. No entiendo por qué la comunidad informática simplemente no entiende esto :-(

Wadud Miah
fuente