Pergunta

Existem alguns lugares na minha base de código, onde a mesma operação é repetida um número muito grande de vezes para um grande conjunto de dados. Em alguns casos, está demorando um tempo considerável para processá -los.

Acredito que o uso do SSE para implementar esses loops deve melhorar seu desempenho significativamente, especialmente quando muitas operações são realizadas no mesmo conjunto de dados; portanto, uma vez que os dados sejam lidos no cache inicialmente, não deve haver erros de cache para parar isto. No entanto, não tenho certeza de fazer isso.

  • Existe uma maneira independente do compilador e do OS, escrevendo o código para aproveitar as instruções da SSE? Gosto do VC ++ Intrinsics, que inclui operações de SSE, mas não encontrei nenhuma soluções de compilador cruzado.

  • Ainda preciso suportar alguns CPUs que não têm suporte SSE limitado ou limitado (por exemplo, Intel Celeron). Existe alguma maneira de evitar ter que fazer versões diferentes do programa, como ter algum tipo de "Linker de tempo de execução" que vincula o código otimizado BASIC ou SSE com base na CPU executando quando o processo é iniciado?

  • E as outras extensões da CPU, olhando para os conjuntos de instruções de vários shows da Intel e da AMD CPU que existem alguns deles?

Foi útil?

Solução

Para o seu segundo ponto, existem várias soluções, desde que você possa separar as diferenças em diferentes funções:

  • Ponteiros de função C antigos e simples
  • Linking dinâmico (que geralmente depende de ponteiros de função C)
  • Se você estiver usando C ++, ter classes diferentes que representam o suporte para diferentes arquiteturas e o uso de funções virtuais pode ajudar imensamente com isso.

Observe que, como você confia em chamadas de função indireta, as funções que abstraem as diferentes operações geralmente precisam representar funcionalidade de nível um pouco mais alta ou você pode perder os ganhos que obtém da instrução otimizada na sobrecarga de chamada (em outras palavras, não t abstrair as operações SSE individuais - Resumo o trabalho que você está fazendo).

Aqui está um exemplo usando ponteiros de função:

typedef int (*scale_func_ptr)( int scalar, int* pData, int count);


int non_sse_scale( int scalar, int* pData, int count)
{
    // do whatever work needs done, without SSE so it'll work on older CPUs

    return 0;
}

int sse_scale( int scalar, in pData, int count)
{
    // equivalent code, but uses SSE

    return 0;
}


// at initialization

scale_func_ptr scale_func = non_sse_scale;

if (useSSE) {
    scale_func = sse_scale;
}


// now, when you want to do the work:

scale_func( 12, theData_ptr, 512);  // this will call the routine that tailored to SSE 
                                    // if the CPU supports it, otherwise calls the non-SSE
                                    // version of the function

Outras dicas

Boa leitura sobre o assunto: Pare a Guerra do conjunto de instruções

Visão geral curta: Desculpe, não é possível resolver seu problema de maneira simples e mais compatível (Intel vs. AMD).

O SSE intrínseco trabalha com C ++ visual, GCC e o Intel Compiler. Não há problema em usá -los hoje em dia.

Observe que você deve sempre manter uma versão do seu código que não use o SSE e constantemente o verifique na sua implementação SSE.

Isso ajuda não apenas para a depuração, mas também é útil se você deseja oferecer suporte a CPUs ou arquiteturas que não suportam as versões SSE necessárias.

Em resposta ao seu comentário:

De maneira eficaz, desde que eu não tente executar o código que contém instruções não suportadas, estou bem e eu poderia me safar de um interruptor de tipo "See (See2Support) {...} else {...}" do tipo?

Depende. É bom que as instruções SSE existam no binário, desde que não sejam executadas. A CPU não tem nenhum problema com isso.

No entanto, se você ativar o suporte SSE no compilador, ele provavelmente trocará várias instruções "normais" para seus equivalentes SSE (operações escalares de ponto flutuante, por exemplo), portanto, até os pedaços do seu código não-sse regulares soprarão em uma CPU que não a suporta.

Portanto, o que você terá a fazer é provavelmente compilar em ou dois arquivos separadamente, com o SSE ativado, e deixe -os conter todas as suas rotinas SSE. Em seguida, vincule isso com o restante do aplicativo, que é compilado sem suporte SSE.

Em vez de codificar à mão uma implementação alternativa de SSE para o seu código escalar, sugiro fortemente que você dê uma olhada OpenCl. É um sistema portátil em termos de plataforma entre fornecedores para aplicações intensivas computacionalmente (e é altamente compatível com a palavra da moda!). Você pode escrever seu algoritmo em um subconjunto de C99 projetado para operações vetorizadas, o que é muito mais fácil do que o SSE de codificação manual. E o melhor de tudo, o OpenCL gerará a melhor implementação no tempo de execução, para executar na GPU ou Na CPU. Então, basicamente, você coloca o código SSE escrito para você.

Existem alguns lugares na minha base de código, onde a mesma operação é repetida um número muito grande de vezes para um grande conjunto de dados. Em alguns casos, está demorando um tempo considerável para processá -los.

Seu aplicativo soa como o tipo de problema que o OpenCL foi projetado para resolver. Escrever funções alternativas na SSE certamente melhoraria a velocidade de execução, mas é um grande trabalho para escrever e depurar.

Existe uma maneira independente do compilador e do OS, escrevendo o código para aproveitar as instruções da SSE? Gosto do VC ++ Intrinsics, que inclui operações de SSE, mas não encontrei nenhuma soluções de compilador cruzado.

Sim. Os intrínsecos SSE foram essencialmente padronizados pela Intel; portanto, as mesmas funções funcionam da mesma forma entre Windows, Linux e Mac (especificamente com C ++ visual e GNU G ++).

Ainda preciso suportar alguns CPUs que não têm suporte SSE limitado ou limitado (por exemplo, Intel Celeron). Existe alguma maneira de evitar ter que fazer versões diferentes do programa, como ter algum tipo de "Linker de tempo de execução" que vincula o código otimizado BASIC ou SSE com base na CPU executando quando o processo é iniciado?

Você pode fazer isso (por exemplo, usando dlopen()) mas é uma solução muito complexa. Muito mais simples seria (em c) para definir uma interface de função e chamar a versão apropriada da função otimizada via ponteiro da função ou em C ++ para usar diferentes classes de implementação, dependendo da CPU detectada.

Com o OpenCL, não é necessário fazer isso, pois o código é gerado em tempo de execução para a arquitetura fornecida.

E as outras extensões da CPU, olhando para os conjuntos de instruções de vários shows da Intel e da AMD CPU que existem alguns deles?

Dentro do conjunto de instruções SSE, existem muitos sabores. Pode ser bastante difícil codificar o mesmo algoritmo em diferentes subconjuntos de SSE quando certas instruções não estão presentes. Sugiro (pelo menos para começar) que você escolha um nível mínimo suportado, como SSE2, e volta à implementação escalar em máquinas mais antigas.

Esta também é uma situação ideal para testes de unidade/regressão, o que é muito importante para garantir que suas diferentes implementações produzam os mesmos resultados. Tenha um conjunto de testes de dados de entrada e bons dados conhecidos de saída e execute os mesmos dados através das duas versões da função de processamento. Pode ser necessário fazer um teste de precisão para passar (ou seja, a diferença epsilon entre o resultado e a resposta correta está abaixo 1e6, por exemplo). Isso ajudará bastante na depuração e, se você criar um tempo de alta resolução com sua estrutura de teste, poderá comparar as melhorias de desempenho ao mesmo tempo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top