
Um desempenho suave é essencial para criar experiências de jogo imersivas para os jogadores. Para garantir que seu jogo esteja otimizado, um fluxo de trabalho de perfil consistente e de ponta a ponta é um "item indispensável" para um desenvolvimento de jogos eficiente, e começa com um simples procedimento de três pontos:
Esta página descreve um fluxo de trabalho geral de perfil para desenvolvedores de jogos. É extraído do e-book, Guia definitivo para perfilagem de jogos Unity, disponível para download gratuito (a versão Unity 6 do guia estará disponível em breve). O e-book foi criado por especialistas em desenvolvimento de jogos, perfilagem e otimização, tanto externos quanto internos da Unity.
Neste artigo, você pode aprender sobre metas úteis a serem definidas com a perfilagem, gargalos de desempenho comuns, como estar vinculado à CPU ou à GPU, e como identificar e investigar essas situações em mais detalhes.
Os jogadores costumam medir o desempenho usando a taxa de quadros, ou quadros por segundo (fps), mas como desenvolvedor, geralmente é recomendado usar tempo de quadro em milissegundos em vez disso. Considere o seguinte cenário simplificado:
Durante a execução, seu jogo renderiza 59 quadros em 0,75 segundos. No entanto, o próximo quadro leva 0,25 segundos para ser renderizado. A taxa média de quadros entregue de 60 fps parece boa, mas na realidade os jogadores notarão um efeito de gagueira, já que o último quadro leva um quarto de segundo para ser renderizado.
Esta é uma das razões pelas quais é importante ter como objetivo um orçamento de tempo específico por quadro. Isso fornece a você uma meta sólida para trabalhar ao perfilar e otimizar seu jogo e, em última análise, cria uma experiência mais suave e consistente para seus jogadores.
Cada quadro terá um orçamento de tempo baseado em seu fps alvo. Um aplicativo com alvo de 30 fps deve sempre levar menos de 33,33 ms por quadro (1000 ms / 30 fps). Da mesma forma, um alvo de 60 fps deixa 16,66 ms por quadro (1000 ms / 60 fps).
Você pode exceder esse orçamento durante sequências não interativas, por exemplo, ao exibir menus de UI ou carregamento de cena, mas não durante o jogo. Mesmo um único quadro que excede o orçamento de quadro alvo causará travamentos.
Observação: Uma taxa de quadros consistentemente alta em jogos de VR é essencial para evitar causar náusea ou desconforto aos jogadores e é frequentemente necessária para que seu jogo obtenha certificação do detentor da plataforma.
Quadros por segundo: Uma métrica enganosa
Uma maneira comum que os jogadores medem o desempenho é com a taxa de quadros, ou quadros por segundo. No entanto, é recomendado que você use o tempo de quadro em milissegundos em vez disso. Para entender por que, olhe para o gráfico acima de fps versus tempo de quadro.
Considere esses números:
1000 ms/sec / 900 fps = 1,111 ms por quadro
1000 ms/sec / 450 fps = 2.222 ms por quadro
1000 ms/sec / 60 fps = 16.666 ms por quadro
1000 ms/sec / 56.25 fps = 17.777 ms por quadro
Se sua aplicação estiver rodando a 900 fps, isso se traduz em um tempo de quadro de 1.111 milissegundos por quadro. A 450 fps, isso é 2.222 milissegundos por quadro. Isso representa uma diferença de apenas 1.111 milissegundos por quadro, mesmo que a taxa de quadros pareça cair pela metade.
Se você olhar as diferenças entre 60 fps e 56.25 fps, isso se traduz em 16.666 milissegundos por quadro e 17.777 milissegundos por quadro, respectivamente. Isso também representa 1.111 milissegundos extras por quadro, mas aqui, a queda na taxa de quadros parece muito menos dramática em termos percentuais.
É por isso que os desenvolvedores usam o tempo médio de quadro para medir a velocidade do jogo em vez de fps.
Não se preocupe com fps a menos que você caia abaixo da sua taxa de quadros alvo. Concentre-se no tempo de quadro para medir quão rápido seu jogo está rodando, então mantenha-se dentro do seu orçamento de quadros.
Leia o artigo original, “Robert Dunlop’s fps versus frame time,” para mais informações.

O controle térmico é uma das áreas mais importantes a otimizar ao desenvolver aplicações para dispositivos móveis. Se a CPU ou GPU gastarem muito tempo trabalhando em plena carga devido a código ineficiente, esses chips ficarão quentes. Para evitar superaquecimento e danos potenciais aos chips, o sistema operacional reduzirá a velocidade do clock do dispositivo para permitir que ele esfrie, causando gagueira nos quadros e uma experiência de usuário ruim. Essa redução de desempenho é conhecida como estrangulamento térmico.
Taxas de quadros mais altas e aumento na execução de código (ou operações de acesso a DRAM) levam a um aumento no consumo de bateria e geração de calor. Um desempenho ruim também pode tornar seu jogo injogável para segmentos inteiros de dispositivos móveis de baixo desempenho, o que pode levar a oportunidades de mercado perdidas.
Ao lidar com o problema térmico, considere o orçamento que você tem para trabalhar como um orçamento de sistema.
Combata o estrangulamento térmico e o consumo de bateria perfilando cedo para otimizar seu jogo desde o início. Ajuste as configurações do seu projeto para o hardware da plataforma alvo para combater problemas de estrangulamento térmico e consumo de bateria.
Ajuste os orçamentos de quadros em dispositivos móveis
Uma dica geral para combater problemas térmicos do dispositivo durante longos períodos de jogo é deixar um tempo ocioso de quadro de cerca de 35%. Isso dá tempo para os chips móveis esfriarem e ajuda a evitar um consumo excessivo de bateria. Usando um tempo de quadro alvo de 33,33 ms por quadro (para 30 fps), o orçamento de quadros para dispositivos móveis será de aproximadamente 22 ms por quadro.
O cálculo é assim: (1000 ms / 30) * 0.65 = 21.66 ms
Para alcançar 60 fps em dispositivos móveis usando o mesmo cálculo, seria necessário um tempo de quadro alvo de (1000 ms / 60) * 0.65 = 10.83 ms. Isso é difícil de alcançar em muitos dispositivos móveis e drenaria a bateria duas vezes mais rápido do que visando 30 fps. Por essas razões, muitos jogos móveis visam 30 fps em vez de 60. Use Application.targetFrameRate para controlar essa configuração e consulte a seção "Defina um orçamento de quadro" no e-book de perfilamento para mais detalhes sobre o tempo de quadro.
A escalabilidade de frequência em chips móveis pode dificultar a identificação das alocações do seu orçamento de tempo ocioso de quadro ao perfilá-los. Suas melhorias e otimizações podem ter um efeito positivo líquido, mas o dispositivo móvel pode estar reduzindo a frequência e, como resultado, funcionando mais frio. Use ferramentas personalizadas como FTrace ou Perfetto para monitorar as frequências dos chips móveis, o tempo ocioso e a escalabilidade antes e depois das otimizações.
Desde que você permaneça dentro do seu orçamento total de tempo de quadro para seu fps alvo (digamos 33,33 ms para 30 fps) e veja seu dispositivo trabalhando menos ou registrando temperaturas mais baixas para manter essa taxa de quadros, então você está no caminho certo.
Outra razão para adicionar espaço ao orçamento de quadros em dispositivos móveis é levar em conta as flutuações de temperatura do mundo real. Em um dia quente, um dispositivo móvel aquecerá e terá dificuldade em dissipar calor, o que pode levar ao estrangulamento térmico e ao desempenho ruim do jogo. Reserve uma porcentagem do orçamento de quadros para ajudar a evitar esse cenário.

O acesso à DRAM é tipicamente uma operação que consome muita energia em dispositivos móveis. O conselho de otimização da Arm para conteúdo gráfico em dispositivos móveis diz que o custo de acesso à memória LPDDR4 é de aproximadamente 100 picojoules por byte.
Reduza o número de operações de acesso à memória por quadro da seguinte forma:
Quando você precisar se concentrar em dispositivos que utilizam hardware de CPU ou GPU da Arm, as ferramentas Arm Performance Studio (especificamente, Streamline Performance Analyzer) incluem ótimos contadores de desempenho para identificar problemas de largura de banda de memória. Os contadores disponíveis estão listados e explicados para cada geração de GPU da Arm em um guia do usuário correspondente, por exemplo, Mali-G710 Performance Counter Reference Guide . Observe que a profilagem de GPU do Arm Performance Studio requer uma GPU Arm Immortalis ou Mali.
Estabeleça níveis de hardware para benchmarking
Além de usar ferramentas de perfilagem específicas da plataforma, estabeleça níveis ou um dispositivo de especificação mais baixa para cada plataforma e nível de qualidade que você deseja suportar, em seguida, perfil e otimize o desempenho para cada uma dessas especificações.
Como exemplo, se você está direcionando plataformas móveis, pode decidir suportar três níveis com controles de qualidade que ativam ou desativam recursos com base no hardware alvo. Você então otimiza para a especificação do dispositivo mais baixa em cada nível. Como outro exemplo, se você está desenvolvendo um jogo para consoles, certifique-se de fazer a profilagem em versões mais antigas e mais novas.
Nosso último guia de otimização para dispositivos móveis tem muitas dicas e truques que ajudarão você a reduzir o estrangulamento térmico e aumentar a vida útil da bateria para dispositivos móveis que executam seus jogos.

Ao fazer a profilagem, você quer garantir que está focando seu tempo e esforço em áreas onde pode criar o maior impacto. Assim, é recomendado começar com uma abordagem de cima para baixo ao fazer a profilagem, o que significa que você começa com uma visão geral de alto nível de categorias como renderização, scripts, física e alocações de coleta de lixo (GC). Uma vez que você tenha identificado áreas de preocupação, pode aprofundar-se nos detalhes mais profundos. Use esta passagem de alto nível para coletar dados e fazer anotações sobre os problemas de desempenho mais críticos, incluindo cenários que causam alocações gerenciadas indesejadas ou uso excessivo da CPU em seu loop de jogo principal.
Você precisará primeiro reunir pilhas de chamadas para marcadores GC.Alloc. Se você não estiver familiarizado com esse processo, encontre algumas dicas e truques na seção intitulada "Localizando alocações de memória recorrentes ao longo da vida útil da aplicação" no e-book.
Se as pilhas de chamadas relatadas não forem detalhadas o suficiente para rastrear a origem das alocações ou outras lentidões, você pode realizar uma segunda sessão de perfilagem com a Profilagem Profunda ativada para encontrar a origem das alocações. Abordamos a profilagem profunda com mais detalhes no e-book, mas em resumo, é um modo no Profiler que captura dados de desempenho detalhados para cada chamada de função, fornecendo insights granulares sobre tempos de execução e comportamentos, mas com uma sobrecarga significativamente maior em comparação com a profilagem padrão.
Ao coletar notas sobre os "infratores" do tempo de quadro, certifique-se de observar como eles se comparam em relação ao restante do quadro. Esse impacto relativo pode ser distorcido quando a profilagem profunda está ativada, porque a profilagem profunda adiciona uma sobrecarga significativa ao instrumentar cada chamada de método.
Perfilar cedo
Embora você deva sempre perfilar ao longo de todo o ciclo de desenvolvimento do seu projeto, os ganhos mais significativos da profilagem são obtidos quando você começa nas fases iniciais.
Perfilar cedo e frequentemente para que você e sua equipe entendam e memorizem uma "assinatura de desempenho" para o projeto que podem usar como referência. Se o desempenho despencar, você poderá facilmente identificar quando as coisas dão errado e corrigir o problema.
Embora a profilagem no Editor ofereça uma maneira fácil de identificar os principais problemas, os resultados de profilagem mais precisos sempre vêm de executar e perfilar builds em dispositivos-alvo, juntamente com o uso de ferramentas específicas da plataforma para investigar as características de hardware de cada plataforma. Essa combinação fornecerá uma visão holística do desempenho da aplicação em todos os seus dispositivos-alvo. Por exemplo, você pode estar limitado pela GPU em alguns dispositivos móveis, mas limitado pela CPU em outros, e você só pode aprender isso medindo nesses dispositivos.
Baixe a versão PDF imprimível deste gráfico aqui.
O objetivo da profilagem é identificar gargalos como alvos para otimização. Se você confiar em suposições, pode acabar otimizando partes do jogo que não são gargalos, resultando em pouca ou nenhuma melhoria no desempenho geral. Algumas "otimizações" podem até piorar o desempenho geral do seu jogo, enquanto outras podem ser trabalhosas, mas resultar em resultados insignificantes. A chave é otimizar o impacto do seu investimento de tempo focado.
O fluxograma acima ilustra o processo inicial de profilagem, com as seções seguintes fornecendo informações detalhadas sobre cada etapa. Eles também apresentam capturas do Profiler de projetos reais do Unity para ilustrar os tipos de coisas a serem observadas.
Para obter uma visão holística de toda a atividade da CPU, incluindo quando ela está aguardando a GPU, use a visualização da linha do tempo no módulo da CPU do Profiler. Familiarize-se com os marcadores comuns do Profiler para interpretar as capturas corretamente. Alguns dos marcadores do Profiler podem aparecer de forma diferente dependendo da sua plataforma alvo, então passe um tempo explorando as capturas do seu jogo em cada uma das suas plataformas alvo para ter uma noção de como é uma captura "normal" para o seu projeto.
O desempenho de um projeto é limitado pelo chip e/ou thread que leva mais tempo. Essa é a área onde os esforços de otimização devem se concentrar. Por exemplo, imagine os seguintes cenários para um jogo com um orçamento de tempo de quadro alvo de 33,33 ms e VSync habilitado:
Veja esses recursos que exploram mais sobre estar limitado pela CPU ou GPU:

Perfilando e otimizando seu projeto cedo e frequentemente durante o desenvolvimento ajudará você a garantir que todas as threads da CPU da sua aplicação e o tempo de quadro geral da GPU estejam dentro do orçamento de quadros. A pergunta que guiará esse processo é: você está dentro do orçamento de quadros ou não?
Acima está uma imagem de uma captura de perfil de um jogo móvel Unity desenvolvido por uma equipe que fez perfilamento e otimização contínuos. O jogo tem como alvo 60 fps em telefones móveis de alta especificação e 30 fps em telefones de especificação média/baixa, como o que está nesta captura.
Note como quase metade do tempo no quadro selecionado é ocupada pelo marcador de Profiler amarelo WaitForTargetFPS. O aplicativo definiu Application.targetFrameRate para 30 fps, e VSync está habilitado. O trabalho de processamento real na thread principal termina em torno da marca de 19 ms, e o restante do tempo é gasto esperando que o restante dos 33,33 ms passe antes de começar o próximo quadro. Embora esse tempo seja representado por um marcador de Profiler, a thread principal da CPU está essencialmente ociosa durante esse tempo, permitindo que a CPU esfrie e use um mínimo de energia da bateria.
O marcador a ser observado pode ser diferente em outras plataformas ou se o VSync estiver desativado. O importante é verificar se a thread principal está operando dentro do seu orçamento de quadros ou exatamente no seu orçamento de quadros com algum tipo de marcador que indique que o aplicativo está esperando pelo VSync e se as outras threads têm algum tempo ocioso.
O tempo ocioso é representado por marcadores de Profiler cinzas ou amarelos. A captura de tela acima mostra que a thread de renderização está ociosa em Gfx.WaitForGfxCommandsFromMainThread, o que indica os momentos em que terminou de enviar chamadas de desenho para a GPU em um quadro e está esperando por mais solicitações de chamadas de desenho da CPU no próximo. Da mesma forma, embora a thread Job Worker 0 passe algum tempo em Canvas.GeometryJob, a maior parte do tempo está ociosa. Todos esses são sinais de um aplicativo que está confortavelmente dentro do orçamento de quadros.
Se o seu jogo está dentro do orçamento de quadros
Se você estiver dentro do orçamento de quadros, incluindo quaisquer ajustes feitos no orçamento para levar em conta o uso da bateria e o estrangulamento térmico, você terminou as principais tarefas de perfilamento. Você pode concluir executando o Memory Profiler para garantir que o aplicativo também esteja dentro do seu orçamento de memória.
A imagem acima mostra um jogo em execução confortavelmente dentro do orçamento de quadro de ~22 ms necessário para 30 fps. Note o preenchimento WaitForTargetfps do tempo da thread principal até o VSync e os tempos ociosos cinzas na thread de renderização e na thread de trabalho. Observe também que o intervalo de VBlank pode ser observado olhando para os tempos finais de Gfx.Present quadro a quadro, e que você pode traçar uma escala de tempo na área da Linha do Tempo ou na régua de Tempo na parte superior para medir de um desses para o próximo.

Se o seu jogo não estiver dentro do orçamento de quadros da CPU, o próximo passo é investigar qual parte da CPU é o gargalo – em outras palavras, qual thread está mais ocupada.
É raro que toda a carga de trabalho da CPU seja o gargalo. Os CPUs modernos têm um número de núcleos diferentes, capazes de realizar trabalho de forma independente e simultânea. Diferentes threads podem ser executadas em cada núcleo de CPU. Uma aplicação Unity completa utiliza uma variedade de threads para diferentes propósitos, mas aquelas que são as mais comuns para encontrar problemas de desempenho são:
Um exemplo do mundo real de otimização da thread principal
A imagem abaixo mostra como as coisas podem parecer em um projeto que está limitado pela thread principal. Este projeto está rodando em um Meta Quest 2, que normalmente visa orçamentos de quadro de 13,88 ms (72 fps) ou até mesmo 8,33 ms (120 fps), porque altas taxas de quadros são importantes para evitar enjoo em dispositivos VR. No entanto, mesmo que este jogo estivesse visando 30 fps, é claro que este projeto está em apuros.
Embora a thread de renderização e as threads de trabalho pareçam semelhantes ao exemplo que está dentro do orçamento de quadro, a thread principal está claramente ocupada com trabalho durante todo o quadro. Mesmo considerando a pequena quantidade de sobrecarga do profiler no final do quadro, a thread principal está ocupada por mais de 45 ms, o que significa que este projeto atinge taxas de quadros de menos de 22 fps. Não há marcador que mostre a thread principal esperando ociosa pelo VSync; ela está ocupada durante todo o quadro.
A próxima etapa da investigação é identificar as partes do quadro que levam mais tempo e entender por que isso acontece. Neste quadro, PostLateUpdate.FinishFrameRendering leva 16,23 ms, mais do que todo o orçamento do quadro. Uma inspeção mais detalhada revela que há cinco instâncias de um marcador chamado Inl_RenderCameraStack, indicando que cinco câmeras estão ativas e renderizando a cena. Como cada câmera no Unity invoca todo o pipeline de renderização, incluindo culling, sorting e batching, a tarefa de maior prioridade para este projeto é reduzir o número de câmeras ativas, idealmente para apenas uma.
BehaviourUpdate, o marcador do Profiler que abrange todas as execuções do método MonoBehaviour.Update(), leva 7,27 milissegundos neste quadro.
Na visualização da Timeline, seções coloridas de magenta indicam pontos onde scripts estão alocando memória gerenciada no heap. Mudando para a visualização Hierarchy e filtrando digitando GC.Alloc na barra de pesquisa, mostra que alocar essa memória leva cerca de 0,33 ms neste quadro. No entanto, essa é uma medição imprecisa do impacto que as alocações de memória têm no desempenho da sua CPU.
Os marcadores GC.Alloc não são cronometrados registrando um ponto de Início e Fim como amostras típicas do Profiler. Para minimizar sua sobrecarga, o Unity registra apenas o timestamp da alocação e o tamanho alocado.
O Profiler atribui uma pequena duração de amostra artificial aos marcadores GC.Alloc apenas para garantir que eles sejam visíveis nas visualizações do Profiler. A alocação real pode levar mais tempo, especialmente se um novo intervalo de memória precisar ser solicitado ao sistema. Para ver o impacto mais claramente, coloque marcadores do Profiler ao redor do código que faz a alocação; em profiling profundo, as lacunas entre as amostras GC.Alloc coloridas de magenta na visualização da Timeline fornecem alguma indicação de quanto tempo elas podem ter levado.
Além disso, alocar nova memória pode ter efeitos negativos no desempenho que são mais difíceis de medir e atribuir diretamente a elas:
No início do quadro, quatro instâncias de Physics.FixedUpdate somam 4,57 ms. Mais tarde, LateBehaviourUpdate (chamadas para MonoBehaviour.LateUpdate()) levam 4 ms, e Animators representam cerca de 1 ms. Para garantir que este projeto atinja seu orçamento e taxa de quadro desejados, todas essas questões da thread principal precisam ser investigadas para encontrar otimizações adequadas.
Armadilhas comuns para gargalos da thread principal
Os maiores ganhos de desempenho serão obtidos otimizando as coisas que levam mais tempo. As seguintes áreas costumam ser lugares frutíferos para procurar otimizações em projetos que são vinculados à thread principal:
Leia nossos guias de otimização que oferecem uma longa lista de dicas práticas para otimizar algumas das armadilhas mais comuns:
Dependendo do problema que você deseja investigar, outras ferramentas também podem ser úteis:
Para dicas abrangentes sobre como otimizar seu jogo, baixe esses guias de especialistas da Unity gratuitamente:

Aqui está um projeto real que é vinculado pela sua thread de renderização. Este é um jogo de console com uma perspectiva isométrica e um orçamento de quadro alvo de 33,33 ms.
A captura do Profiler mostra que antes que a renderização possa começar no quadro atual, a thread principal espera pela thread de renderização, como indicado pelo marcador Gfx.WaitForPresentOnGfxThread . A thread de renderização ainda está enviando comandos de chamada de desenho do quadro anterior e não está pronta para aceitar novas chamadas de desenho da thread principal; ela também está gastando tempo em Camera.Render.
Você pode perceber a diferença entre marcadores relacionados ao quadro atual e marcadores de outros quadros, porque os últimos aparecem mais escuros. Você também pode ver que, uma vez que a thread principal consegue continuar e começar a emitir chamadas de desenho para a thread de renderização processar, a thread de renderização leva mais de 100 ms para processar o quadro atual, o que também cria um gargalo durante o próximo quadro.
Uma investigação mais aprofundada mostrou que este jogo tinha uma configuração de renderização complexa, envolvendo nove câmeras diferentes e muitos passes extras causados por shaders de substituição. O jogo também estava renderizando mais de 130 luzes pontuais usando um caminho de renderização para frente, o que pode adicionar várias chamadas de desenho transparentes adicionais para cada luz. No total, esses problemas combinados criaram mais de 3000 chamadas de desenho por quadro.
Armadilhas comuns para gargalos da thread de renderização
As seguintes são causas comuns a serem investigadas para projetos que estão limitados pela thread de renderização:
O Módulo de Profiler de Renderização mostra uma visão geral do número de lotes de chamadas de desenho e chamadas de SetPass a cada quadro. A melhor ferramenta para investigar quais lotes de chamadas de desenho sua thread de renderização está emitindo para a GPU é o Frame Debugger.
Ferramentas para resolver os gargalos identificados
Embora o foco deste e-book seja identificar problemas de desempenho, os dois guias complementares de otimização de desempenho que destacamos anteriormente oferecem sugestões sobre como resolver os gargalos, dependendo se sua plataforma alvo é PC ou console ou mobile. No contexto de gargalos da thread de renderização, vale a pena enfatizar que a Unity oferece diferentes sistemas e opções de agrupamento dependendo dos problemas que você identificou. Aqui está uma visão geral rápida de algumas das opções que explicamos em mais detalhes nos e-books:
Além disso, do lado da CPU, técnicas como Camera.layerCullDistances podem ser usadas para reduzir o número de objetos enviados para a thread de renderização, eliminando objetos com base na distância deles da câmera, ajudando a aliviar gargalos da CPU durante a eliminação de câmera.
Estas são apenas algumas das opções disponíveis. Cada uma delas tem diferentes vantagens e desvantagens. Algumas são limitadas a certas plataformas. Os projetos precisam frequentemente usar uma combinação de vários desses sistemas e, para isso, é necessário entender como obter o máximo deles.

Projetos limitados por threads da CPU que não sejam a principal ou a de renderização não são tão comuns. No entanto, isso pode ocorrer se seu projeto usar o Data-Oriented Technology Stack (DOTS), especialmente se o trabalho for transferido da thread principal para threads de trabalho usando o job system.
A imagem acima é uma captura do modo de reprodução no Editor, mostrando um projeto DOTS executando uma simulação de fluido de partículas na CPU.
Parece um sucesso à primeira vista. As threads de trabalho estão compactadas com trabalhos Burst-compiled, indicando que uma grande quantidade de trabalho foi transferida da thread principal. Normalmente, esta é uma decisão sensata.
No entanto, neste caso, o tempo de quadro de 48,14 ms e o marcador cinza WaitForJobGroupID de 35,57 ms na thread principal são sinais de que tudo não está bem. WaitForJobGroupID indica que a thread principal agendou trabalhos para serem executados de forma assíncrona em threads de trabalho, mas precisa dos resultados desses trabalhos antes que as threads de trabalho tenham terminado de executá-los. Os marcadores azuis do Profiler abaixo de WaitForJobGroupID mostram a thread principal executando trabalhos enquanto espera, na tentativa de garantir que os trabalhos terminem mais cedo.
Embora os trabalhos sejam compilados com Burst, eles ainda estão fazendo muito trabalho. Talvez a estrutura de consulta espacial usada por este projeto para encontrar rapidamente quais partículas estão próximas umas das outras deva ser otimizada ou trocada por uma estrutura mais eficiente. Ou, os trabalhos de consulta espacial podem ser agendados para o final do quadro em vez do início, com os resultados não sendo necessários até o início do próximo quadro. Talvez este projeto esteja tentando simular muitas partículas. Uma análise mais aprofundada do código dos trabalhos é necessária para encontrar a solução, então adicionar marcadores de Profiler mais detalhados pode ajudar a identificar suas partes mais lentas.
Os trabalhos em seu projeto podem não estar tão paralelizados quanto neste exemplo. Talvez você tenha apenas um trabalho longo sendo executado em uma única thread de trabalho. Isso é aceitável, desde que o tempo entre o agendamento do trabalho e o tempo que precisa ser concluído seja longo o suficiente para que o trabalho seja executado. Se não for, você verá a thread principal travar enquanto espera o trabalho ser concluído, como na captura de tela acima.
Armadilhas comuns para gargalos de threads de trabalho
Causas comuns de pontos de sincronização e gargalos de threads de trabalho incluem:
Você pode usar o recurso Flow Events na visualização da linha do tempo do módulo de Profiler de Uso da CPU para investigar quando os trabalhos são agendados e quando seus resultados são esperados pela thread principal.
Para mais informações sobre como escrever código DOTS eficiente, consulte o guia Melhores Práticas DOTS.

Sua aplicação é limitada pela GPU se a thread principal gastar muito tempo em marcadores do Profiler como Gfx.WaitForPresentOnGfxThread, e sua thread de renderização exibir simultaneamente marcadores como Gfx.PresentFrame ou .WaitForLastPresent..
A melhor maneira de obter tempos de quadro da GPU é usar uma ferramenta de perfilagem de GPU específica para a plataforma-alvo, mas nem todos os dispositivos facilitam a captura de dados confiáveis.
A API FrameTimingManager pode ser útil nesses casos, fornecendo tempos de quadro de alto nível e baixo overhead tanto na CPU quanto na GPU.
A captura acima foi feita em um telefone móvel Android usando a API gráfica Vulkan. Embora parte do tempo gasto em Gfx.PresentFrame neste exemplo possa estar relacionado à espera pelo VSync, a extrema duração deste marcador do Profiler indica que a maior parte desse tempo é gasta esperando a GPU terminar de renderizar o quadro anterior.
Neste jogo, certos eventos de jogabilidade acionaram o uso de um shader que triplicou o número de chamadas de desenho renderizadas pela GPU. Questões comuns a investigar ao perfilar o desempenho da GPU incluem:
Se sua aplicação parecer estar limitada pela GPU, você pode usar o Frame Debugger como uma maneira rápida de entender os lotes de chamadas de desenho que estão sendo enviados para a GPU. No entanto, esta ferramenta não pode apresentar nenhuma informação específica de tempo da GPU, apenas como a cena geral é construída.
A melhor maneira de investigar a causa dos gargalos da GPU é examinar uma captura da GPU de um profiler de GPU adequado. Qual ferramenta você usa depende do hardware alvo e da API gráfica escolhida. Veja a seção de ferramentas de profiling e depuração no e-book para mais informações.


Encontre mais melhores práticas e dicas do central de melhores práticas da Unity. Escolha entre mais de 30 guias, criados por especialistas da indústria e engenheiros e artistas técnicos da Unity, que ajudarão você a desenvolver de forma eficiente com as ferramentas e sistemas da Unity.