Eu implementei o CG no FORTRAN vinculando-o ao Intel MKL.
Quando houver declarações como: ( Consulte Wikipedia )
p=r;
x=x+alpha*p
r=r-alpha*Ap;
ou similares no QMR (em quantidade muito maior)
v_tld = r;
y = v_tld;
rho = norm( y );
w_tld = r;
z = w_tld;
xi = norm( z ); (and more)
Faz sentido usar implementações de nível 1 do BLAS, como DAXPY, DCOPY, DSCAL? A motivação para minha pergunta é:
Eu tenho 2 implementações dos algoritmos. Um em que apenas vinculei Normas e MatVecs ao MKL; copiar, dimensionar e adicionar é feito pelas funções intrínsecas do Fortran e outra onde todas as sub-rotinas possíveis são realizadas pelo BLAS.
Eu pensava que nada pode ficar mais rápido que o BLAS. Mas, acontece que meu código usando as funções intrínsecas do Fortran correu 100% mais rápido que um com as sub-rotinas BLAS Nível 1 (FWIW, este não era um problema pequeno, estava resolvendo um sistema denso de tamanho 13k x 13k que preenchia minhas 4 GB de RAM). Eu estava executando ambos em 2 threads (em uma máquina de 2 núcleos)
ifort QMR.f90 -mkl
comMKL_DYNAMIC=TRUE
Eu fiz uma pergunta no SO referente à extensão do BLAS, mas ao tentar incluir o BLAS Nível 1 no meu código, meu código continuava ficando cada vez mais lento.
Estou fazendo algo errado ou isso é esperado?
Além disso, faz sentido tentar estender o BLAS para executar operações não óbvias como y = 2.89*x
por DCOPY(n,2.89*x,1,y,1) or even DSCAL then DCOPY
?
O que também é interessante é DDOT
e DNRM2
melhorar o desempenho. Atribuí-o ao fato de que, uma vez que realizam multiplicações de precisão dupla, colocá-las em paralelo pode ajudar.
Pergunta complementar: Quando você decide se uma operação BLAS nível 1 realmente ajudará o desempenho?
Adicionando: Atualmente, estou executando um laptop i3 de 2,13 GHz com 4 GB de RAM e informações de Proc Debian de 64 bits aqui . Porém, recebo respostas semelhantes em uma estação de trabalho Intel Xeon 12 core com 24 GB de RAM.
fonte
Respostas:
Se seu objetivo é realmente extrair o máximo de desempenho possível, é importante lembrar:
Uma biblioteca BLAS ajustada pelo fornecedor certamente deve ser sua abordagem padrão, mas se você tiver passado algum tempo nos kernels individuais e notado que alguma outra implementação é mais rápida, use todos os meios de qualquer outra maneira. Perder o uso de intrínsecas vetoriais pode levar à grande diferença de desempenho.
É possível que sua melhor aposta em rotinas simples como daxpy e dscal seja um loop escrito à mão que explora intrínsecas vetoriais.
fonte
Dado o estado da otimização compiladores hoje em dia, eu não acho que há muito vodu nos BLAS rotinas lineares, por exemplo
DAXPY
,DCOPY
eDSCAL
, que o seu compilador não já fazem, por exemplo, SSE-vetorização e desenrolando loop.Se o código for o mesmo, a única diferença entre sua rotina e uma chamada para o BLAS do MKL é a sobrecarga da chamada de função e qualquer mágica extra que o MKL possa estar tentando fazer lá. Se for esse o caso, a diferença entre o seu código e o código do MKL deve ser constante, independente do tamanho do problema / vetor.
Esta questão tem ecos interessantes de esta questão , que também usa
DAXPY
como exemplo.fonte
O padrão BLAS, na verdade, possui várias verificações para verificar se os argumentos da função são desnecessários em muitas situações. Veja esta implementação de referência de
daxpy.f
. Além disso, constantes comoINCX
você geralmente são conhecidas em tempo de compilação, mas podem não ser assumidas pela implementação. O BLAS chama unidades de compilação cruzada, e eu não conheço nenhum compilador que possa otimizar isso sem ativar a otimização de todo o programa.gemm
, com a otimização suficiente ativada.fonte
As funções BLAS1 representam um conjunto de kernels com largura de banda limitada porque sua intensidade de computação é baixa. Em particular, esses kernels fazem O (1) falhanços por acesso à memória. Isso significa que, no hardware moderno, eles rodam em uma pequena fração do pico e não há basicamente nada que você possa fazer. A melhor implementação do BLAS1 verificará o alinhamento e o módulo do comprimento do vetor FPU e o desempenho no pico da largura de banda, que provavelmente será de 5 a 10% do pico de computação.
Quando você escreve essas operações explicitamente na fonte, um bom compilador as reconhece imediatamente e destaca alguma implementação ideal equivalente à BLAS1 mencionada acima. No entanto, como o compilador sabe mais sobre o contexto, ele pode evitar certas ramificações (não muito importantes) e sobrecarga de chamada de função, além de potencialmente realizar transformações de ordem superior no código que seria bloqueado por uma chamada de função para uma biblioteca opaca.
Há uma variedade de experimentos que você pode realizar para determinar o que realmente está afetando o desempenho do seu código. Eles são bastante óbvios, então não os listarei aqui.
fonte