Como calcular o Gflops de um kernel

Eu quero uma medida de quanto do desempenho máximo meu kernel arquiva.

Digamos que eu tenha um NVIDIA Tesla C1060, que tem um pico de GFLOPS de 622,08 (~ = 240Cores * 1300MHz * 2). Agora no meu kernel eu contei para cada thread 16000 flop (4000 x (2 subtração, 1 multiplicação e 1 sqrt)). Então, quando eu tenho 1.000.000 de threads eu criaria 16GFLOP. E como o kernel leva 0,1 segundos eu arquivaria 160GFLOPS, o que seria um quarto do desempenho de pico. Agora minhas perguntas:

  • Esta abordagem é correta?
  • E quanto a comparações ( if(a>b) then.... )? Eu tenho que considerá-los também?
  • Posso usar o criador de perfil CUDA para obter resultados mais fáceis e precisos? Eu tentei o contador de instructions , mas não consegui descobrir o que a figura significa.

Pergunta irmã: Como calcular a largura de banda obtida de um kernel CUDA

Primeiro algumas observações gerais:

Em geral, o que você está fazendo é principalmente um exercício de futilidade e é o reverso de como a maioria das pessoas provavelmente faria uma análise de desempenho.

O primeiro ponto a ser feito é que o valor de pico que você está citando é estritamente para instruções de adição múltipla de ponto flutuante (FMAD), que contam como dois FLOPS, e podem ser retiradas a uma taxa máxima de um por ciclo. Outras operações de ponto flutuante que se aposentam a uma taxa máxima de um por ciclo seriam formalmente classificadas apenas como um único FLOP, enquanto outras poderiam exigir que muitos ciclos fossem retirados. Então, se você decidiu citar o desempenho do kernel em relação ao pico, você está realmente comparando o desempenho do seu código com um stream de instruções puramente FMAD, e nada mais do que isso.

O segundo ponto é que quando os pesquisadores citam valores de FLOP / s a ​​partir de um pedaço de código, eles geralmente estão usando uma contagem de FLOP modelo para a operação, não tentando contar as instruções. A multiplicação de matrizes e os benchmarks de fatoração Linpack LU são exemplos clássicos dessa abordagem de benchmarking de desempenho. O limite inferior da contagem de operações desses cálculos é exatamente conhecido, portanto, a taxa de transferência calculada é simplesmente o limite inferior dividido pelo tempo. A contagem real de instruções é irrelevante. Os programadores costumam usar todos os tipos de técnicas, incluindo cálculos redundantes, cálculos especulativos ou preditivos e uma série de outras idéias para fazer o código rodar mais rápido. A contagem real de FLOP desse código é irrelevante, a referência é sempre a contagem de FLOP do modelo.

Finalmente, quando se olha para quantificar o desempenho, geralmente há apenas dois pontos de comparação de qualquer interesse real

  • A versão A do código é executada mais rapidamente que a versão B no mesmo hardware?
  • O hardware A tem um desempenho melhor do que o hardware B fazendo a tarefa de interesse?

No primeiro caso, você realmente só precisa medir o tempo de execução. No segundo, uma medida adequada geralmente não é FLOP / s, são operações úteis por unidade de tempo (registros por segundo na sorting, células por segundo em uma simulação mecânica de fluidos, etc). Às vezes, como mencionado acima, as operações úteis podem ser a contagem de FLOP do modelo de uma operação de complexidade teórica conhecida. Mas a contagem real de instruções de ponto flutuante raramente, ou nunca, entra na análise.

Se o seu interesse é realmente sobre otimização e compreensão do desempenho do seu código, então talvez esta apresentação de Paulius Micikevicius da NVIDIA possa ser de interesse.

Abordando as questões principais:

Esta abordagem é correta?

Estritamente falando, não. Se você estiver contando operações de ponto flutuante, você precisaria saber a contagem exata de FLOP do código que a GPU está executando. A operação do sqrt pode consumir muito mais do que um único FLOP, dependendo de sua implementação e das características do número em que está operando, por exemplo. O compilador também pode executar muitas otimizações que podem alterar a contagem real de operação / instrução. A única maneira de obter uma contagem verdadeiramente precisa seria desmontar o código compilado e contar os operandos individuais de ponto flutuante, talvez até exigindo suposições sobre as características dos valores que o código irá computar.

E quanto a comparações (se (a> b) então ….)? Eu tenho que considerá-los também?

Eles não são operações de multiplicação-adição de ponto flutuante, então não.

Posso usar o criador de perfil CUDA para obter resultados mais fáceis e precisos? Eu tentei o contador de instruções, mas não consegui descobrir o que a figura significa.

Na verdade não. O profiler não pode diferenciar entre uma intruction de ponto flutuante e qualquer outro tipo de instrução, então (a partir de 2011) a contagem de FLOP de um pedaço de código através do profiler não é possível. [EDIT: veja a resposta do Greg abaixo para uma discussão sobre as facilidades de contagem do FLOP disponíveis nas versões das ferramentas de criação de perfil lançadas desde que esta resposta foi escrita]

O Nsight VSE (> 3.2) e o Visual Profiler (> = 5.5) suportam o cálculo de FLOPs Alcançado. Para coletar a métrica, os profilers executam o kernel duas vezes (usando a reprodução do kernel). Na primeira repetição, o número de instruções de ponto flutuante executadas é coletado (com compreensão da predicação e da máscara ativa). na segunda repetição, a duração é coletada.

O nvprof e o Visual Profiler possuem uma definição codificada. A FMA conta como 2 operações. Todas as outras operações são 1 operação. Os contadores flops_sp_ * são contagens de execução de instrução de thread, enquanto flops_sp é a sum ponderada, portanto, pode ser aplicada uma ponderação usando as métricas individuais. No entanto, o flops_sp_special abrange várias instruções diferentes.

A configuração experimental do Nseight VSE permite ao usuário definir as operações por tipo de instrução.

Nsight Visual Studio Edition

Configurando para coletar FLOPS Realizado

  1. Execute o comando de menu Nsight> Start Performance Analysis … para abrir o Activity Editor
  2. Definir o tipo de atividade para o aplicativo Profile CUDA
  3. Em Configurações de experiência, defina Experimentos para executar como personalizado
  4. Na lista de experiências, adicione FLOPS Realizado
  5. No painel do meio, selecione FLOPS Realizado
  6. No painel direito, você pode personalizar os FLOPS por instrução executados. A ponderação padrão é para FMA e RSQ para contar como 2. Em alguns casos, tenho visto o RSQ tão alto quanto 5.
  7. Execute a session de análise.

Configuração do experimento Nsight VSE Achieved FLOPS

Visualizando FLOPS Realizados

  1. No nvreport abrir o CUDA Lança a página do relatório.
  2. Na página Lançamentos do CUDA , selecione um kernel.
  3. No painel de correlação do relatório (canto inferior esquerdo), selecione FLOPS Realizado

O Nseight VSE obteve resultados de FLOPS

nvprof

Métricas Disponíveis (em um K20)

 nvprof --query-metrics | grep flop flops_sp: Number of single-precision floating-point operations executed by non-predicated threads (add, multiply, multiply-accumulate and special) flops_sp_add: Number of single-precision floating-point add operations executed by non-predicated threads flops_sp_mul: Number of single-precision floating-point multiply operations executed by non-predicated threads flops_sp_fma: Number of single-precision floating-point multiply-accumulate operations executed by non-predicated threads flops_dp: Number of double-precision floating-point operations executed non-predicated threads (add, multiply, multiply-accumulate and special) flops_dp_add: Number of double-precision floating-point add operations executed by non-predicated threads flops_dp_mul: Number of double-precision floating-point multiply operations executed by non-predicated threads flops_dp_fma: Number of double-precision floating-point multiply-accumulate operations executed by non-predicated threads flops_sp_special: Number of single-precision floating-point special operations executed by non-predicated threads flop_sp_efficiency: Ratio of achieved to peak single-precision floating-point operations flop_dp_efficiency: Ratio of achieved to peak double-precision floating-point operations 

Coleta e Resultados

 nvprof --devices 0 --metrics flops_sp --metrics flops_sp_add --metrics flops_sp_mul --metrics flops_sp_fma matrixMul.exe [Matrix Multiply Using CUDA] - Starting... ==2452== NVPROF is profiling process 2452, command: matrixMul.exe GPU Device 0: "Tesla K20c" with compute capability 3.5 MatrixA(320,320), MatrixB(640,320) Computing result using CUDA Kernel... done Performance= 6.18 GFlop/s, Time= 21.196 msec, Size= 131072000 Ops, WorkgroupSize= 1024 threads/block Checking computed result for correctness: OK Note: For peak performance, please refer to the matrixMulCUBLAS example. ==2452== Profiling application: matrixMul.exe ==2452== Profiling result: ==2452== Metric result: Invocations Metric Name Metric Description Min Max Avg Device "Tesla K20c (0)" Kernel: void matrixMulCUDA(float*, float*, float*, int, int) 301 flops_sp FLOPS(Single) 131072000 131072000 131072000 301 flops_sp_add FLOPS(Single Add) 0 0 0 301 flops_sp_mul FLOPS(Single Mul) 0 0 0 301 flops_sp_fma FLOPS(Single FMA) 65536000 65536000 65536000 

NOTA: flops_sp = flops_sp_add + flops_sp_mul + flops_sp_special + (2 * flops_sp_fma) (aproximadamente)

Visual Profiler

O Visual Profiler suporta as métricas mostradas na seção nvprof acima.