Onde trabalhei, sempre usamos vários níveis de criação de perfil; se você encontrar um problema, basta mover a lista um pouco mais até descobrir o que está acontecendo:
- O "profiler humano", também conhecido como apenas jogar o jogo ; sente lento ou "engate" ocasionalmente? Notando animações espasmódicas? (Como desenvolvedor, observe que você será mais sensível a alguns tipos de problemas de desempenho e alheio a outros. Planeje testes extras de acordo.)
- Ligue a tela do FPS , que é um FPS médio de 5 segundos na janela deslizante. Muito pouca sobrecarga para calcular e exibir.
- Ligue as barras de perfil , que são apenas uma série de quads (cores ROYGBIV) que representam diferentes partes do quadro (por exemplo, vblank, preframe, atualização, colisão, renderização, pós-quadro) usando um simples cronômetro "cronômetro" em cada seção do código . Para enfatizar o que queremos, definimos uma barra de largura de tela como representativa de um quadro de destino de 60Hz, para que seja realmente fácil ver se você está, por exemplo, com 50% abaixo do orçamento (apenas meia barra) ou 50% acima ( a barra envolve e se torna uma barra e meia). Também é muito fácil dizer o que geralmente está comendo a maior parte do quadro: red = render, yellow = update, etc ...
- Crie uma compilação instrumentada especial que insira "cronômetro" como código em todas as funções. (Observe que você pode ter um desempenho massivo, dcache e icache atingido ao fazer isso, por isso é definitivamente intrusivo. Mas se você não tiver um perfil de amostragem adequado ou um suporte decente na CPU, essa é uma opção aceitável. Você também pode ser inteligente sobre como gravar um mínimo de dados na função, entrar / sair e reconstruir rastros de chamadas posteriormente.) Quando criamos o nosso, imitamos grande parte do formato de saída do gprof .
- O melhor de tudo, execute um criador de perfil de amostragem ; O VTune e o CodeAnalyst estão disponíveis para x86 e x64; você tem vários ambientes de simulação ou emulação que podem fornecer dados aqui.
(Há uma história divertida da GDC do ano passado de um programador gráfico que tirou quatro fotos de si mesmo - feliz, indiferente, irritado e irritado - e exibiu uma imagem apropriada no canto das construções internas com base na taxa de quadros. os criadores de conteúdo aprenderam rapidamente a não ativar shaders complicados para todos os seus objetos e ambientes: eles irritariam o programador. Veja o poder do feedback.)
Observe que você também pode fazer coisas divertidas, como representar graficamente as "barras de perfil" continuamente, para ver padrões de pico ("estamos perdendo um quadro a cada 7 quadros") ou algo semelhante.
Porém, para responder sua pergunta diretamente: na minha experiência, embora seja tentador (e geralmente gratificante - geralmente aprendo algo) reescrever funções / módulos únicos para otimizar o número de instruções ou o desempenho do icache ou dcache, e realmente precisamos fazer Às vezes, quando temos um problema de desempenho particularmente desagradável, a grande maioria dos problemas de desempenho com os quais lidamos regularmente se resume ao design . Por exemplo:
- Devemos armazenar em cache na RAM ou recarregar do disco os quadros de animação de estado de "ataque" para o player? Que tal para cada inimigo? Não temos RAM para fazer tudo, mas as cargas de disco são caras! Você pode ver o engate se 5 ou 6 inimigos diferentes aparecerem ao mesmo tempo! (Ok, que tal desova impressionante?)
- Estamos realizando um único tipo de operação em todas as partículas ou todas as operações em uma única partícula? (Essa é uma troca do icache / dcache, e a resposta nem sempre é clara.) Que tal separar todas as partículas e armazenar as posições juntas (a famosa "estrutura de matrizes") versus manter todos os dados de partículas em um só lugar (" matriz de estruturas ").
Você o ouve até que se torne desagradável em qualquer curso de ciência da computação em nível universitário, mas: é realmente tudo sobre estruturas e algoritmos de dados. Passar algum tempo com o design de algoritmos e fluxo de dados vai lhe trazer mais benefícios em geral. (Certifique-se de ler os excelentes slides das Armadilhas da Programação Orientada a Objetos de um membro dos Serviços de Desenvolvedor da Sony para obter algumas dicas aqui.) Isso não parece otimização; é na maior parte do tempo gasto com um quadro branco ou ferramenta UML ou criando muitos protótipos, em vez de tornar o código atual mais rápido. Mas geralmente vale muito mais a pena.
E outra heurística útil: se você estiver próximo do "núcleo" do seu mecanismo, pode valer algum esforço e experimentação extra para otimizar (por exemplo, vetorizar essas matrizes multiplica!). Quanto mais longe do núcleo, menos você deve se preocupar com isso, a menos que uma de suas ferramentas de criação de perfil diga o contrário.
Lembre-se também de "pessimização prematura". Embora não haja necessidade de ser incondicional em todas as linhas de código, há justificativa para perceber que você está realmente trabalhando em um jogo, o que tem implicações de desempenho em tempo real.
Enquanto todo mundo pede para você medir e otimizar os pontos de acesso, essa técnica não mostra o desempenho perdido em locais ocultos. Por exemplo, se cada operação '+' no seu código levasse o dobro do tempo necessário, ela não aparecerá como um ponto de acesso e, portanto, você nunca a otimizará nem perceberá, no entanto, uma vez que está sendo usada em todo o coloque-o pode custar muito desempenho. Você ficaria surpreso com quantos desses ciclos desaparecem sem nunca serem detectados. Portanto, esteja ciente do que você faz.
Além disso, costumo escrever perfis regularmente para ter uma idéia do que está lá e quanto tempo resta por quadro. Para mim, o tempo por quadro é o mais lógico, pois me diz diretamente onde estou com os objetivos da taxa de quadros. Tente também descobrir onde estão os picos e o que os causa - prefiro uma taxa de quadros estável a uma taxa de quadros alta com picos.
fonte
Quando um jogo estiver pronto para ser lançado (final ou beta), ou é visivelmente lento, provavelmente é o melhor momento para criar um perfil do seu aplicativo. Obviamente, você sempre pode executar o criador de perfil a qualquer momento; mas sim, a otimização prematura é a raiz de todo mal. Otimização infundada também; você precisa de dados reais para mostrar que algum código é lento, antes de tentar "otimizá-lo". Um criador de perfil faz isso por você.
Se você não conhece um perfilador, aprenda-o! Aqui está uma boa postagem no blog demonstrando a utilidade de um criador de perfil.
Caso contrário, se o seu pequeno jogo estiver rodando a 200 FPS, mesmo com um algoritmo ineficiente, você realmente tem um motivo para otimizar? Você deve ter uma boa idéia das especificações da sua máquina-alvo e garantir que o jogo corra bem nessa máquina, mas qualquer coisa além disso é (sem dúvida) desperdício de tempo que poderia ser melhor gasto em codificação ou polimento do jogo.
fonte
Acho útil criar perfis. Mesmo que você não esteja otimizando ativamente, é bom ter uma idéia do que está limitando seu desempenho a qualquer momento. Muitos jogos têm algum tipo de HUD sobreposto, que exibe um gráfico simples (geralmente apenas uma barra colorida) mostrando quanto tempo várias partes do ciclo do jogo levam cada quadro.
Seria uma má idéia deixar a análise e a otimização do desempenho para um estágio tardio demais. Se você já construiu o jogo e está 200% acima do orçamento da CPU e não consegue encontrá-lo através da otimização, está ferrado.
Você precisa saber quais são os orçamentos para gráficos, física etc., enquanto escreve. Você não pode fazer isso se não tem idéia de qual será o seu desempenho e não consegue adivinhar sem saber qual é o seu desempenho e o quanto de folga pode haver.
Portanto, crie algumas estatísticas de desempenho desde o primeiro dia.
Quanto a quando lidar com as coisas - novamente, provavelmente é melhor não deixar tarde demais, para que você não precise refatorar metade do seu motor. Por outro lado, não se envolva muito em otimizar coisas para espremer todos os ciclos se você acha que pode mudar o algoritmo inteiramente amanhã, ou se não colocou dados reais do jogo nele.
Apanhe as frutas baixas à medida que avança, lide com as coisas grandes periodicamente e você ficará bem.
fonte
Se olharmos para a citação de Knuth em seu contexto, ele continua explicando que devemos otimizar, mas com ferramentas, como um criador de perfil.
Você deve constantemente criar um perfil e um perfil de memória para o seu aplicativo após a arquitetura básica ser estabelecida.
A criação de perfil não apenas ajuda a aumentar a velocidade, mas também a encontrar bugs. Se o seu programa repentinamente muda drasticamente a velocidade, isso geralmente ocorre devido a um erro. Se você não criar um perfil, pode passar despercebido.
O truque para otimizar é fazê-lo por design. Não espere até o último minuto. Certifique-se de que o design do seu programa ofereça o desempenho que você precisa, sem realmente fazer truques desagradáveis de loop interno.
fonte
Para o meu projeto, costumo aplicar algumas otimizações MUITO necessárias no meu mecanismo básico. Por exemplo, eu sempre gosto de implementar uma boa implementação sólida de SIMD usando SSE2 e 3DNow! Isso garante que minha matemática de ponto flutuante esteja na sugestão de onde eu quero que ela esteja. Outra boa prática é criar o hábito das otimizações à medida que você codifica, em vez de voltar. Na maioria das vezes, essas pequenas práticas consomem tanto tempo quanto o que você estava codificando de qualquer maneira. Antes de codificar um recurso, pesquise a maneira mais eficiente de fazê-lo.
Bottom line, na minha opinião, é mais difícil tornar seu código mais eficiente depois que ele já é péssimo.
fonte
Eu diria que a maneira mais fácil seria usar seu bom senso - se algo parece estar lento, então dê uma olhada. Veja se é um gargalo.
Use um criador de perfil para dar uma olhada nas funções de velocidade que estão sendo executadas e com que frequência elas estão sendo chamadas.
Não faz sentido otimizar ou gastar tempo tentando otimizar algo que não precisa.
fonte
Se o seu código estiver lento, execute um criador de perfil e veja o que exatamente está causando a execução mais lenta. Ou você pode ser proativo e já ter um gerador de perfil em execução antes de começar a perceber problemas de desempenho.
Você desejará otimizar quando a taxa de quadros cair a um ponto em que o jogo começa a sofrer. O culpado mais provável será o uso excessivo da CPU (100%).
fonte
Você deve otimizar seu código ... quantas vezes precisar.
O que eu fiz no passado é apenas executar o jogo continuamente com a criação de perfis ativada (pelo menos um contador de quadros na tela o tempo todo). Se o jogo estiver ficando lento (abaixo da taxa de quadros de destino na sua máquina de especificações mínimas, por exemplo), ligue o criador de perfil e veja se algum hot spot aparece.
Às vezes não é o código. Muitos dos problemas que encontrei no passado foram orientados a gpu (é verdade, isso ocorreu no iPhone). Problemas de taxa de preenchimento, muitas chamadas de desenho, sem lotes de geometria suficiente, sombreadores ineficientes ...
Além de algoritmos ineficientes para problemas difíceis (ou seja, busca de caminhos, física), raramente encontrei problemas em que o próprio código era o culpado. E esses problemas difíceis devem ser coisas que você gasta muito do seu esforço para acertar o algoritmo e não se preocupar com coisas menores.
fonte
Para mim é o melhor seguir um modelo de dados bem preparado. E otimização - antes do principal passo adiante. Quero dizer, antes de começar a implementar algo grande novo. Outra razão para a otimização é quando estou perdendo o controle sobre os recursos, o aplicativo precisa de muita carga de CPU / carga de GPU ou memória e não sei por que :) ou é demais.
fonte