O DAXPY, DCOPY, DSCAL é um exagero?

8

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 é:

  1. 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.

  2. 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 -mklcomMKL_DYNAMIC=TRUE

  3. 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*xpor DCOPY(n,2.89*x,1,y,1) or even DSCAL then DCOPY?


O que também é interessante é DDOTe DNRM2melhorar 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.

Inquérito
fonte
Em que hardware você está executando?
Pedro
2
Não assuma que não há nada mais rápido que BLAS / LAPACK. Eles são otimizados para utilidade, não necessariamente para ganhar medalhas de ouro. Quando a velocidade é sua necessidade, você pode tentar isso .
precisa saber é o seguinte
DCOPY (n, 2,89 * x, 1, y, 1) não fará o que você deseja. Está errado. A função que você deseja é DAXPY.
Jeff Jeff
MKL_DYNAMIC = TRUE é péssimo para o desempenho. Não conheço nenhum código científico que se beneficie disso. Desligue-o e defina o número da linha via MKL_NUM_THREADS / OMP_NUM_THREADS e ative OMP_SCHEDULE = STATIC.
Jeff

Respostas:

6

Se seu objetivo é realmente extrair o máximo de desempenho possível, é importante lembrar:

  1. A biblioteca (BLAS) pode não ter sido ajustada para o seu sistema / configuração exato.
  2. Os desenvolvedores de bibliotecas cometem erros.

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.

Jack Poulson
fonte
Embora eu não possa refutar logicamente (2), não acredito que seja pertinente aqui. DCOPY, DSCAL e DAXPY são quase triviais para implementar corretamente, portanto, duvido que as pessoas cometam erros. A questão é que sua trivialidade deriva do fato de que essas funções atingem o limite de hardware muito rapidamente e, portanto, poucas otimizações são eficazes.
Jeff Jeff
3

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, DCOPYe DSCAL, 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 DAXPYcomo exemplo.

Pedro
fonte
2

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 como INCXvocê 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.

  • Um aspecto engraçado disso é que o Intel Compiler agora reconhece loops multiplicadores de matriz e matriz BLAS 3 e transformará esse código na chamada x equivalente gemm, com a otimização suficiente ativada.
Aron Ahmadia
fonte
Você executou o experimento em que elimina os condicionais no DAXPY para verificar se isso tem algum impacto no desempenho? Eu duvido seriamente que sim.
Jeff Jeff
Não, mas eu tenho escrito código de montagem pura e superou fornecido pelo fabricante DAXPY em BLAS em algumas plataformas :)
Aron Ahmadia
1

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.

Jeff
fonte