
Algumas otimizações exigem estruturas de dados complexas e milhares de linhas de código. Em outros casos, um aumento sério na produtividade gera uma alteração mínima: às vezes você só precisa definir zero. É como um
conto antigo
sobre um capitão que conhece o lugar certo para bater com um martelo e depois fatura ao cliente: US $ 0,50 por um golpe na válvula e US $ 999,50 por saber onde bater.
Eu, pessoalmente, encontrei vários erros de desempenho que foram corrigidos digitando um zero e, neste artigo, quero compartilhar duas histórias.
A importância da medição

Nos dias do Xbox original, ajudei a otimizar muitos jogos. Em um deles, o criador de perfil apontou para a função de transformação da matriz, que consumiu 7% do tempo da CPU - o maior salto no gráfico. Por isso, trabalhei diligentemente na otimização desse recurso.

Pode-se ver que eu não fui o primeiro a tentar fazer isso. A função já foi reescrita no assembler. Encontrei várias melhorias em potencial na linguagem assembly e tentei medir seus efeitos. Este é um passo importante, caso contrário, é fácil fazer a "otimização", que não mudará nada ou até piorará a situação.
No entanto, a medição foi difícil. Eu corri o jogo, joguei um pouco com o perfil paralelo e depois estudei o perfil: o código ficou mais rápido? Parecia que houve uma ligeira melhora, mas era impossível dizer com certeza.
Então eu apliquei o método
científico . Ele escreveu uma coleção de testes para gerenciar versões antigas e novas de código para medir com precisão as diferenças de desempenho.

Isso não levou muito tempo: como esperado, o novo código foi cerca de 10% mais rápido que o antigo.
Mas descobriu-se que a aceleração de 10% é um absurdo.
É muito mais interessante que dentro do código de teste foi executado cerca de 10 vezes mais rápido que no jogo. Esta foi uma descoberta emocionante.
Depois de verificar os resultados, olhei para o vazio por um tempo, mas então me dei conta.
Função de armazenamento em cache
Para dar aos desenvolvedores de jogos controle total e desempenho máximo, os consoles de jogos permitem alocar memória com vários atributos. Em particular, o Xbox original permite alocar memória não armazenável em cache. Esse tipo de memória (de fato, o tipo de tag nas tabelas de páginas) é útil ao gravar dados na GPU. Como a memória não é armazenada em cache, a gravação irá para a RAM quase imediatamente, sem atrasos ou contaminação do cache com o mapeamento "normal".
Portanto, a memória não armazenada em cache é uma otimização importante, mas deve ser usada com cuidado. Em particular, é extremamente importante que os jogos nunca tentem
ler da memória não armazenada em cache, caso contrário, seu desempenho diminuirá seriamente. Mesmo a
CPU relativamente lenta de
733 MHz no Xbox original precisa de seus próprios caches para fornecer desempenho de leitura suficiente.
Agora fica claro o que está acontecendo. Aparentemente, para esta função, os dados são alocados na memória não armazenada em cache, portanto, baixo desempenho. Um pequeno teste confirmou essa hipótese, então é hora de corrigir o problema. Encontrei a linha em que a memória está alocada, clique duas vezes no valor do sinalizador e apontei para zero.
Em vez de cerca de 7% do tempo do processador, a função começou a consumir cerca de 0,7% e não era mais um problema.
No final da semana, meu relatório era mais ou menos assim: "39.999 horas de pesquisa, 0,001 horas de programação é um enorme sucesso!"
Os desenvolvedores geralmente não precisam se preocupar em alocar acidentalmente memória não armazenada em cache: na maioria dos sistemas operacionais, essa opção não está disponível no espaço do usuário usando métodos padrão. Mas se você estiver interessado em quanta memória não armazenável em cache pode atrasar o programa, tente os sinalizadores PAGE_NOCACHE ou PAGE_WRITECOMBINE no
VirtualAlloc .
0 GiB é melhor que 4 GiB

Eu quero lhe contar outra história. É sobre um bug que eu encontrei, e alguém o corrigiu. Há alguns anos, notei que o cache do disco no meu laptop é frequentemente limpo. Rastreei que isso acontece quando a linha de 4 GiB é alcançada e, no final, o driver do meu novo HDD de backup define SectorSize como 0xFFFFFFFF (ou -1) ao apontar para um tamanho de setor desconhecido. O kernel do Windows interpreta esse valor como 4 GiB e aloca o bloco de memória correspondente, o que causou o problema.
Não tenho contatos no Western Digital, mas posso assumir com segurança que eles corrigiram esse erro substituindo a constante 0xFFFFFFFF (ou -1) por zero. Um caractere entrou - e resolveu um sério problema de desempenho.
(Leia mais sobre este estudo no artigo “Abrandando o Windows: Explorando e Identificando” )Observações
- Nos dois casos, o problema está no cache
- Decisivo foi o uso de um criador de perfil para identificar o problema.
- Se o patch não for verificado por medidas, ele não ajudará necessariamente.
- Eu poderia escrever sobre muitos outros casos, mas eles são muito secretos ou muito chatos.
- A decisão correta não precisa ser complicada. Às vezes, uma grande melhoria dá uma pequena mudança. Tudo que você precisa saber é onde
Por acaso, otimizei o código descomentando #define e por outras alterações triviais. Conte-nos nos comentários se você tiver essas histórias.