Extensão SIMD para C ++ OpenMP no Visual Studio

Na era das aplicações onipresentes de IA, existe uma demanda emergente do compilador que acelera o código de aprendizado de máquina intensivo em computação para o hardware existente. Esse código geralmente faz cálculos matemáticos como transformação e manipulação de matrizes e geralmente é na forma de loops. A extensão SIMD do OpenMP fornece aos usuários uma maneira fácil de acelerar os loops, explicitamente aproveitando a unidade vetorial dos processadores modernos. Estamos orgulhosos de começar a oferecer a vetorização C / C ++ OpenMP SIMD no Visual Studio 2019.


A interface do programa de aplicativos OpenMP C / C ++ foi originalmente projetada para melhorar o desempenho do aplicativo, permitindo que o código seja efetivamente executado em paralelo em vários processadores nos anos 90. Ao longo dos anos, o padrão OpenMP foi expandido para suportar conceitos adicionais, como paralelização baseada em tarefas, vetorização SIMD e descarregamento de processador. Desde 2005, o Visual Studio suporta o padrão OpenMP 2.0, que se concentra na paralelização multithread. À medida que o mundo está entrando na era da IA, vemos uma oportunidade crescente de melhorar a qualidade do código, expandindo o suporte ao padrão OpenMP no Visual Studio. Continuamos nossa jornada no Visual Studio 2019 adicionando suporte ao OpenMP SIMD.




O OpenMP SIMD, introduzido pela primeira vez no padrão OpenMP 4.0, visa principalmente a vetorização de loop. Até agora, é o recurso OpenMP mais utilizado no aprendizado de máquina, de acordo com nossa pesquisa. Anotando um loop com uma diretiva OpenMP SIMD, o compilador pode ignorar dependências de vetores e vetorizar o loop o máximo possível. O compilador respeita a intenção dos usuários de executar várias iterações de loop simultaneamente.


#pragma omp simd for (i = 0; i < count; i++) { a[i] = b[i] + 1; } 

Como você deve saber, o C ++ no Visual Studio já fornece pragmas de loop não OpenMP semelhantes, como #pragma vector e #pragma ivdep . No entanto, o compilador pode fazer mais com o OpenMP SIMD. Por exemplo:


  1. O compilador sempre tem permissão para ignorar quaisquer dependências de vetores presentes.
  2. / fp: fast é ativado dentro do loop.
  3. Os loops com chamadas de função são vetorizáveis.
  4. Os loops externos são vetorizáveis.
  5. Loops aninhados podem ser coalescidos em um loop e vetorizados.
  6. A aceleração híbrida é possível com #pragma omp for simd para permitir multithreading de granulação grossa e vetorização de granulação fina.

Além disso, a diretiva OpenMP SIMD pode usar as seguintes cláusulas para aprimorar ainda mais a vetorização:


  • simdlen ( length ): especifique o número de faixas de vetores
  • safelen ( length ): especifique a distância de dependência do vetor
  • linear ( list [ : linear-step] ): o mapeamento linear da variável de indução de loop para a assinatura da matriz
  • alinhado ( lista [ : alinhamento] ): o alinhamento dos dados
  • privado ( lista ): especifique a privatização de dados
  • lastprivate ( list ): especifique a privatização de dados com o valor final da última iteração
  • redução ( identificador de redução : lista ): especifique operações de redução personalizadas
  • colapso ( n ): ninho de laços coalescentes

-Openmp: switch experimental novo


Um programa anotado no OpenMP-SIMD pode ser compilado com um novo comutador CL -openmp: experimental. Essa nova opção permite que os recursos adicionais do OpenMP não estejam disponíveis em -openmp . Embora o nome desse switch seja “experimental”, o próprio switch e a funcionalidade que ele habilita são totalmente suportados e prontos para produção. O nome reflete que ele não habilita nenhum subconjunto ou versão completa de um padrão OpenMP. As iterações futuras do compilador podem usar essa opção para habilitar recursos adicionais do OpenMP e novos switches relacionados ao OpenMP podem ser adicionados. A opção -openmp: experimental substitui a opção -openmp, o que significa que é compatível com todos os recursos do OpenMP 2.0. Observe que a diretiva SIMD e suas cláusulas não podem ser compiladas com a opção -openmp .


Para loops que não são vetorizados, o compilador emitirá uma mensagem para cada um deles, como abaixo. Por exemplo,


cl -O2 -openmp: experimental mycode.cpp


mycode.cpp (84): info C5002: Omp simd loop não vetorizado devido ao motivo '1200'


mycode.cpp (90): info C5002: Omp simd loop não vetorizado devido ao motivo '1200'


Para loops vetorizados, o compilador permanece silencioso, a menos que seja fornecida uma opção de log de vetorização:


cl -O2 -openmp: experimental -Qvec-report: 2 mycode.cpp


mycode.cpp (84): info C5002: Omp simd loop não vetorizado devido ao motivo '1200'


mycode.cpp (90): info C5002: Omp simd loop não vetorizado devido ao motivo '1200'


mycode.cpp (96): info C5001: Omp simd loop vetorizado


Como primeira etapa do suporte ao OpenMP SIMD, basicamente conectamos o pragma do SIMD com o vetorizador de back-end sob o novo switch. Nosso foco foi na vetorização de loops mais internos, melhorando a análise do vetorizador e do alias. Nenhuma das cláusulas SIMD é eficaz no Visual Studio 2019 no momento da redação deste documento. Eles serão analisados, mas ignorados pelo compilador com um aviso emitido para conscientização do usuário. Por exemplo, o compilador emitirá


aviso C4849: Cláusula OpenMP 'simdlen' ignorada na diretiva 'simd'


para o seguinte código:


 #pragma omp simd simdlen(8) for (i = 1; i < count; i++) { a[i] = a[i-1] + 1; b[i] = *c + 1; bar(i); } 

Mais sobre a semântica da diretiva OpenMP SIMD


A diretiva OpenMP SIMD fornece aos usuários uma maneira de ditar o compilador para vetorizar um loop. É permitido ao compilador ignorar a aparente legalidade dessa vetorização, aceitando a promessa de correção dos usuários. É de responsabilidade do usuário quando um comportamento inesperado acontece com a vetorização. Ao anotar um loop com a diretiva OpenMP SIMD, os usuários pretendem executar várias iterações de loop simultaneamente. Isso dá ao compilador muita liberdade para gerar código de máquina que aproveita os recursos SIMD ou vetoriais no processador de destino. Embora o compilador não seja responsável por explorar a correção e o lucro desse paralelismo especificado pelo usuário, ele ainda deve garantir o comportamento seqüencial de uma iteração de loop único.


Por exemplo, o seguinte loop é anotado com a diretiva OpenMP SIMD. Não existe um paralelismo perfeito entre iterações de loop, pois existe uma dependência reversa de a [i] a [i-1]. Mas, devido à diretiva SIMD, o compilador ainda pode compactar iterações consecutivas da primeira instrução em uma instrução vetorial e executá-las em paralelo.


 #pragma omp simd for (i = 1; i < count; i++) { a[i] = a[i-1] + 1; b[i] = *c + 1; bar(i); } 

Portanto, a seguinte forma vetorial transformada do loop é legal porque o compilador mantém o comportamento seqüencial de cada iteração original do loop. Em outras palavras, a [i] é executado após a [-1], b [i] é após a [i] e a chamada para a barra acontece finalmente.


 #pragma omp simd for (i = 1; i < count; i+=4) { a[i:i+3] = a[i-1:i+2] + 1; b[i:i+3] = *c + 1; bar(i); bar(i+1); bar(i+2); bar(i+3); } 

É ilegal mover a referência de memória * c para fora do loop, se houver um apelido com a [i] ou b [i] . Também é ilegal reordenar as instruções dentro de uma iteração original, se isso interromper a dependência seqüencial. Como exemplo, o seguinte loop transformado não é legal.


 c = b; t = *c; #pragma omp simd for (i = 1; i < count; i+=4) { a[i:i+3] = a[i-1:i+2] + 1; bar(i); // illegal to reorder if bar[i] depends on b[i] b[i:i+3] = t + 1; // illegal to move *c out of the loop bar(i+1); bar(i+2); bar(i+3); } 

Planos futuros e feedback


Recomendamos que você experimente esse novo recurso. Como sempre, agradecemos seus comentários. Se você vir um loop SIM do OpenMP que espera ser vetorizado, mas não o é ou o código gerado não é o ideal, informe-nos. Podemos ser contatados através dos comentários abaixo, via e-mail ( visualcpp@microsoft.com ), twitter (@visualc) ou via Comunidade de desenvolvedores .


No futuro, gostaríamos de ouvir sua necessidade de funcionalidades do OpenMP ausentes no Visual Studio. Como houve várias evoluções importantes no OpenMP desde o padrão 2.0, o OpenMP agora possui recursos tremendos para facilitar seu esforço para criar programas de alto desempenho. Por exemplo, a programação de simultaneidade baseada em tarefas está disponível a partir do OpenMP 3.0. A computação heterogênea (CPU + aceleradores) é suportada no OpenMP 4.0. A vetorização SIMD avançada e o suporte à paralelização de loop DOACROSS também estão disponíveis no mais recente padrão OpenMP agora. Consulte as revisões padrão completas e os conjuntos de recursos no site oficial do OpenMP: https://www.openmp.org . Sinceramente, pedimos a sua opinião sobre os recursos específicos do OpenMP que você gostaria de ver. Também estamos interessados ​​em saber como você está usando o OpenMP para acelerar seu código. Seus comentários são críticos para ajudar a direcionar o suporte ao OpenMP no Visual Studio.


Avatar
Hongtao Yu

Source: https://habr.com/ru/post/pt446688/


All Articles