Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A otimização guiada por perfil (PGO) usa dados de tempo de execução para ajudar o compilador a tomar melhores decisões de otimização. Usando dados de perfil de execução coletados de cargas de trabalho representativas, o PGO permite que o compilador tome decisões mais inteligentes sobre inlining, layout de código e separação de código quente/frio. Essas decisões são impossíveis de tomar apenas com base na análise estática.
O SPGO adota uma abordagem diferente. Em vez de instrumentar seu binário e executá-lo por meio de cenários de treinamento sintéticos, o SPGO usa a amostragem do contador de desempenho de hardware coletada de seus binários de versão reais. Os processadores modernos fornecem recursos de amostragem de hardware. Você pode coletar esses exemplos com sobrecarga de runtime insignificante, tornando prático coletar perfis de runtime diretamente do código de produção.
Como os perfis SPGO liberam bits em vez de builds instrumentados, ele permite muito mais flexibilidade em onde e como você coleta dados. Você pode reunir perfis de runtime de servidores de produção, computadores desenvolvedores, laboratórios de desempenho ou qualquer combinação. O resultado é um binário que executa trechos críticos com mais eficiência, com um ganho de desempenho típico de 5 a 15%, dependendo da qualidade dos dados de perfil.
Neste tutorial, você percorrerá o fluxo de trabalho SPGO completo: crie um aplicativo de exemplo, crie um perfil usando xperf, prepare os dados do perfil e recompile com os dados do perfil. Ao concluir, você pode aplicar o mesmo processo a seus próprios projetos.
Pré-requisitos
Antes de começar, verifique se você tem o software e o hardware a seguir.
Programas de computador
- ferramentas de compilação do MSVC para x64/x86/ARM64 v14.51 ou mais recente—Instale-as por meio do Instalador do Visual Studio. Em Componentes Individuais, pesquise por "ferramentas de build do MSVC".
-
Windows Performance Toolkit (xperf.exe)—O profiler
xperfcoleta dados de amostragem durante a execução do seu programa. Baixe o Kit de Avaliação e Implantação do Windows (ADK) em ADK install. Ao executar o instalador do ADK, selecione o componente Windows Performance Toolkit para obterxperf. Você não precisa instalar o ADK completo. - Arquivo de texto Guerra e Paz—Usado como carga de trabalho de exemplo para gerar dados de perfilamento. Baixe-o de Project Gutenberg: https://www.gutenberg.org/ebooks/2600. Salve-o como um arquivo de texto sem formatação no diretório de trabalho.
Requisitos de hardware
O tutorial tem três caminhos de criação de perfil. Qual caminho você usa depende do hardware. Execute os comandos de detecção em Escolher seu método de criação de perfil para descobrir qual caminho sua máquina oferece suporte. Por enquanto, use esta tabela para confirmar que você atende a pelo menos um dos requisitos.
| Path | Requisito de CPU | Observações |
|---|---|---|
| LBR (melhores resultados) | Os Registros do Último Desvio (LBR) são contadores de desempenho disponibilizados em CPUs Intel Haswell (Core de 4ª geração, 2013) ou posteriores; AMD Zen 4 (2022) ou posteriores; ARM64 ARMv9.2-A (2020) ou posteriores | Fornece os melhores dados de ramificação. Para obter mais informações sobre LBR, consulte Uma introdução aos últimos registros de branch |
| Modo PMC/IP (bons resultados) | Os PMC (Contadores de Monitoramento de Desempenho) têm suporte em qualquer CPU x64 com uma PMU (unidade de monitoramento de desempenho) | Funciona na maioria das CPUs modernas em que o LBR não está disponível. Para obter mais informações sobre PMC, consulte Gravação de eventos de desempenho de hardware (PMU) e Gravação de eventos de desempenho de hardware (PMU) com exemplos completos |
| Temporizador do sistema operacional (funciona em qualquer lugar) | Qualquer CPU x64 ou ARM64, incluindo Azure VMs e máquinas virtuais | Exemplos de menor fidelidade, mas sempre disponíveis |
A maioria dos desenvolvedores em desktops x64 modernos conta com suporte a LBR. As VMs e alguns hardwares mais antigos têm PMC ou um temporizador do sistema operacional.
Como o SPGO funciona
O SPGO coleta dados de perfil do seu binário em execução e os fornece de volta ao compilador na próxima compilação. O compilador usa esses dados para tomar melhores decisões sobre inserção em linha, organização do código e previsão de desvios. Uma conveniência é que nenhuma instrumentação é necessária.
O fluxo de trabalho é:
- Compile seu binário com a flag do vinculador /spgo. Esta etapa cria um banco de dados de perfil de exemplo vazio (
.spdarquivo). - Crie o perfil do binário usando
xperfpara produzir um arquivo de rastreamento ETL. - Converta o ETL em um arquivo SPT usando
SPTAggregate.exee converta o SPT em um arquivo SPD usandoSPDConvert.exe. - Recompile usando a flag do vinculador /spdin, apontando para o banco de dados de perfil de exemplo (SPD) preenchido. O vinculador aplica otimizações SPGO.
O otimizador usa o SPD para responder a perguntas como: quais ramificações são seguidas com mais frequência? Quais funções são chamadas em loops quentes? Esse processo produz melhor layout de código e decisões de sublinhação do que somente análise estática.
O SPGO funciona com C e C++. O fluxo de trabalho e os sinalizadores são idênticos para ambos os idiomas.
Melhores candidatos para SPGO: Aplicativos C/C++ grandes e cheios de ramificação com loops internos apertados. Os ganhos aumentam com o tamanho da base de código e a complexidade do branch. O pequeno exemplo neste tutorial mostra cerca de 7% melhoria. As bases de código de produção maiores geralmente veem mais melhorias.
Comparação do processo de compilação
Esta seção aborda como o SPGO se encaixa no pipeline de compilação, se você quiser entender seu funcionamento.
Processo de build normal
Em um build de versão padrão do C/C++:
-
Entradas: Arquivos de código-fonte (
.cpp,.h) e sinalizadores do compilador no modo de versão (/O2/GLe assim por diante). - Processo: O compilador aplica otimizações padrão, como a heurística embutida, suposições de previsão de branch e decisões de layout de código com base apenas na análise estática. Ele não tem dados sobre como o programa realmente se comporta quando é executado.
-
Saída: Executável (
.exe), arquivos DLL (.dll), informações de depuração (.pdb).
Sem dados de runtime, caminhos quentes e caminhos frios recebem tratamento semelhante.
Processo de compilação com SPGO habilitado
O SPGO adiciona dados de criação de perfil como uma nova entrada ao pipeline de build:
-
Entradas: código-fonte, o arquivo de perfil
.spd(contagens de amostras de uma execução de criação de perfil), sinalizadores do compilador para o modo de release,/link /spgoe/spdin:<path>para especificar um arquivo SPD de entrada (se não for especificado, o padrão será um arquivo .spd com base no nome do binário e localizado na pasta obj). - Processo: O vinculador lê o SPD junto com o código intermediário. Ele usa dados de frequência de ramificação para tomar melhores decisões de inlining, layout de código e ordenação de ramificação. As funções mais usadas são organizadas para acesso rápido; o código menos usado é movido para fora do caminho crítico.
-
Saída: Executável otimizado (
.exe), arquivos DLL otimizados (.dll), informações de depuração (.pdb), e um novo arquivo.spdpara futuras iterações de criação de perfil.
A visão chave: o SPGO move as decisões de otimização do compilador e da heurística do vinculador para as escolhas controladas por dados com base na execução real.
Sinalizadores principais
| Flag | Tipo | Purpose |
|---|---|---|
/spgo |
Linker | Habilita o SPGO. Insere metadados SPGO no binário e cria um arquivo de saída vazio .spd , a menos que /spdin seja especificado, nesse caso, o arquivo especificado .spd é usado como entrada. |
/spdin:<path> |
Linker | SPD de entrada – fornece dados de perfil para o vinculador para otimização |
/spd:<path> |
Linker | Caminho SPD de saída – especifica onde o novo SPD é gravado (opcional; usa como padrão o mesmo diretório que o binário). Serve como o caminho SPD de entrada se /spdin não for especificado. |
/GL |
Compilador | Otimização de programa inteiro necessária para que o SPGO funcione entre unidades de tradução |
/O1, /O2 (Minimizar tamanho, maximizar velocidade) |
Compilador | Otimizar para velocidade; permite otimizações agressivas que o SPGO pode aprimorar |
Como o SPGO difere do PGO
O PGO (otimização guiada por perfil) exige que você compile seu binário com flags de instrumentação (/GENPROFILE), execute o binário instrumentado mais lento para coletar arquivos de contagem de execução .pgc e, em seguida, revincule com /USEPROFILE. O compilador obtém as contagens exatas de execução, mas você precisa instrumentar o código primeiro. Para obter mais informações sobre esse processo, consulte otimizações guiadas por perfil.
O SPGO usa contadores de desempenho de hardware da CPU para coletar amostras estatísticas do seu binário de release não instrumentado. Execute seu binário existente, crie o perfil usando xperf, converta o rastreamento em um arquivo SPD e recompile. Não há compilação instrumentada nem desaceleração durante a análise de desempenho. O compilador obtém dados de amostragem estatística em vez de contagens exatas, o que é menos preciso, mas mais fácil de obter e não requer alterações de código. Ele também permite a criação de perfil de componentes do sistema ou componentes em tempo real que são difíceis de coletar dados com uma abordagem instrumentada. Você também pode analisar o desempenho de binários finais/de distribuição.
Este tutorial aborda três métodos de criação de perfil: LBR, PMC e temporizador do sistema operacional. Escolha seu método em Escolher seu método de criação de perfil. Para obter uma comparação detalhada entre o processo de compilação normal e o processo de compilação do SPGO, incluindo uma tabela de referência de flags, consulte Comparação dos Processos de Compilação.
Configurar o perfcore.ini
⚠️ Obrigatório: sem esta etapa,
xperfnão fornece os dados de criação de perfil necessários. Conclua esta etapa antes de executarxperf.
O Windows Performance Toolkit (WPT) usa perfcore.ini, localizado se você instalou o WPT no local padrão em C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\perfcore.ini, para registrar os provedores de DLL necessários para SPGO.
Abra Windows Bloco de Notas como Administrador. Em seguida, abra perfcore.ini. Localize a seção de lista de DLL e adicione as seguintes entradas, uma por linha:
perf_spt.dll
perf_lbr.dll
Se xperf.exe não estiver instalado, consulte problemas gerais para instalá-lo.
Salve e feche perfcore.ini. Os arquivos DLL já vêm no mesmo diretório que xperf.exe, então você não precisa copiá-los para lugar nenhum. Você só está registrando-os em perfcore.ini. Verifique se xperf está no seu PATH.
Criar o aplicativo de amostra
O aplicativo de exemplo para este tutorial é um programa C++ que lê texto de entrada padrão e produz uma contagem de linhas, contagem de palavras, contagem total de caracteres, uma tabela de frequência de caracteres e tempo decorrido para processar o arquivo em milissegundos. Ele é escrito em C++, mas o SPGO também funciona com C. O fluxo de trabalho é idêntico para projetos C.
Crie um arquivo nomeado textCount.cpp no diretório de trabalho e adicione o seguinte código-fonte:
// textCount.cpp : Text Statistics Counter
// Counts words, lines, and character frequencies from standard input
// Usage: textCount < file.txt
#include <iostream>
#include <string>
#include <map>
#include <cctype>
#include <chrono>
int main()
{
auto start = std::chrono::steady_clock::now();
std::map<unsigned char, int> charFrequency;
int wordCount = 0;
int lineCount = 0;
int totalChars = 0;
std::string line;
bool inWord = false;
while (std::getline(std::cin, line))
{
lineCount++;
for (char c : line)
{
totalChars++;
unsigned char uc = static_cast<unsigned char>(c);
charFrequency[uc]++;
if (std::isspace(static_cast<unsigned char>(c)))
{
inWord = false;
}
else
{
if (!inWord)
{
wordCount++;
inWord = true;
}
}
}
inWord = false;
}
std::cout << "\n=== TEXT STATISTICS ===" << std::endl;
std::cout << "Lines: " << lineCount << std::endl;
std::cout << "Words: " << wordCount << std::endl;
std::cout << "Total Characters: " << totalChars << std::endl;
std::cout << "\n=== CHARACTER FREQUENCIES ===" << std::endl;
std::cout << "\nLetters:" << std::endl;
for (unsigned char ch = 'a'; ch <= 'z'; ch++)
{
unsigned char upperCh = static_cast<unsigned char>(std::toupper(ch));
int count = charFrequency[ch] + charFrequency[upperCh];
if (count > 0)
{
std::cout << static_cast<char>(ch) << ": " << count << std::endl;
}
}
std::cout << "\nDigits:" << std::endl;
for (unsigned char ch = '0'; ch <= '9'; ch++)
{
if (charFrequency[ch] > 0)
{
std::cout << static_cast<char>(ch) << ": " << charFrequency[ch] << std::endl;
}
}
std::cout << "\nSpecial Characters:" << std::endl;
for (const auto& pair : charFrequency)
{
unsigned char ch = pair.first;
if (!std::isalnum(ch))
{
std::string displayChar;
switch (ch)
{
case ' ': displayChar = "[space]"; break;
case '\t': displayChar = "[tab]"; break;
case '\n': displayChar = "[newline]"; break;
case '\r': displayChar = "[return]"; break;
default:
if (ch >= 32 && ch < 127)
{
displayChar = std::string(1, static_cast<char>(ch));
}
else
{
displayChar = "[byte:" + std::to_string(static_cast<int>(ch)) + "]";
}
break;
}
std::cout << displayChar << ": " << pair.second << std::endl;
}
}
auto end = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration<double, std::milli>(end - start);
std::cout << "Elapsed time: " << std::fixed;
std::cout.precision(3);
std::cout << elapsed.count() << " ms\n";
return 0;
}
Compilar e executar o exemplo para obter uma linha de base
Antes de aplicar o SPGO, crie textCount e execute-o em um arquivo de texto grande, como War e Peace (você pode baixá-lo de Project Gutenberg), para ver a velocidade com que ele é executado. Esta etapa mostra o desempenho antes de otimize-o usando SPGO:
Construir:
cl /EHsc /GL /O2 textCount.cpp
Executar:
textCount.exe < warAndPeace.txt
Você vê um resultado semelhante a:
=== TEXT STATISTICS ===
Lines: 66041
Words: 566333
Total Characters: 3227531
=== CHARACTER FREQUENCIES ===
Letters:
a: 202719
...
Elapsed time: 512.000 ms
Registre o valor Elapsed time. Você vai compará-lo com o tempo otimizado pelo SPGO em Meça os resultados.
Compilar textCount usando /spgo
Agora, crie textCount com SPGO habilitado. Esta etapa lança as bases para coletar dados de análise de desempenho.
cl /EHsc /GL /O2 textCount.cpp /link /debug /spgo
Quando o build for concluído, você verá uma mensagem como:
SPD textCount.spd not found, compiling without profile guided optimizations
Esta mensagem é exibida no primeiro /spgo build. O vinculador cria o arquivo SPD, mas ainda está vazio, portanto, ele ainda não aplica nenhuma otimização SPGO. Depois de executar o binário, coletar dados de perfil e convertê-los em SPD, você não verá essa mensagem.
Explicações de sinalizador:
| Flag | Purpose |
|---|---|
/EHsc |
Habilitar o tratamento de exceções do C++ |
/GL |
Otimização de programa inteiro – necessária para SPGO. Adia a otimização final para a etapa de vinculação, permitindo decisões sobre inlining entre módulos, layout de código e eliminação de código morto. |
/O2 |
Otimizar para velocidade – permite inlining agressivo, otimização de loop, remoção de código morto e transformações relacionadas. |
/link /debug |
Passe /debug para o ligador para gerar informações de depuração (.pdb), que o xperf usa para associar amostras de perfilamento ao código-fonte. |
/spgo |
Sinalizador do vinculador SPGO — insere metadados SPGO no binário e cria um arquivo vazio textCount.spd junto com o executável. |
Note
/spgo é um sinalizador de vinculador. Passe-o para o vinculador via /link /spgo no comando cl.
O /spgo sinalizador ainda não otimiza o binário. Isso o prepara para a análise de desempenho. A otimização ocorre em Rebuild textCount usando /spdin depois que o SPD é preenchido com dados reais de tempo de execução.
Note
Para gravar o SPD em um local específico, adicione o sinalizador do vinculador opcional /spd:<path> . Por exemplo: /link /debug /spgo /spd:.\profiles\textCount.spd. Se você omitir esse sinalizador, o SPD será criado junto com o .exe.
Escolha seu método de criação de perfil
O SPGO dá suporte a três métodos de criação de perfil. Qual método você usa depende do hardware.
Os três métodos de criação de perfil
| Método | Qualidade da amostra | Requisito de hardware | Melhor para |
|---|---|---|---|
| LBR (último registro de ramificação) | Máximo — registra sequências de ramificações executadas recentemente, fornecendo ao otimizador dados detalhados de fluxo de controle por amostra | Intel Haswell (2013) ou posterior; AMD Zen 4 (2022) ou posterior; ARM64 ARMv9.2-A (2020) ou posterior | Hardware de área de trabalho mais moderno |
| Modo PMC / IP (contador de monitoramento de desempenho/ponteiro de instrução) | Bom. Captura amostras do ponteiro de instrução com pilhas de chamadas usando a PMU (Unidade de Monitoramento de Desempenho) da CPU, coletadas por meio do ETW (Rastreamento de Eventos para Windows) | Qualquer CPU x64 ou ARM64 com um PMU | Hardware sem suporte a LBR |
| Temporizador do sistema operacional | Básico — exemplos baseados em temporizador | Qualquer CPU x64 ou ARM64, VMs sem passagem de PMU | VMs e hardware mais antigo |
Com o modo PMC/IP, cada interrupção de hardware fornece apenas um ponto de dados: "a CPU estava no endereço 0x1A2B3C4D quando a interrupção foi disparada". Com o LBR, cada interrupção oferece uma pilha dos últimos 16 a 32 branches que a CPU tomou antes da interrupção ser disparada. O otimizador obtém melhores dados de fluxo de controle e pode tomar melhores decisões de inlining e layout.
Detecte seu caminho
Execute os dois comandos a seguir para determinar qual caminho de criação de perfil seu computador dá suporte. Esses comandos não exigem um prompt elevado.
Etapa 1: verifique se há suporte a LBR. Esse teste funciona no Intel/AMD/ARM64.
Execute o seguinte em um prompt de comando do desenvolvedor administrator Visual Studio:
xperf.exe -on PMC_PROFILE -pmcprofile TotalIssues -LastBranch PmcInterrupt -setProfInt TotalIssues 2560000
xperf -stop -d lbrtest.etl
xperf -tle -i lbrtest.etl -a dumper | findstr "LBR, TimeStamp"
- Se esse comando encontrar uma linha que
LBR, TimeStampcontenha, o computador oferecerá suporte a LBR. Use o caminho LBR. - Caso contrário, continue para a Etapa 2.
Etapa 2: Verificar se há suporte ao PMC (sem LBR)
xperf.exe -pmcsources | findstr TotalIssues
- Se esse comando produzir saída, o computador oferecerá suporte a contadores PMC, mas não a LBR. Use o caminho do PMC.
- Se esse comando não produzir saída, use o caminho do temporizador do sistema operacional.
Para obter mais informações sobre a coleção de eventos PMU com xperf, consulte Gravando eventos de PMU de hardware com xperf.
Tabela de decisão
LBR, TimeStamp saída |
TotalIssues Saída |
Seu caminho |
|---|---|---|
| Não está vazio | (não verificado) | LBR |
| Vazio | Não está vazio | PMC |
| Vazio | Vazio | Temporizador do sistema operacional |
| Processador ARM64 | N/A | PMC (se a PMU estiver disponível) ou temporizador do sistema operacional |
Escolha sua abordagem
Decida se deve usar o caminho do temporizador LBR, PMC ou OS com base nos resultados da detecção. Cada caminho tem parâmetros de início diferentes xperf para coletar os dados de criação de perfil apropriados. Siga o caminho que corresponde às capacidades do seu hardware.
Seu caminho:
- Usuários do LBR (com LBR detectado na Etapa 1): Acesse o caminho do LBR.
- Usuários do PMC (InstructionRetired detectado na Etapa 2): vá para o caminho do PMC (sem LBR).
- Usuários do temporizador do SO (VM ou hardware sem PMU): vá para o caminho do temporizador do SO.
Todos os caminhos convergem em Executar a carga de trabalho e interromper o xperf.
Os comandos nesta seção dependem do caminho de criação de perfil que você identificou em Escolher o método de criação de perfil. Encontre a subseção que corresponde ao seu caminho, execute o comando xperf start e, em seguida, continue em Executar a carga de trabalho e interromper o xperf para executar a carga de trabalho e interromper o xperf.
⚠️ Executar como Administrador:
xperfrequer um prompt de comando de desenvolvedor com privilégios elevados (Administrador). Sem elevação,xperfretorna"failed to configure counters".
Caminho do LBR
Comece xperf com a coleção LBR:
xperf -on LOADER+PROC_THREAD+PMC_PROFILE -MinBuffers 4096 -MaxBuffers 4096 -BufferSize 4096 -pmcprofile BranchInstructionRetired -LastBranch PmcInterrupt -setProfInt BranchInstructionRetired 16384
Explicação do parâmetro:
| Parâmetro | Purpose |
|---|---|
LOADER+PROC_THREAD+PMC_PROFILE |
Provedores do kernel: eventos do carregador (mapeamento de módulo), eventos de processo e thread (contexto de execução) e eventos de profilamento de PMC |
-MinBuffers 4096 -MaxBuffers 4096 -BufferSize 4096 |
Buffers de anéis grandes para evitar amostras descartadas durante uma execução completa de Guerra e Paz |
-pmcprofile BranchInstructionRetired |
Gatilho de evento PMC: gerar um exemplo em cada instrução de ramificação de Nth desativada |
-LastBranch PmcInterrupt |
Habilita a gravação de hardware do LBR: em cada interrupção do PMC, captura a pilha de registros de último desvio do hardware |
-setProfInt BranchInstructionRetired 16384 |
Intervalo de exemplo: disparar uma interrupção a cada 16.384 instruções de ramificação desativadas |
Depois de iniciar o xperf, continue executando a carga de trabalho e interrompa o xperf.
Caminho do PMC (sem LBR)
Inicie xperf com a coleta PMC / modo IP:
xperf -on LOADER+PROC_THREAD+PMC_PROFILE+PROFILE -MinBuffers 4096 -BufferSize 4096 -pmcprofile InstructionRetired -setProfInt InstructionRetired 16384 -stackwalk profile
Explicação do parâmetro:
| Parâmetro | Purpose |
|---|---|
LOADER+PROC_THREAD+PMC_PROFILE+PROFILE |
Adiciona PROFILE (amostragem de CPU) e PMC_PROFILE para eventos PMC; não -LastBranch |
-pmcprofile InstructionRetired |
Gatilho de evento PMC: exemplo em instruções desativadas (modo de ponteiro de instrução) |
-setProfInt InstructionRetired 16384 |
Disparar uma interrupção a cada 16.384 instruções desativadas |
-stackwalk profile |
Capturar uma pilha de chamadas em cada interrupção de perfil, fornecendo dados de cadeia de chamadas em vez de sequências de ramificação |
Comparado ao LBR: sem -LastBranch sinalizador; usa InstructionRetired em vez de BranchInstructionRetired. O resultado são exemplos de ponteiro de instrução com pilhas de chamadas, não sequências de branch. Esse caminho ainda fornece dados úteis para o otimizador, mas é um pouco menos rico.
Depois de iniciar xperf, prossiga para Executar a carga de trabalho e parar o xperf.
Caminho do temporizador do sistema operacional
Inicie o xperf com a amostragem baseada em temporizador do sistema operacional:
xperf -on LOADER+PROC_THREAD+PROFILE -MinBuffers 4096 -BufferSize 4096 -setProfInt Timer 1221 -stackwalk profile
Explicação do parâmetro:
| Parâmetro | Purpose |
|---|---|
LOADER+PROC_THREAD+PROFILE |
Nenhum evento PMC; Amostragem de CPU somente por meio de interrupção do temporizador do sistema operacional |
-setProfInt Timer 1221 |
Acionar a interrupção do temporizador do sistema operacional a cada 1.221 tiques de temporizador (aproximadamente 1 kHz) |
-stackwalk profile |
Capturar uma pilha de chamadas em cada interrupção do temporizador |
Em comparação com LBR e PMC, esse método não usa contadores de desempenho de hardware. O temporizador do sistema operacional é acionado em intervalos de tempo aproximadamente fixos, independentemente da atividade da CPU. Os exemplos são menos densamente correlacionados ao código quente, mas ainda fornecem dados úteis de fluxo de controle para o otimizador.
Executar a carga de trabalho e parar o xperf (todos os caminhos)
Com xperf em execução, execute textCount com Guerra e Paz:
textCount.exe < warAndPeace.txt
Depois que textCount terminar, pare xperf e grave o arquivo de rastreamento. Permitir que outros processos sejam executados durante a criação de perfil dilui a qualidade da amostra. Para obter melhores resultados, feche aplicativos desnecessários antes de executar a carga de trabalho.
xperf -stop -d textCount.etl
Depois de parar xperf (pode demorar um pouco para gravar o arquivo etl), confirme que textCount.etl foi criado no diretório atual.
Converter o arquivo ETL em SPT
Esta etapa é a mesma para todos os três caminhos de criação de perfil.
Execute SPTAggregate.exe para processar o rastreamento ETL bruto e criar um arquivo de perfil SPT:
SPTAggregate.exe /binary textCount.exe /etl textCount.etl textCount.spt
Explicação do parâmetro:
| Parâmetro | Purpose |
|---|---|
/binary textCount.exe |
O binário do qual extrair amostras. O ETL pode conter exemplos de todos os processos executados durante a criação de perfil |
/etl textCount.etl |
Arquivo de rastreamento de entrada do ETL |
textCount.spt |
Arquivo de perfil SPT de saída |
SPTAggregate gera um resumo que mostra quantos exemplos ele coletou. Este resumo é a primeira confirmação de que o profilamento funcionou.
Verifique a saída de SPTAggregate em relação ao caminho que você percorreu:
- Caminho do LBR: Procure uma contagem de amostras LBR usadas diferente de zero.
- Caminho do PMC: Verifique se há um PMC diferente de zero ou uma contagem de amostras de pilha diferente de zero.
- Caminho do temporizador do sistema operacional: Procure uma contagem de exemplos de pilhas usadas sem zero.
Se todas as contagens forem zero, consulte solução de problemas antes de continuar.
Converter o arquivo SPT em SPD
Seu caminho:
- Usuários do LBR (usar
/mode:LBR): modo LBR- Usuários do PMC (usar
/mode:IP): modo IP (PMC e temporizador do SO)- Usuários do timer do SO (use
/mode:IP): Modo IP (PMC e timer do SO)Os caminhos de temporizador do PMC e do sistema operacional são usados
/mode:IPporque ambos produzem exemplos de ponteiro de instrução.
A próxima etapa varia de acordo com o caminho de criação de perfil, especificamente com base na flag /mode passada para SPDConvert.exe.
Modo LBR
SPDConvert.exe /mode:LBR textCount.spd textCount.spt
/mode:LBR instrui SPDConvert a interpretar o SPT como se contivesse dados de sequência de desvios LBR.
Modo IP (PMC e temporizador do sistema operacional)
Tanto o PMC quanto o temporizador do SO produzem amostras do ponteiro de instrução, portanto ambos usam o mesmo comando de conversão:
SPDConvert.exe /mode:IP textCount.spd textCount.spt
/mode:IP instrui SPDConvert a interpretar o SPT como contendo amostras do ponteiro de instruções.
Aviso
Usar o modo errado para o tipo de dados pode produzir um SPD vazio ou malformado. Se você tiver criado o perfil com LBR, use /mode:LBR.
Se você fez o profiling com PMC ou com o temporizador do sistema operacional, use /mode:IP. A SPTAggregate saída resumida de Converter o arquivo ETL em SPT mostra quais tipos de amostra foram coletados e confirma o modo correto que deve ser usado.
Depois de executar SPDConvert, confirme se textCount.spd foi criado (ou atualizado) no diretório atual.
Interpretando a saída do SPDConvert
O comando SPDConvert textCount.spd textCount.spt exibe um resumo da cobertura de blocos antes e depois, por exemplo:
Block coverage (before) : 33.90% ( 4507/ 13294)
Block coverage (after) : 45.64% ( 6067/ 13294)
Este resumo mostra a porcentagem dos blocos de código do binário que têm dados de perfil associados. Uma porcentagem maior é melhor. A cobertura acima de 70% é excelente, enquanto a cobertura abaixo de 40% pode limitar a eficácia da otimização. Se a cobertura for baixa, execute a carga de trabalho de criação de perfil por mais tempo ou combine vários arquivos SPT de execuções separadas com cargas de trabalho diferentes. Por exemplo, você pode executar textCount em vários arquivos de texto para percorrer diferentes caminhos de código.
Você pode ver um aviso de SPDConvert como o seguinte:
Compiler may be conservative on some hot functions due to sparse sample coverage.
SPGO is estimated to optimize better if sample density is increased to 5.4x of current level.
Sample density can be increased by sampling for longer period, or increasing sample rate.
Esse aviso significa que sua execução de profiling não coletou amostras suficientes para que o otimizador pudesse otimizar com confiança todas as funções mais utilizadas. O SPD ainda é utilizável, mas você pode melhorar os resultados:
- Executando a carga de trabalho por mais tempo (por exemplo, 5 ou mais minutos em vez de 1 minuto) ou usando cargas de trabalho diferentes.
- Reduzindo o valor
-setProfIntno comandoxperfpara aumentar a taxa de amostragem. A compensação é que essa alteração produz um arquivo ETL maior, que leva mais tempo para ser processada. - Combinar vários arquivos SPT de execuções de criação de perfil separadas passando todos eles para
SPDConvert.
O arquivo SPT é um formato binário. Para inspecionar seu conteúdo, você pode executar SPTDump.exe textCount.spt. Da mesma forma, PTDump.exe textCount.spt mostra os dados de perfil compilados após a execução SPDConvert. Ambas as ferramentas são úteis para verificar amostras não nulas antes de prosseguir.
Recompilar textCount com /spdin
Recompile textCount usando o arquivo SPD preenchido. O vinculador lê os dados do perfil e aplica otimizações SPGO.
Esta etapa é a mesma para todos os três caminhos de criação de perfil.
cl /EHsc /GL /O2 textCount.cpp /link /debug /spgo /spdin:textCount.spd
Novo sinalizador (comparado ao Build textCount com /spgo):
| Flag | Purpose |
|---|---|
/spdin:textCount.spd |
Fornecer os dados de perfil SPD ao linker para otimização |
O comando ainda inclui /spgo. Ele gera um novo arquivo SPD junto com o binário otimizado, que você pode usar como ponto de partida para iterações de criação de perfil subsequentes.
Aviso
O arquivo SPD está associado ao binário exato para o qual ele gera perfis. Se você recompilar textCount sem /spdin ou recompilar a partir do código-fonte alterado, deverá gerar um novo arquivo SPD. O existente não corresponde ao GUID do novo binário e o vinculador não o usará.
Após a recompilação com /spdin, o linkador gera estatísticas sobre quanto do seu código foi otimizado com base em dados de perfil. Por exemplo:
221 of 221 (100.00%) profiled functions will be compiled for speed
201 of 1383 inline instances were from dead/cold paths
474 of 474 profiled functions (100.0%) were optimized using profile data
202738780 of 202738780 instructions (100.0%) were optimized using profile data
Uma porcentagem alta significa que o SPD abrange bem o seu binário. Se o percentual for baixo (por exemplo, abaixo de 90%), ou a carga de trabalho usada para coletar o perfil não cobriu uma parte suficiente do binário, ou o binário foi alterado significativamente desde que o perfil foi coletado. Em ambos os casos, reprofile-se em relação ao binário atual.
O que o SPGO faz com seus dados de perfil
O SPGO usa os dados de amostra coletados para preencher as contagens em cada bloco e aresta no grafo de fluxo de controle do programa. Essas contagens orientam otimizações como:
- Inlining guiado por perfil: faz inline agressivamente de locais de chamada quentes, evitando o aumento de código causado pelo inline de caminhos frios.
- Separação de código quente/frio: mova o código raramente executado para separar seções do binário, melhorando a utilização e o comportamento de paginação do cache de instruções.
- Organização das funções: coloque funções que chamam umas às outras com frequência próximas entre si no binário, reduzindo faltas de página e melhorando a localidade. As funções otimizadas são organizadas em grupos COFF de alta afinidade no binário.
- Decisões de tamanho/velocidade: Compile funções frequentemente usadas para velocidade e funções raramente usadas para tamanho. Rotinas sem acessos registrados no perfil podem ser compiladas para reduzir o tamanho em vez de priorizar a velocidade, limitando otimizações como inlining e loop unrolling nesses trechos raramente executados.
- Desvirtualização especulativa: quando a amostragem revela que uma chamada indireta aponta de forma consistente para a mesma função, o SPGO pode assumir especulativamente esse destino e inseri-la em linha, com uma alternativa de segurança para o caso incomum.
Medir os resultados
Execute textCount novamente e compare os tempos decorridos.
textCount.exe < warAndPeace.txt
Colete várias execuções para cada configuração e use a mediana. Uma única execução não é confiável porque o agendamento do sistema operacional e o ruído do sistema podem distorcer medidas individuais.
| Build | Tempo decorrido representativo |
|---|---|
Linha de referência (cl /EHsc /O2) |
(sua medida) |
/spgo compilação (ainda não há dados de criação de perfil) |
(deve estar perto da linha de base) |
Otimizado para SPGO (/spdin) |
(deve mostrar melhoria) |
Em um teste, o SPGO, usando o método LBR, proporcionou uma redução de aproximadamente 7% no tempo decorrido. Seus resultados podem variar nos seus próprios projetos, pois os ganhos do SPGO dependem de quão bem a carga de trabalho usada para criação de perfil representa o comportamento típico de execução. Bases de código maiores e preenchidas por ramificação tendem a ver mais melhorias dentro do intervalo de 5 a 10%. O método de criação de perfil afeta a qualidade da otimização. O LBR normalmente produz melhores resultados do que o PMC, que produz melhores resultados do que o temporizador do sistema operacional. Se você estiver no modo do temporizador do sistema operacional, espere ganhos menores.
O caminho LBR seguido neste tutorial foi aplicado ao projeto SQLite , que é uma biblioteca de banco de dados de produção. O binário SQLite otimizado para SPGO mostrou aproximadamente uma melhoria de 7%.
Aplicar O SPGO ao seu próprio projeto
Use essa lista de verificação para aplicar o SPGO ao seu próprio aplicativo C ou C++.
Adicione
/link /spgoao comando de build de versão existente. Modifique o script de build ou o arquivo de projeto:cl /EHsc /GL /O2 myapp.cpp /link /spgoEscolha uma carga de trabalho representativa. Selecione um cenário de uso real que exerça os caminhos críticos da sua aplicação. Use dados similares aos de produção. Evite usar os itens a seguir como principal carga de trabalho para análise de desempenho: testes de cobertura de código (eles não exercitam os gargalos de desempenho), fluxos de erro incomuns, fases de inicialização e desligamento e caminhos de código obsoletos. Essa carga de trabalho impulsiona o perfil que alimenta o otimizador.
Execute xperf usando o caminho detectado. Use o caminho que você identificou em Escolher seu método de criação de perfil (LBR, PMC ou temporizador do sistema operacional). Inicie
xperf, execute a carga de trabalho uma vez, parexperfe capture o arquivo ETL.Para o caminho do timer PMC ou OS, execute o SPTAggregate e o SPDConvert com a flag correta
/mode. Converta ETL em SPT e, em seguida, em SPD. Use/mode:LBRpara dados de LBR; use/mode:IPpara dados do temporizador do PMC ou do sistema operacional.Reconstruir com
/spdin:<your-spd-path>. Compile seu aplicativo com o SPD preenchido:cl /EHsc /GL /O2 yourApp.cpp /link /spgo /spdin:yourApp.spdMedir antes e depois. Execute sua carga de trabalho com os binários não otimizados e os binários otimizados com SPGO. Colete a mediana de várias execuções para cada configuração. Uma única execução não é confiável para o benchmarking.
Armazene o
.spdarquivo no controle de versão. Verifique o.spdarquivo em seu sistema de controle do código-fonte junto com o código-fonte.Habilite o SPGO em compilações Release para desenvolvedores. Faça com que as compilações de release da sua equipe usem os mesmos binários otimizados com SPGO usados em produção. Isso ajuda a capturar regressões de desempenho antecipadamente.
Desative o SPGO em compilações de depuração.
Acompanhe as estatísticas de preenchimento do perfil do vinculador. Após cada build com
/spgo, observe a porcentagem de funções com perfil otimizadas usando dados de perfil. Se isso cair significativamente (abaixo de 90%), reprofile o binário atual. As alterações de código se acumulam e o SPD pode ficar obsoleto.
Alternativa ao uso xperf
Outra maneira de coletar dados de perfil é usar um criador de perfil de amostragem como o WPR (Gravador de Desempenho Windows). O WPR é instalado por padrão em Windows 10 e posterior. Ele coleta dados semelhantes a xperf. Você pode configurar o WPR para coletar amostras de CPU com pilhas de chamadas e, em seguida, exportar os dados para um arquivo ETL que pode ser processado com SPTAggregate e SPDConvert, como o ETL xperf. Aqui está um exemplo de como usar a WPR para coletar dados de perfil:
wpr -start CPU.light -filemode
textCount.exe < warAndPeace.txt
wpr -stop spgo_data.etl
Para obter mais informações sobre como usar a WPR, consulte Using Windows Performance Recorder.
Distribuição SPD
É possível:
- Faça check-in do arquivo
.spddiretamente no controle de versão junto com o seu código-fonte. - Compartilhe o arquivo
.spdcom colegas para que eles possam compilar com otimizações SPGO sem precisar refazer o perfilamento. - Empacote o
.spdarquivo com seus binários como um artefato com versão (por exemplo, um pacote NuGet) e registre qual versão corresponde a qual binário. - Regenerar o arquivo
.spda qualquer momento repetindo o fluxo de trabalho de perfilamento.
O SPD liga-se ao binário exato do qual foi construído. Após alterações significativas de código, reprofile para gerar um SPD novo. Durante o /spdin build, o compilador também produz um novo .spd arquivo. Salve este novo SPD como um artefato de build - é o ponto de partida para sua próxima iteração de criação de perfil.
Reutilização de informações de SPD entre compilações
O conceito de "carry forward" no SPGO permite adicionar dados de perfil a um arquivo SPD existente sem precisar refazer do zero a criação de perfil de todos os seus cenários e sem perder as informações de perfil existentes. Você também pode ajustar quanto peso atribuir aos dados de perfil mais antigos. Essa flexibilidade é útil quando pode haver mudanças de comportamento ao longo do tempo e você não quer perder completamente as informações de perfil das execuções anteriores de cenários. Por exemplo, uma DLL pode ter diferentes APIs chamadas à medida que o aplicativo que a chama evolui. Você ainda quer as otimizações da forma como ele se comportava antes, mas também quer combinar isso com oportunidades de otimização para os casos em que agora ele às vezes se comporta de maneira diferente. Você pode evoluir o perfil ao longo do tempo misturando dados antigos e novos.
Ao executar SPDConvert com um novo arquivo SPT, passe o nome do arquivo SPD existente. Em seguida, use a opção /retire:N para controlar quão agressivamente SPDConvert reduz a ênfase nos dados de perfil mais antigos ao adicionar novos arquivos SPT:
- O padrão (
/retire:8) pondera dados mais recentes com mais peso. - Use
/retire:0para atribuir o mesmo peso a todas as execuções. - Use
/retire:16para permitir apenas a contagem de dados mais recente.
Solução de problemas
Encontre seu problema:
- Problemas no caminho LBR:problemas no caminho LBR
- Problemas de caminho do PMC:problemas de caminho do PMC
- Problemas de temporizador do sistema operacional:problemas de caminho do temporizador do sistema operacional
- Problemas que afetam todos os caminhos:Problemas gerais
Problemas de caminho LBR
| Problema | Causa provável | Corrigir |
|---|---|---|
Nenhuma amostra de LBR na saída SPTAggregate |
A CPU não dá suporte a LBR ou a VM não expõe LBR | Execute o comando de detecção a partir de Detect your path. Se estiver em uma VM Hyper-V, execute Set-VMProcessor MyVMName -Perfmon @("pmu", "lbr") no host. Se o LBR não estiver disponível, mude para o uso do PMC ou do temporizador do sistema operacional. |
O processador dá suporte a LBR, mas SPTAggregate mostra 0 amostras de LBR |
perfcore.ini Registro de DLL incompleto |
Conclua a perfcore.ini configuração em Configurar perfcore.ini. Verifique se perf_lbr.dll está registrado. |
SPDConvert falha ou produz um SPD vazio |
Sinalizador incorreto /mode ou SPT contém apenas exemplos de modo IP |
Confirme que a saída SPTAggregate exibiu amostras de LBR. Se a saída mostrar apenas exemplos de modo IP, alterne para /mode:IP. |
Problemas no caminho do PMC
| Problema | Causa provável | Corrigir |
|---|---|---|
Nenhuma amostra de PMC na saída SPTAggregate |
perfcore.ini Registro de DLL incorreto |
Conclua a perfcore.ini configuração em Configurar perfcore.ini. Verifique se perf_spt.dll está registrado. Sem essa DLL, xperf produz zero exemplos de PMC sem uma mensagem de erro.Execute xperf.exe -pmcsources para ver a lista de fontes de Contadores de Desempenho disponíveis em sua CPU. Se você não vir entradas como SPT_OP_RETIRE_INSTR ou SPT_OP_RETIRE_BR_INSTR ou SPT_OP_ETW_INSTR, o registro de perfcore.ini DLL pode estar incompleto ou sua CPU pode não dar suporte ao PMC. Se você não conseguir corrigir o registro da DLL, tente usar o temporizador do sistema operacional, em vez disso. |
findstr InstructionRetired retorna a saída, mas xperf não produz exemplos |
Contadores PMC com mascaramento de VM | Verifique se está em execução em uma VM. Habilite a PMU no Hyper-V com Set-VMProcessor ou mude para o caminho do temporizador do SO. |
SPDConvert falha no caminho do PMC |
Usando /mode:LBR em um SPT somente IP |
Mudar para /mode:IP. |
Problemas de caminho do temporizador do sistema operacional
| Problema | Causa provável | Corrigir |
|---|---|---|
| Melhoria menor do que o esperado | Esperado – o temporizador do sistema operacional tem menor precisão | Isto é normal. O otimizador tem menos informações de fluxo de ramificação de exemplos de temporizador do que de LBR ou PMC. Os ganhos de desempenho são menores. Considere atualizar para PMC ou LBR se o hardware der suporte a ele. |
| Exemplos de temporizador zero |
xperf não foi executado em um prompt elevado ou o provedor PROFILE está ausente |
Confirme a execução como Administrador. Confirme se -stackwalk profile foi fornecido para o comando xperf. |
Problemas gerais (todos os caminhos)
| Problema | Causa provável | Corrigir |
|---|---|---|
"failed to configure counters" erro |
xperf não está sendo executado como administrador |
Reinicie o prompt de comando como Administrador (clique com o botão direito do mouse > em Executar como administrador). O xperf requer privilégios elevados para configurar contadores de desempenho de hardware. |
xperf não encontrado |
xperf.exe não está no PATH |
Confirme se o ADK do Windows está instalado. Verifique C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\. Adicione esse diretório ao SEU PATH ou execute o xperf diretamente. |
textCount.etl não foi criado |
o xperf falhou silenciosamente | Confirme a execução como administrador. Execute o comando `xperf start` novamente e verifique se há mensagens de erro. |
SPTAggregate falha com "binário não encontrado" |
textCount.exe não no diretório atual ou no caminho errado |
Confirme se você está no mesmo diretório textCount.exeou forneça o caminho completo para o /binary parâmetro. |
| Arquivo SPD não criado |
SPDConvert Falhou |
Verifique se o textCount.spt tamanho não é zero. Execute SPTDump.exe textCount.spt para inspecionar seu conteúdo. |
/spdin build não produz nenhuma melhoria |
Incompatibilidade GUID/idade entre SPD e binário | O SPD foi construído a partir de um textCount.exe diferente. Crie o perfil do build atual novamente para gerar um SPD novo. |
Erro de versão do MSVC em /spgo |
Conjunto de ferramentas MSVC anterior à v14.51 | Abra o Visual Studio Installer >Componentes individuais> e instale o MSVC v14.51 ou versão posterior. Reabra o prompt de comando do desenvolvedor. |
Próximas Etapas
Depois de concluir este tutorial, explore esses recursos para obter mais do SPGO:
-
Mesclagem de perfis: Execute várias cargas de trabalho, acumule arquivos SPT de cada execução e passe todos para
SPDConvert. Um SPD combinado reflete toda a gama de padrões de uso reais e produz otimizações melhores do que um perfil de cenário único. Use a opção/retire:Npara controlar com que intensidadeSPDConvertreduz a ênfase nos dados de perfil mais antigos quando você adiciona novos arquivos SPT. O padrão (/retire:8) pondera dados mais recentes com mais peso. Use/retire:0para dar peso igual a todas as execuções; use/retire:16para permitir apenas a contagem de dados mais recente. - Os melhores resultados vêm da mesclagem de perfis de várias fontes, como parâmetros de comparação que enfatizam cenários-chave mais dados do mundo real (quando disponíveis). Passe arquivos SPT de todas as fontes para
SPDConvert. Repita um arquivo SPT na lista de argumentos para dar mais peso (por exemplo,SPDConvert myapp.spd critical.spt critical.spt common.sptpesacritical.sptduas vezes maiscommon.spt). -
Otimização iterativa: Cada recompilação com
/spdinproduz um novo SPD. Você pode repetir o ciclo de execução, criação de perfil e recompilação. Iterações posteriores podem apresentar retorno decrescente, mas uma segunda passada às vezes pode captar padrões que a primeira não identificou. - Alterações de código: Após alterações significativas no código-fonte, colete novamente os dados de perfil. O SPD existente está vinculado ao binário com base no qual foi perfilado. Ele não corresponderá a um binário substancialmente reconstruído.
-
Atualidade do perfil: O vinculador informa a porcentagem de funções perfiladas otimizadas usando dados de perfil após cada
/spdincompilação. Se essa porcentagem cair significativamente, é um sinal de que o código divergiu do perfil. Refaça o perfil do binário atual.