AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 78827628
Accepted
Iceberglet
Iceberglet
Asked: 2024-08-03 08:59:39 +0800 CST2024-08-03 08:59:39 +0800 CST 2024-08-03 08:59:39 +0800 CST

Perguntas sobre o desempenho do CUDA para tarefas simples não compartilhadas

  • 772

Sou um novato em aceleração de GPU. Apenas tentei uma ligação LWJGL básica em CUDA com um kernel simples, sem memória compartilhada, a assinatura da função é a seguinte

__global__ void compute(
unsigned int n,
unsigned long long int* timeMs,
double* a, double* b, double* c, 
double *g_odata)

a função do kernel é basicamente recuperar dados para o id do thread dos arrays acima (timeMs, a, b, c etc.) e fazer algumas contas e colocar o resultado no array g_odata no id do thread apropriado. n sendo o número de threads a serem computados (ele verifica se o ID do thread ultrapassa n, é claro). Não há memória compartilhada ou redução.

Agora aqui está o caso curioso sobre n (tamanho total do thread/paralelismo) e tamanho do bloco quando meço o tempo TOTAL necessário para o kernel ser concluído (tenho uma GPU com 80 multiprocessadores)

Platô estranho

Por meio disso clock64(), adicionei carimbo de data / hora na função do kernel antes e depois e coletei o tempo total de cada thread, e é aparente que quanto mais threads houver, mais lentos eles demoram para a MESMA tarefa

Agora perguntas:

  1. Por que o tempo total diminui após cerca de 100 threads? Dados 80 multiprocessadores e mais de 10 mil núcleos cuda, esperaria que esse número fosse maior, então talvez algum problema de configuração?
  2. Por que a função do kernel está demorando mais para mais threads? a execução é entrelaçada (ou seja, o escalonador pode pausar um deles antes de concluir e executar outro)
  3. Por que há um comportamento de platô após um aumento de 100 threads? e por que ele decola novamente
  4. O desempenho variável com base no número do bloco. Eu li que grade/bloco é apenas a perspectiva do desenvolvedor e não tem influência (especialmente para meus threads totalmente segregados sem compartilhamento/redução). Então, por que isso é importante e como escolher o melhor tamanho de bloco?
cuda
  • 1 1 respostas
  • 38 Views

1 respostas

  • Voted
  1. Best Answer
    Homer512
    2024-08-03T17:02:24+08:002024-08-03T17:02:24+08:00

    Você não mostra o código relevante nem nos fornece o tipo de GPU. Isso torna difícil responder a detalhes. Comecemos pelo princípio: se esta for uma GPU de nível de consumidor, você não usa seus "núcleos cuda", pois eles são apenas para precisão única ( float). Apenas verificando as especificações de uma GPU aleatória: pelo excelente banco de dados de GPU da TechPowerUp , o RTX-4090 tem 82,58 TFLOPS de precisão simples e apenas 1,29 TFLOPS de precisão dupla.

    Por que a função do kernel está demorando mais para mais threads? a execução é entrelaçada (ou seja, o escalonador pode pausar um deles antes de concluir e executar outro)

    Sim, é assim que uma GPU funciona. Se você olhar a tabela Compute Capabilities no CUDA Programming Guide, verá que normalmente um SM (multiprocessador de streaming) tem 1024-2048 threads, mas quando você compara com a tabela de instruções aritméticas , apenas uma taxa de transferência de cerca de 128 instruções de precisão única por ciclo de clock. Ocultar a latência comprometendo demais os recursos da GPU é como funciona.

    Por que há um comportamento de platô após um aumento de 100 threads? e por que ele decola novamente

    Uma escala logarítmica é difícil de interpretar, mas parece que pode haver um aumento de 256 threads (?). Pode ser quando o escalonador não consegue encontrar uma unidade de execução de dupla precisão livre a cada ciclo de clock. O criador de perfil visual Nsight Compute deve ser capaz de informar você.

    Observe que um único bloco sempre é executado em um único SM. Portanto, 256 threads com tamanho de bloco de 1.024 significa que todos os threads são executados no mesmo processador, deixando os recursos de computação nos outros processadores desocupados.

    No geral, acho que essa métrica não tem sentido de qualquer maneira. 100-1000 threads é muito pouco e você precisa observar o rendimento de todos os threads, ou seja, o número de itens de trabalho dividido pelo tempo total de execução do kernel.

    O desempenho variável com base no número do bloco. Eu li que grade/bloco é apenas a perspectiva do desenvolvedor e não tem influência (especialmente para meus threads totalmente segregados sem compartilhamento/redução). Então, por que isso é importante e como escolher o melhor tamanho de bloco?

    Isto é errado. O tamanho do bloco é importante. Novamente, se você observar os recursos de computação, há limites para o número de blocos por SM, bem como para threads por SM. Se o tamanho do seu bloco for inferior a 64, você não alcançará 100% de ocupação. Um tamanho de bloco que não seja múltiplo do tamanho do warp também desperdiçará recursos com threads desativados. E é claro que um tamanho de bloco de 1.024 nunca atingirá mais de 2/3 da ocupação em dispositivos CUDA 8.6-8.9 com 1.536 threads por SM.

    Os blocos também têm sobrecarga de lançamento, portanto, menos blocos podem ser benéficos, mas torná-los muito grandes também pode ter efeitos negativos. Um novo bloco só pode começar quando todos os threads de um bloco antigo terminarem. Blocos grandes significam que no final do kernel (ou nas __syncthreads()barreiras), muitos threads podem esperar por poucos retardatários, ocupando recursos por mais tempo do que o necessário.

    Regra geral, use cerca de 128-256 threads por bloco. Compare tamanhos diferentes, se necessário. Mas você precisa torná-lo uma referência significativa. Observe o rendimento geral e ocupe totalmente a GPU.

    • 2

relate perguntas

  • Separar `cudaMalloc` e `cudaMemcpy` em funções diferentes?

  • Como os streams e a contagem do asyncEngine funcionam juntos no CUDA

  • Por que eles estão preenchendo apenas uma memória compartilhada?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle?

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Quando devo usar um std::inplace_vector em vez de um std::vector?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Martin Hope
    Aleksandr Dubinsky Por que a correspondência de padrões com o switch no InetAddress falha com 'não cobre todos os valores de entrada possíveis'? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer Quando devo usar um std::inplace_vector em vez de um std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB Por que o GCC gera código que executa condicionalmente uma implementação SIMD? 2024-02-17 06:17:14 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve