A conclusão aqui:
Quão melhores são os compiladores Fortran realmente?
é que o gfortran e o gcc são tão rápidos quanto o código simples. Então, eu queria tentar algo mais complicado. Peguei o exemplo do tiroteio da norma espectral. Primeiro eu pré-calculo a matriz 2D A (:, :) e depois calculo a norma. (Esta solução não é permitida na disputa, eu acho.) Eu implementei o Fortran e a versão C. Aqui está o código:
https://github.com/certik/spectral_norm
As versões mais rápidas do gfortran são spectral_norm2.f90 e spectral_norm6.f90 (uma usa o matmul e o dot_product integrados do Fortran, a outra implementa essas duas funções no código - sem diferença de velocidade). O código C / C ++ mais rápido que eu pude escrever é spectral_norm7.cpp. Os tempos da versão git 457d9d9 no meu laptop são:
$ 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
Portanto, a versão do gfortran é um pouco mais rápida. Por que é que? Se você enviar uma solicitação pull com uma implementação C mais rápida (ou apenas colar um código), atualizarei o repositório.
No Fortran, passo um array 2D, enquanto no CI use um array 1D. Sinta-se à vontade para usar uma matriz 2D ou qualquer outra maneira que achar melhor.
Quanto aos compiladores, vamos comparar gcc vs gfortran, icc vs ifort e assim por diante. (Diferentemente da página de tiroteios, que compara ifort x gcc.)
Atualização : usando a versão 179dae2, que melhora o matmul3 () na minha versão C, eles agora são mais 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
A versão vetorizada de Pedro abaixo é mais rápida:
$ time ./spectral_norm8 5500
1.274224153
real 0m2.523s
user 0m2.336s
sys 0m0.156s
Finalmente, como os relatórios laxxy abaixo para os compiladores Intel, não parece haver uma grande diferença, e mesmo o código Fortran mais simples (spectral_norm1) está entre os mais rápidos.
Respostas:
Antes de tudo, obrigado por postar esta pergunta / desafio! Como isenção de responsabilidade, sou programador nativo em C com alguma experiência em Fortran e me sinto mais à vontade em C; portanto, vou me concentrar apenas em melhorar a versão em C. Convido todos os hacks do Fortran a fazerem o mesmo!
Apenas para lembrar aos recém-chegados sobre o que é isso: A premissa básica neste segmento era que gcc / fortran e icc / ifort deveriam, uma vez que possuem os mesmos back-ends, respectivamente, produzir código equivalente para o mesmo programa (semanticamente idêntico), independentemente sendo em C ou Fortran. A qualidade do resultado depende apenas da qualidade das respectivas implementações.
Eu brinquei um pouco com o código e no meu computador (ThinkPad 201x, Intel Core i5 M560, 2,67 GHz), usando
gcc
4.6.1 e os seguintes sinalizadores do compilador:Também fui adiante e escrevi uma versão em linguagem C do código C ++ vetorizada pelo SIMD
spectral_norm_vec.c
:Todas as três versões foram compiladas com os mesmos sinalizadores e os mesmos
gcc
versão. Observe que envolvi a chamada de função principal em um loop de 0 a 9 para obter tempos mais precisos.Portanto, com sinalizadores "melhores" do compilador, a versão C ++ supera a versão Fortran e os loops vetorizados codificados à mão fornecem apenas uma melhoria marginal. Uma rápida olhada no assembler para a versão C ++ mostra que os loops principais também foram vetorizados, embora desenrolados de forma mais agressiva.
Também dei uma olhada no assembler gerado pelo
gfortran
e aqui está a grande surpresa: sem vetorização. Atribuo o fato de que é apenas um pouco mais lento ao problema de a largura de banda ser limitada, pelo menos na minha arquitetura. Para cada uma das multiplicações de matriz, são percorridos 230 MB de dados, o que praticamente inverte todos os níveis de cache. Se você usar um valor de entrada menor, por exemplo100
, as diferenças de desempenho aumentam consideravelmente.Como observação, em vez de ficar obcecado com sinalizações de vetorização, alinhamento e compilador, a otimização mais óbvia seria calcular as primeiras iterações na aritmética de precisão única, até obtermos ~ 8 dígitos do resultado. As instruções de precisão única não são apenas mais rápidas, mas a quantidade de memória que precisa ser movida também é reduzida pela metade.
fonte
gcc
/gfortran
você está usando? Nos threads anteriores, versões diferentes deram resultados significativamente diferentes.matmul2
na versão Fortran é semanticamente equivalente amatmul3
na minha versão C. As duas versões agora são realmente as mesmas e, portanto,gcc
/gfortran
devem produzir os mesmos resultados para ambas, por exemplo, nenhum front-end / idioma é melhor que o outro neste caso.gcc
apenas tem a vantagem de podermos explorar instruções vetorizadas, se quisermos.vector_size
atributo para tornar o código independente da plataforma, ou seja, usando esta sintaxe,gcc
deve ser possível gerar código vetorizado para outras plataformas, por exemplo, usando AltiVec na arquitetura IBM Power.A resposta do user389 foi excluída, mas deixe-me afirmar que estou firmemente no campo dele: não consigo ver o que aprendemos comparando micro-benchmarks em diferentes idiomas. Não me surpreende que C e Fortran obtenham praticamente o mesmo desempenho neste benchmark, dada a sua baixa. Mas o benchmark também é chato, pois pode ser facilmente escrito nos dois idiomas em algumas dezenas de linhas. Do ponto de vista do software, esse não é um caso representativo: devemos nos preocupar com software que tenha 10.000 ou 100.000 linhas de código e como os compiladores fazem isso. Certamente, nessa escala, descobriremos rapidamente outras coisas: o idioma A requer 10.000 linhas, enquanto o idioma B requer 50.000. Ou o contrário, dependendo do que você deseja fazer. E de repente é '
Em outras palavras, não importa muito para mim que talvez meu aplicativo pudesse ser 50% mais rápido se eu o desenvolvesse no Fortran 77. Em vez disso, levará apenas um mês para que ele funcione corretamente, enquanto isso levaria três meses. em F77. O problema com a pergunta aqui é que ela se concentra em um aspecto (núcleos individuais) que não é relevante na prática, na minha opinião.
fonte
Acontece que eu posso escrever um código Python (usando numpy para fazer as operações BLAS) mais rápido que o código Fortran compilado com o compilador gfortran do meu sistema.
foo1.py:
e sn6a.f90, um spectral_norm6.f90 muito levemente modificado:
fonte
Verifiquei isso com os compiladores Intel. Com 11.1 (-fast, implicando -O3) e com 12.0 (-O2), os mais rápidos são 1,2,6,7 e 8 (ou seja, os códigos "mais simples" de Fortran e C e o C vetorizado à mão) - estes são indistinguíveis um do outro a ~ 1.5s. Os testes 3 e 5 (com matriz em função) são mais lentos; # 4 Não pude compilar.
Notavelmente, se compilar com 12.0 e -O3, em vez de -O2, os 2 primeiros códigos (mais simples) do Fortran desaceleram MUITO (1,5 -> 10,2 segundos) - essa não é a primeira vez que vejo algo como isso, mas esse pode ser o exemplo mais dramático. Se esse ainda for o caso no release atual, acho que seria uma boa ideia denunciá-lo à Intel, pois há claramente algo de errado com suas otimizações nesse caso bastante simples.
Caso contrário, concordo com Jonathan que este não é um exercício particularmente informativo :)
fonte