Oharra
Baimena behar duzu orria atzitzeko. Direktorioetan saioa has dezakezu edo haiek alda ditzakezu.
Baimena behar duzu orria atzitzeko. Direktorioak alda ditzakezu.
La optimización guiada por perfiles (PGO) usa datos en tiempo de ejecución para ayudar al compilador a tomar mejores decisiones de optimización. Mediante el uso de datos de perfil de ejecución recopilados de cargas de trabajo representativas, PGO permite al compilador tomar decisiones más inteligentes sobre la inserción, el diseño de código y la separación de código en caliente o en frío. Estas decisiones son imposibles de tomar solo a partir del análisis estático.
SPGO adopta un enfoque diferente. En lugar de instrumentar el archivo binario y someterlo a escenarios sintéticos de entrenamiento, SPGO utiliza el muestreo de contadores de rendimiento del hardware obtenido de tus binarios reales de lanzamiento. Los procesadores modernos proporcionan funcionalidades de muestreo de hardware. Puede recopilar estos ejemplos con una sobrecarga en tiempo de ejecución insignificante, lo que facilita la recopilación de perfiles de tiempo de ejecución directamente desde el código de producción.
Dado que los perfiles de SPGO liberan bits en lugar de compilaciones instrumentadas, permite mucha más flexibilidad en dónde y cómo se recopilan datos. Puede recopilar perfiles en tiempo de ejecución de servidores de producción, máquinas para desarrolladores, laboratorios de rendimiento o cualquier combinación. El resultado es un binario que ejecuta las rutas críticas de forma más eficiente, con una mejora típica del rendimiento de entre un 5 % y un 15 %, en función de la calidad de los datos de perfil.
En este tutorial, se recorre el flujo de trabajo completo de SPGO: compilar una aplicación de ejemplo, crear un perfil de ella con xperf, preparar los datos del perfil y volver a compilarla con esos datos. Cuando termine, puede aplicar el mismo proceso a sus propios proyectos.
Prerequisites
Antes de empezar, asegúrese de que tiene el siguiente software y hardware.
Software
- Herramientas de compilación de MSVC para x64/x86/ARM64 v14.51 o posterior: instálalas mediante el Instalador de Visual Studio. En Componentes individuales, busque "Herramientas de compilación de MSVC".
-
Windows Performance Toolkit (xperf.exe): el generador de perfiles de
xperfrecopila datos de ejemplo durante la ejecución del programa. Descargue el kit de evaluación e implementación de Windows (ADK) de ADK install. Al ejecutar el instalador de ADK, seleccione el componente Windows Performance Toolkit para obtenerxperf. No es necesario instalar el ADK completo. - Archivo de texto de Guerra y paz—Se utiliza como carga de trabajo de ejemplo para generar datos de perfilado. Descárguelo de Project Gutenberg: https://www.gutenberg.org/ebooks/2600. Guárdelo como un archivo de texto sin formato en el directorio de trabajo.
Requisitos de hardware
El tutorial tiene tres rutas de generación de perfiles. La ruta de acceso que use depende del hardware. Los comandos de detección se ejecutan en Elegir el método de generación de perfiles para averiguar qué ruta de acceso admite la máquina. Por ahora, use esta tabla para confirmar que cumple al menos uno de los requisitos.
| Path | Requisito de CPU | Notas |
|---|---|---|
| LBR (mejores resultados) | Los últimos registros de rama (LBR) son contadores de rendimiento proporcionados en CPU de Intel Haswell (4ª generación Core, 2013) o posterior; AMD Zen 4 (2022) o posterior, ARM64 ARMv9.2-A (2020) o posterior | Proporciona los mejores datos de rama. Para obtener más información sobre LBR, consulte Introducción a los últimos registros de rama. |
| Modo PMC/IP (buenos resultados) | Los contadores de supervisión de rendimiento (PMC) se admiten en cualquier CPU x64 con una unidad de supervisión de rendimiento (PMU) | Funciona en las CPU más modernas en las que LBR no está disponible. Para obtener más información acerca de PMC, vea Grabación de eventos de rendimiento de hardware (PMU) y grabación de eventos de rendimiento de hardware (PMU) con ejemplos completos |
| Temporizador del sistema operativo (funciona en todas partes) | Cualquier CPU x64 o ARM64, incluidas las máquinas virtuales y las máquinas virtuales de Azure | Ejemplos de menor fidelidad, pero siempre disponibles |
La mayoría de los desarrolladores del hardware de escritorio x64 moderno tienen compatibilidad con LBR. Las máquinas virtuales y algún hardware anterior tienen PMC o un temporizador del sistema operativo.
Funcionamiento de SPGO
SPGO recoge datos de perfil de su binario en ejecución y se los proporciona al compilador la próxima vez que compile. El compilador usa esos datos para tomar mejores decisiones sobre la inserción, el diseño de código y la predicción de rama. Una comodidad es que no se requiere instrumentación.
El flujo de trabajo es:
- Compile el archivo binario con la marca del enlazador /spgo . Este paso crea una base de datos de perfil de ejemplo vacía (
.spdarchivo). - Genere un perfil del binario mediante
xperfpara producir un archivo de traza ETL. - Convierta el ETL en un archivo SPT mediante
SPTAggregate.exey, a continuación, convierta el SPT en un archivo SPD medianteSPDConvert.exe. - Vuelva a compilar con la opción del enlazador /spdin que apunte a la base de datos de perfiles de ejemplo rellena (SPD). El enlazador aplica optimizaciones de SPGO.
El optimizador usa el SPD para responder a preguntas como: ¿qué ramas se toman con más frecuencia? ¿Qué funciones se llaman en bucles activos? Este proceso genera un mejor diseño de código y decisiones de inserción que el análisis estático por sí solo.
SPGO funciona con C y C++. El flujo de trabajo y las marcas son idénticos para ambos idiomas.
Los mejores candidatos para SPGO: Aplicaciones C/C++ grandes, con abundantes bifurcaciones y bucles internos muy optimizados. Los beneficios aumentan con el tamaño de la base de código y la complejidad de las ramas. La pequeña muestra de este tutorial muestra una mejora de alrededor del 7 %. Los códigos base de producción más grandes a menudo ven más mejoras.
Comparación de procesos de compilación
En esta sección se explica cómo encaja SPGO en el flujo de compilación si quiere entender cómo funciona.
Proceso de compilación normal
En una compilación estándar de lanzamiento de C/C++:
-
Entradas: Archivos de código fuente (
.cpp,.h) y marcas del compilador en modo de versión (/O2,/GL, etc.). - Proceso: El compilador aplica optimizaciones estándar, como la inclusión de heurística, suposiciones de predicción de rama y decisiones de diseño de código basadas solo en el análisis estático. No tiene datos sobre cómo se comporta realmente el programa cuando se ejecuta.
-
Salida: Ejecutable (
.exe), archivos DLL (.dll), información de depuración (.pdb).
Sin datos en tiempo de ejecución, las rutas de acceso activas y las rutas de acceso inactivas reciben un tratamiento similar.
Proceso de compilación con SPGO habilitado
SPGO agrega datos de generación de perfiles como una nueva entrada a la canalización de compilación:
-
Entradas: código fuente, el archivo de perfil
.spd(recuentos de muestras de una ejecución de perfilado), opciones del compilador para el modo de publicación,/link /spgoy/spdin:<path>para especificar un archivo SPD de entrada (si no se especifica, de forma predeterminada se usa un archivo .spd con el nombre del binario y ubicado en la carpeta obj). - Proceso: El enlazador lee el SPD junto con el código intermedio. Se sirve de datos sobre la frecuencia de las bifurcaciones para tomar mejores decisiones sobre la expansión en línea, la disposición del código y el orden de las bifurcaciones. Las funciones más utilizadas se organizan para un acceso rápido; el código menos utilizado se aparta de la ruta crítica.
-
Salida: Ejecutable optimizado (), archivos DLL optimizados (
.exe.dll), información de depuración (.pdb) y un nuevo.spdarchivo para futuras iteraciones de generación de perfiles.
La idea clave: SPGO traslada las decisiones de optimización de las heurísticas del compilador y del enlazador a decisiones basadas en datos y en la ejecución real.
Indicadores clave
| Flag | Tipo | propósito |
|---|---|---|
/spgo |
Linker | Habilita SPGO. Inserta metadatos de SPGO en el binario y crea un archivo de salida vacío .spd a menos /spdin que se especifique, en cuyo caso se usa el archivo especificado .spd como entrada. |
/spdin:<path> |
Linker | SPD de entrada: proporciona datos de perfil al enlazador para la optimización. |
/spd:<path> |
Linker | Ruta de salida del SPD: especifica dónde se escribe el nuevo SPD (opcional; el directorio predeterminado es el mismo que el del archivo binario). Actúa como la ruta de entrada de SPD si no se especifica /spdin. |
/GL |
Compilador | Se requiere la optimización de todo el programa para que SPGO funcione entre unidades de traducción |
/O1, /O2 (Minimizar tamaño, Maximizar velocidad) |
Compilador | Optimizar la velocidad; permite optimizaciones agresivas que SPGO puede mejorar |
Diferencias entre SPGO y PGO
La PGO (optimización guiada por perfiles) requiere que compile su binario con indicadores de instrumentación (/GENPROFILE), ejecute el binario instrumentado, que es más lento, para recopilar archivos .pgc de recuento de ejecución y, a continuación, vuelva a enlazar con /USEPROFILE. El compilador obtiene recuentos exactos de ejecución, pero primero tiene que instrumentar el código. Para obtener más información sobre este proceso, consulte Optimizaciones guiadas por perfiles.
SPGO usa contadores de rendimiento de hardware de la CPU para recopilar muestras estadísticas a partir de su binario de lanzamiento sin instrumentar. Ejecute el binario existente, genérele un perfil mediante xperf, convierta la traza en un archivo SPD y vuelva a compilar. No hay ninguna compilación instrumentada ni ralentización durante la generación de perfiles. El compilador obtiene datos de muestreo estadísticos en lugar de recuentos exactos, lo que es menos preciso pero más fácil de obtener y no requiere ningún cambio de código. También permite el perfilado de componentes del sistema o de componentes en tiempo real de los que resulta difícil recopilar datos mediante un enfoque instrumentado. También puede generar perfiles de archivos binarios finales o de envío.
En este tutorial se tratan tres métodos de generación de perfiles: LBR, PMC y temporizador del sistema operativo. Elija el método en Elegir el método de generación de perfiles. Para obtener una comparación detallada del proceso de compilación normal frente al proceso de compilación de SPGO, incluida una tabla de referencia de marcas, consulte Comparación de procesos de compilación.
Configurar perfcore.ini
⚠️ Obligatorio: sin este paso,
xperfno proporciona los datos de generación de perfiles necesarios. Complete este paso antes de ejecutarxperf.
Windows Performance Toolkit (WPT) usa perfcore.ini, que, si instaló WPT en la ubicación predeterminada, se encuentra en C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\perfcore.ini, para registrar los proveedores DLL que necesita para SPGO.
Abra Windows Bloc de notas como administrador. A continuación, abra perfcore.ini. Busque la sección lista dll y agregue las siguientes entradas, una por línea:
perf_spt.dll
perf_lbr.dll
Si xperf.exe no está instalado, consulte Problemas generales para instalarlo.
Guarde y cierre perfcore.ini. Los archivos DLL ya se incluyen en el mismo directorio, xperf.exe por lo que no es necesario copiarlos en ningún lugar. Solo los va a registrar en perfcore.ini. Asegúrese de que xperf está en la ruta de acceso.
Crear la aplicación de ejemplo
La aplicación de ejemplo de este tutorial es un programa de C++ que lee texto de la entrada estándar y genera un recuento de líneas, recuento de palabras, recuento total de caracteres, una tabla de frecuencia de caracteres y tiempo transcurrido para procesar el archivo en milisegundos. Está escrito en C++, pero SPGO también funciona con C. El flujo de trabajo es idéntico para los proyectos de C.
Cree un archivo denominado textCount.cpp en el directorio de trabajo y agregue el código fuente siguiente:
// 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;
}
Compilación y ejecución del ejemplo para obtener una línea base
Antes de aplicar SPGO, compile textCount y ejecútelo en un archivo de texto grande, como War and Peace (puede descargarlo desde Project Gutenberg), para ver lo rápido que se ejecuta. En este paso se muestra el rendimiento antes de optimizarlo mediante SPGO:
Compilación:
cl /EHsc /GL /O2 textCount.cpp
Ejecutar:
textCount.exe < warAndPeace.txt
Verá una salida similar a la siguiente:
=== TEXT STATISTICS ===
Lines: 66041
Words: 566333
Total Characters: 3227531
=== CHARACTER FREQUENCIES ===
Letters:
a: 202719
...
Elapsed time: 512.000 ms
Tome nota del valor Elapsed time. Lo comparará con el tiempo optimizado con SPGO en Medir los resultados.
Compilación de textCount con /spgo
Ahora compile textCount con SPGO habilitado. Este paso establece la base para recopilar datos de generación de perfiles.
cl /EHsc /GL /O2 textCount.cpp /link /debug /spgo
Cuando finalice la compilación, verá un mensaje similar al siguiente:
SPD textCount.spd not found, compiling without profile guided optimizations
Este mensaje aparece en la primera /spgo compilación. El enlazador crea el archivo SPD, pero todavía está vacío, por lo que aún no aplica ninguna optimización de SPGO. Después de ejecutar el archivo binario, recopilar datos de perfil y convertirlos en SPD, no verá este mensaje.
Explicaciones de marcas:
| Flag | propósito |
|---|---|
/EHsc |
Habilitación del control de excepciones de C++ |
/GL |
Optimización de todo el programa: necesaria para SPGO. Aplaza la optimización final hasta el momento del enlazado, permitiendo la expansión en línea entre módulos, la disposición del código y la eliminación de código muerto. |
/O2 |
Optimizar para velocidad — permite la integración agresiva, la optimización de bucles, la eliminación de código muerto y otras transformaciones relacionadas. |
/link /debug |
Pase /debug al enlazador para generar información de depuración (.pdb), que xperf usa para asociar las muestras de generación de perfiles con el código fuente. |
/spgo |
Marca del enlazador de SPGO: inserta metadatos de SPGO en el binario y crea un archivo vacío textCount.spd junto con el ejecutable. |
Note
/spgo es una marca del enlazador. Páselo al enlazador mediante /link /spgo en el comando cl.
La /spgo marca aún no optimiza el archivo binario. Lo prepara para la generación de perfiles. La optimización se produce en Recompilar textCount con /spdin después de que el SPD se rellene con datos en tiempo de ejecución reales.
Note
Para escribir el SPD en una ubicación específica, añada el indicador opcional del enlazador /spd:<path>. Por ejemplo: /link /debug /spgo /spd:.\profiles\textCount.spd. Si omite esta marca, el SPD se crea junto a .exe.
Elección del método de generación de perfiles
SPGO admite tres métodos de generación de perfiles. El método que use depende del hardware.
Los tres métodos de generación de perfiles
| Método | Calidad de la muestra | Requisito de hardware | Más adecuado para |
|---|---|---|---|
| LBR (último registro de rama) | Más alto: registra secuencias de ramas tomadas recientemente, lo que proporciona al optimizador datos enriquecidos de flujo de control por ejemplo. | Intel Haswell (2013) o posterior; AMD Zen 4 (2022) o posterior; ARM64 ARMv9.2-A (2020) o posterior | Hardware de escritorio más moderno |
| Modo PMC / IP (modo de contador de monitorización del rendimiento/puntero de instrucción) | Bueno. Captura muestras del puntero de instrucción con pilas de llamadas mediante la unidad de supervisión del rendimiento (PMU) de la CPU, recopiladas a través de Event Tracing for Windows (ETW) | Cualquier CPU x64 o ARM64 con una PMU | Hardware sin compatibilidad con LBR |
| Temporizador del sistema operativo | Básico: ejemplos basados en temporizador | Cualquier CPU x64 o ARM64, máquinas virtuales sin acceso directo de PMU | Máquinas virtuales y hardware anterior |
Con el modo PMC/IP, cada interrupción de hardware le proporciona solo un punto de datos: "la CPU estaba en la dirección 0x1A2B3C4D cuando se desencadenó la interrupción". Con LBR, cada interrupción te da una pila de los últimos 16–32 saltos que realizó la CPU antes de que se produjera la interrupción. El optimizador obtiene mejores datos de flujo de control y puede tomar mejores decisiones de inserción y diseño.
Detecta tu ruta
Ejecute los dos comandos siguientes para determinar qué ruta de generación de perfiles admite la máquina. Estos comandos no requieren un símbolo del sistema con privilegios elevados.
Paso 1: Comprobar la compatibilidad con LBR. Esta prueba funciona en Intel/AMD/ARM64.
Ejecute lo siguiente desde un símbolo del sistema para desarrolladores de Visual Studio como administrador:
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"
- Si este comando encuentra una línea que contiene
LBR, TimeStamp, la máquina admite LBR. Use la ruta de LBR. - De lo contrario, continúe con el paso 2.
Paso 2: Comprobar la compatibilidad con PMC (sin LBR)
xperf.exe -pmcsources | findstr TotalIssues
- Si este comando genera resultados, la máquina admite contadores PMC, pero no LBR. Use la ruta PMC.
- Si este comando no genera ninguna salida, entonces use la ruta de acceso del temporizador del sistema operativo.
Para obtener más información sobre la recopilación de eventos PMU con xperf, consulte Grabación de eventos PMU de hardware con xperf.
Tabla de decisión
LBR, TimeStamp salida |
TotalIssues salida |
Tu ruta |
|---|---|---|
| No está vacío | (no activado) | LBR |
| Vacía | No está vacío | PMC |
| Vacía | Vacía | Temporizador del sistema operativo |
| Procesador ARM64 | N/A | PMC (si PMU está disponible) o temporizador del sistema operativo |
Elección del enfoque
Decida si usar la ruta del temporizador LBR, PMC u OS según los resultados de la detección. Cada ruta de acceso tiene parámetros de inicio diferentes xperf para recopilar los datos de generación de perfiles adecuados. Siga la ruta que coincida con las capacidades de su hardware.
Ruta de acceso:
- Usuarios de LBR (LBR detectado en el paso 1): vaya a ruta de LBR.
- Usuarios de PMC (InstructionRetired detectado en el paso 2): vaya a ruta de acceso de PMC (sin LBR).
- Usuarios del temporizador del sistema operativo (VM o hardware sin PMU): vayan a la ruta del temporizador del sistema operativo.
Todos los caminos convergen de nuevo en Ejecutar la carga de trabajo y detener xperf.
Los comandos de esta sección dependen de la ruta de generación de perfiles que identificó en Elegir el método de generación de perfiles. Busque la subsección que corresponda a su ruta, ejecute el comando xperf start y, a continuación, continúe con Ejecutar la carga de trabajo y detener xperf para ejecutar la carga de trabajo y detener xperf.
⚠️ Ejecutar como administrador:
xperfrequiere un símbolo del sistema para desarrolladores con privilegios elevados (Administrador). Sin elevación,xperfdevuelve"failed to configure counters".
Ruta LBR
Comience xperf con la colección LBR:
xperf -on LOADER+PROC_THREAD+PMC_PROFILE -MinBuffers 4096 -MaxBuffers 4096 -BufferSize 4096 -pmcprofile BranchInstructionRetired -LastBranch PmcInterrupt -setProfInt BranchInstructionRetired 16384
Explicación de parámetros:
| Parámetro | propósito |
|---|---|
LOADER+PROC_THREAD+PMC_PROFILE |
Proveedores de kernel: eventos del cargador (asignación de módulos), eventos de proceso o subproceso (contexto de ejecución) y eventos de generación de perfiles de PMC |
-MinBuffers 4096 -MaxBuffers 4096 -BufferSize 4096 |
Búferes circulares grandes para evitar la pérdida de muestras durante una ejecución completa de Guerra y paz |
-pmcprofile BranchInstructionRetired |
Desencadenador de eventos PMC: genere un ejemplo en cada instrucción de rama retirada de Nth. |
-LastBranch PmcInterrupt |
Habilita la grabación de hardware LBR: en cada interrupción de PMC, capture la pila de registros de última rama de hardware. |
-setProfInt BranchInstructionRetired 16384 |
Intervalo de ejemplo: activar una interrupción cada 16 384 instrucciones de rama retirada |
Después de iniciar xperf, continúe ejecutando la carga de trabajo y detenga xperf.
Ruta PMC (no LBR)
Inicie xperf con la recopilación en modo PMC/IP:
xperf -on LOADER+PROC_THREAD+PMC_PROFILE+PROFILE -MinBuffers 4096 -BufferSize 4096 -pmcprofile InstructionRetired -setProfInt InstructionRetired 16384 -stackwalk profile
Explicación de parámetros:
| Parámetro | propósito |
|---|---|
LOADER+PROC_THREAD+PMC_PROFILE+PROFILE |
Agrega PROFILE (muestreo de CPU) y PMC_PROFILE para eventos PMC; no -LastBranch |
-pmcprofile InstructionRetired |
Desencadenador de eventos PMC: ejemplo en instrucciones retiradas (modo de puntero de instrucción) |
-setProfInt InstructionRetired 16384 |
Desencadenar una interrupción cada 16.384 instrucciones retiradas |
-stackwalk profile |
Capturar una pila de llamadas en cada interrupción del perfil, proporcionando datos de cadena de llamadas en lugar de secuencias de rama |
En comparación con LBR: sin marca -LastBranch ; usa InstructionRetired en lugar de BranchInstructionRetired. El resultado es ejemplos de puntero de instrucción con pilas de llamadas, no secuencias de rama. Esta ruta sigue proporcionando datos eficaces para el optimizador, pero es algo menos completa.
Después de iniciar xperf, continúe ejecutando la carga de trabajo y detenga xperf.
Ruta del temporizador del sistema operativo
Inicie xperf con muestreo basado en temporizador del sistema operativo:
xperf -on LOADER+PROC_THREAD+PROFILE -MinBuffers 4096 -BufferSize 4096 -setProfInt Timer 1221 -stackwalk profile
Explicación de parámetros:
| Parámetro | propósito |
|---|---|
LOADER+PROC_THREAD+PROFILE |
Sin eventos PMC; muestreo de la CPU únicamente mediante la interrupción del temporizador del sistema operativo |
-setProfInt Timer 1221 |
Se activa la interrupción del temporizador del sistema operativo cada 1221 tics del temporizador (aproximadamente 1 kHz) |
-stackwalk profile |
Capturar una pila de llamadas en cada interrupción del temporizador |
En comparación con LBR y PMC, este método no usa contadores de rendimiento de hardware. El temporizador del sistema operativo se activa aproximadamente a intervalos de tiempo fijos, independientemente de la actividad de CPU. Las muestras se correlacionan con menor densidad con el código crítico, pero siguen proporcionando datos de flujo de control útiles para el optimizador.
Ejecutar la carga de trabajo y detener xperf (todas las rutas de acceso)
Con xperf en ejecución, ejecuta textCount con War and Peace:
textCount.exe < warAndPeace.txt
Cuando finalice textCount, detenga xperf y escriba el archivo de traza. Permitir que otros procesos se ejecuten durante la generación de perfiles diluyen la calidad de la muestra. Para obtener los mejores resultados, cierre las aplicaciones innecesarias antes de ejecutar la carga de trabajo.
xperf -stop -d textCount.etl
Después de detener xperf (puede tardar un tiempo en guardar el archivo ETL), compruebe que textCount.etl se haya creado en el directorio actual.
Convertir el archivo ETL en SPT
Este paso es el mismo para las tres rutas de generación de perfiles.
Ejecute SPTAggregate.exe para procesar el seguimiento ETL sin procesar y crear un archivo de perfil SPT:
SPTAggregate.exe /binary textCount.exe /etl textCount.etl textCount.spt
Explicación de parámetros:
| Parámetro | propósito |
|---|---|
/binary textCount.exe |
Binario del que se van a extraer muestras. El ETL puede contener ejemplos de todos los procesos que se ejecutaron durante la generación de perfiles |
/etl textCount.etl |
Archivo de seguimiento ETL de entrada |
textCount.spt |
Archivo de salida del perfil SPT |
SPTAggregate genera un resumen que muestra cuántos ejemplos recopiló. Este resumen es la primera confirmación de que el perfilado funcionó.
Compruebe la salida de SPTAggregate con la ruta que siguió:
- Ruta LBR: Busque un recuento de muestras LBR usadas distinto de cero.
- Ruta de PMC: Busque un número de muestras de PMC o de pila distinto de cero.
- Ruta del temporizador del sistema operativo: Busque un número de muestras de pila usadas distinto de cero.
Si todos los recuentos son cero, consulte Solución de problemas antes de continuar.
Convertir el archivo SPT en SPD
Ruta de acceso:
- Usuarios de LBR (usar
/mode:LBR): modo LBR- Usuarios de PMC (usar
/mode:IP): modo IP (temporizador de PMC y del SO)- Usuarios del temporizador del SO (usar
/mode:IP): Modo IP (PMC y temporizador del SO)Tanto las rutas del temporizador de PMC como las del SO usan
/mode:IPporque ambas producen muestras del puntero de instrucción.
El siguiente paso se divide según la ruta de perfilado, concretamente en función del indicador /mode que se pasa a SPDConvert.exe.
Modo LBR
SPDConvert.exe /mode:LBR textCount.spd textCount.spt
/mode:LBR indica a SPDConvert que interprete el SPT como que contiene datos de secuencia de bifurcación LBR.
Modo IP (temporizador de PMC y del SO)
Tanto PMC como el temporizador del sistema operativo producen ejemplos de puntero de instrucción, por lo que ambos usan el mismo comando de conversión:
SPDConvert.exe /mode:IP textCount.spd textCount.spt
/mode:IP le indica a SPDConvert que interprete el SPT como que contiene muestras del puntero de instrucción.
Advertencia
El uso del modo incorrecto para el tipo de datos puede producir un SPD vacío o con formato incorrecto. Si ha perfilado con LBR, use /mode:LBR.
Si ha realizado el perfilado con PMC o el temporizador del sistema operativo, use /mode:IP. La SPTAggregate salida de resumen de Convertir el archivo ETL a SPT muestra qué tipos de muestra se recogieron y confirma el modo correcto que debe usarse.
Después de ejecutar SPDConvert, confirme que textCount.spd se creó (o actualizó) en el directorio actual.
Interpretación de la salida SPDConvert
El comando SPDConvert textCount.spd textCount.spt muestra un resumen de la cobertura de bloques antes y después, por ejemplo:
Block coverage (before) : 33.90% ( 4507/ 13294)
Block coverage (after) : 45.64% ( 6067/ 13294)
En este resumen se muestra el porcentaje de los bloques de código binarios que tienen datos de perfil asociados. Un porcentaje mayor es mejor. La cobertura superior a 70% es excelente, mientras que la cobertura por debajo de 40% podría limitar la eficacia de la optimización. Si la cobertura es baja, ejecute la carga de trabajo de generación de perfiles más larga o combine varios archivos SPT de ejecuciones independientes con diferentes cargas de trabajo. Por ejemplo, podría ejecutar textCount con varios archivos de texto para probar distintos recorridos del código.
Puede que vea una advertencia de SPDConvert como la siguiente:
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.
Esta advertencia significa que la ejecución de generación de perfiles no ha recopilado suficientes ejemplos para que el optimizador optimice con confianza todas las funciones activas. El SPD todavía se puede usar, pero puede mejorar los resultados mediante:
- Ejecutar la carga de trabajo más larga (por ejemplo, 5 o más minutos en lugar de 1 minuto) o usar diferentes cargas de trabajo.
- Reducir el
-setProfIntvalor en elxperfcomando para aumentar la frecuencia de muestreo. El inconveniente es que este cambio genera un archivo ETL mayor, que tarda más tiempo en procesarse. - Combinación de varios archivos SPT de ejecuciones de perfilado independientes pasándolos todos a
SPDConvert.
El archivo SPT es un formato binario. Para inspeccionar su contenido, puede ejecutar SPTDump.exe textCount.spt. Del mismo modo, PTDump.exe textCount.spt muestra los datos de perfil compilados después de ejecutar SPDConvert. Ambas herramientas son útiles para comprobar ejemplos distintos de cero antes de continuar.
Recompilación de textCount con /spdin
Vuelva a generar textCount mediante el archivo SPD rellenado. El enlazador lee los datos del perfil y aplica optimizaciones de SPGO.
Este paso es el mismo para las tres rutas de generación de perfiles.
cl /EHsc /GL /O2 textCount.cpp /link /debug /spgo /spdin:textCount.spd
Nuevo indicador (en comparación con Build textCount con /spgo):
| Flag | propósito |
|---|---|
/spdin:textCount.spd |
Proporcione los datos del perfil de SPD al enlazador para la optimización. |
El comando todavía incluye /spgo. Genera un nuevo archivo SPD junto con el binario optimizado, que puede usar como punto de partida para iteraciones de generación de perfiles posteriores.
Advertencia
El archivo SPD está asociado al binario exacto para el que se genera el perfil. Si vuelve a compilar textCount sin /spdin, o recompila a partir del código fuente modificado, debe generar un archivo SPD nuevo. El existente no coincide con el GUID del nuevo binario y el enlazador no lo usará.
Después de la recompilación con /spdin, el enlazador genera estadísticas sobre la cantidad de código que se ha optimizado con los datos del perfil. Por ejemplo:
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
Un porcentaje alto significa que el SPD cubre bien su binario. Si el porcentaje es bajo (por ejemplo, por debajo del 90 %), o bien la carga de trabajo de generación de perfiles no abarcó una parte suficiente del binario, o bien el binario ha cambiado significativamente desde que se recopiló el perfil. En ambos casos, vuelva a reproducir el archivo binario actual.
Qué hace SPGO con los datos de perfil
SPGO usa los datos de ejemplo recopilados para rellenar los recuentos de cada bloque y borde en el gráfico de flujo de control del programa. Estos recuentos impulsan optimizaciones como:
- Expansión en línea guiada por perfiles: Expanda en línea de forma agresiva los puntos de llamada frecuentes, evitando el aumento del tamaño del código al expandir en línea rutas poco frecuentes.
- Separación de código frecuente y poco frecuente: mover el código que rara vez se ejecuta a secciones separadas del binario, mejorando la utilización de la caché de instrucciones y el comportamiento de paginación.
- Disposición de funciones: coloque las funciones que se llaman entre sí con frecuencia cerca unas de otras en el binario, reduciendo los fallos de página y mejorando la localidad. Las funciones optimizadas se organizan en grupos COFF de alta afinidad en el binario.
- Decisiones de tamaño/velocidad: compila las funciones más utilizadas para maximizar la velocidad y las menos utilizadas para reducir el tamaño. Las rutinas sin coincidencias observadas en el perfil podrían compilarse priorizando el tamaño frente a la velocidad, lo que limita optimizaciones como la expansión en línea y el desenrollado de bucles en esas rutas de ejecución poco frecuentes.
- Desvirtualización especulativa: cuando el muestreo revela que una llamada indirecta tiene como destino coherente la misma función, SPGO puede especular sobre ese destino e insertarlo, con una reserva para el caso poco común.
Medición de los resultados
Vuelva a ejecutar textCount y compare los tiempos transcurridos.
textCount.exe < warAndPeace.txt
Recopile varias ejecuciones para cada configuración y use la mediana. Una sola ejecución no es confiable porque la programación del sistema operativo y el ruido del sistema pueden sesgar las medidas individuales.
| Construir | Tiempo transcurrido representativo |
|---|---|
Línea de base (cl /EHsc /O2) |
(tu medida) |
/spgo compilación (todavía no hay datos de perfil) |
(debe estar cerca de la línea base) |
Optimizado para SPGO (/spdin) |
(debe mostrar la mejora) |
En una prueba, SPGO con el método LBR logró una reducción de aproximadamente un 7 % en el tiempo de ejecución. Tus resultados pueden variar con tus propios proyectos, ya que las mejoras de SPGO dependen de lo bien que la carga de trabajo de generación de perfiles represente la ejecución típica. Los códigos base rellenados por ramas más grandes tienden a ver más mejoras en el intervalo de 5 a 10%. El método de generación de perfiles afecta a la calidad de la optimización. LBR normalmente genera mejores resultados que PMC, lo que genera mejores resultados que el temporizador del sistema operativo. Si utiliza el temporizador del sistema operativo, espere mejoras menores.
La ruta de acceso de LBR seguida en este tutorial se aplicó al proyecto SQLite , que es una biblioteca de bases de datos de producción. El binario de SQLite optimizado para SPGO mostró aproximadamente una mejora de 7%.
Aplicación de SPGO a su propio proyecto
Use esta lista de comprobación para aplicar SPGO a su propia aplicación de C o C++.
Agregue
/link /spgoal comando de compilación de versión existente. Modifique el script de compilación o el archivo de proyecto:cl /EHsc /GL /O2 myapp.cpp /link /spgoElija una carga de trabajo representativa. Seleccione un escenario de uso real que recorra las rutas de ejecución más frecuentes de su aplicación. Utilice datos similares a los de producción. Evite lo siguiente como carga de trabajo principal para la elaboración de perfiles: pruebas de cobertura de código (no ponen a prueba los cuellos de botella del rendimiento), rutas de error poco frecuentes, fases de arranque y apagado, y rutas de código obsoletas. Esta carga de trabajo impulsa el perfil que alimenta el optimizador.
Ejecute xperf mediante la ruta de acceso detectada. Use la ruta de acceso que identificó en Elegir el método de generación de perfiles (LBR, PMC o temporizador del sistema operativo). Inicie
xperf, ejecute la carga de trabajo una vez, detengaxperfy capture el archivo ETL.Para la ruta del temporizador de PMC o del SO, ejecute SPTAggregate y SPDConvert con el indicador correcto
/mode. Convierta ETL a SPT y, a continuación, a SPD. Utilice/mode:LBRpara los datos de LBR; utilice/mode:IPpara los datos del temporizador de PMC o del SO.Recompile con
/spdin:<your-spd-path>. Compile la aplicación con el SPD rellenado:cl /EHsc /GL /O2 yourApp.cpp /link /spgo /spdin:yourApp.spdMida antes y después. Ejecute la carga de trabajo con los binarios no optimizados y con los binarios optimizados con SPGO. Recopile la mediana de varias ejecuciones para cada configuración. Una sola ejecución no es confiable para realizar pruebas comparativas.
Almacene el archivo
.spden el control de versiones. Archive el archivo.spden su sistema de control de versiones junto con su código fuente.Habilitar SPGO en compilaciones Release para desarrolladores. Haz que las compilaciones de lanzamiento de tu equipo usen los mismos binarios optimizados con SPGO que en producción. Esto ayuda a detectar las regresiones de rendimiento al principio.
Deshabilite SPGO en compilaciones de depuración.
Consulte las estadísticas del grado de cumplimentación del perfil del vinculador. Después de cada compilación con
/spgo, anote el porcentaje de funciones perfiladas optimizadas con datos de perfil. Si esto cae significativamente (por debajo de 90%), vuelva a reproducir el binario actual. Los cambios de código se acumulan y el SPD puede quedar obsoleto.
Alternativa al uso de xperf
Otra forma de recopilar datos de generación de perfiles es usar un generador de perfiles por muestreo como Windows Performance Recorder (WPR). WPR se instala de forma predeterminada en Windows 10 y versiones posteriores. Recopila datos similares a xperf. Puede configurar WPR para recopilar muestras de CPU con pilas de llamadas y, a continuación, exportar los datos a un archivo ETL que puede procesar con SPTAggregate y SPDConvert, como el ETL de xperf. Este es un ejemplo del uso de WPR para recopilar datos de perfil:
wpr -start CPU.light -filemode
textCount.exe < warAndPeace.txt
wpr -stop spgo_data.etl
Para obtener más información sobre el uso de WPR, vea Using Windows Performance Recorder.
Distribución de SPD
Ustedes pueden:
- Agregue directamente el archivo
.spdal control de versiones junto con su código fuente. - Comparta el archivo
.spdcon sus compañeros de equipo para que puedan compilar con optimizaciones SPGO sin volver a crear el perfil. - Empaquete el
.spdarchivo con los archivos binarios como un artefacto con versiones (por ejemplo, un paquete NuGet) y registre la versión correspondiente al binario. - Vuelva a generar el
.spdarchivo en cualquier momento repitiendo el flujo de trabajo de generación de perfiles.
El SPD se vincula al binario exacto desde el que se creó. Después de cambios significativos en el código, vuelva a crear un SPD nuevo. Durante la /spdin compilación, el compilador también genera un nuevo .spd archivo. Guarde este nuevo SPD como un artefacto de compilación: es el punto de partida de la siguiente iteración de generación de perfiles.
Reutilización de información de SPD en compilaciones
El concepto de "carry forward" en SPGO permite agregar datos de perfilado a un archivo SPD existente sin tener que volver a perfilar todos los escenarios desde cero y sin perder la información de perfil ya existente. También puede ajustar qué peso dar a los datos de perfil más antiguos. Esta flexibilidad es útil cuando puede haber cambios de comportamiento con el tiempo y no desea perder por completo la información de perfilado de ejecuciones anteriores de escenarios. Por ejemplo, una DLL podría recibir distintas llamadas a la API a medida que evoluciona la aplicación que la llama. Sigues queriendo las optimizaciones derivadas de cómo se comportaba antes, pero también quieres combinar oportunidades de optimización para los casos en los que ahora a veces se comporta de forma diferente. Puede evolucionar el perfil a lo largo del tiempo mezclando datos antiguos y nuevos.
Cuando se ejecuta SPDConvert con un nuevo archivo SPT, pase el nombre del archivo SPD existente. A continuación, use la opción /retire:N para controlar el grado de intensidad con que SPDConvert resta importancia a los datos de perfil antiguos al añadir nuevos archivos SPT:
- El valor predeterminado (
/retire:8) pondera los datos más recientes en mayor medida. - Utilice
/retire:0para asignar el mismo peso a todas las ejecuciones. - Use
/retire:16para permitir solo el recuento de datos más reciente.
Solución de problemas
Busque el problema:
- Problemas de ruta de acceso de LBR:Problemas de ruta de acceso de LBR
- Problemas de la ruta de acceso de PMC:Problemas de ruta de acceso de PMC
- Problemas del temporizador del sistema operativo:Problemas de la ruta del temporizador del sistema operativo
- Problemas que afectan a todas las rutas de acceso:Problemas generales
Problemas de ruta de LBR
| Problem | Causa probable | Corregir |
|---|---|---|
Cero muestras de LBR en la salida SPTAggregate |
La CPU no admite LBR o la máquina virtual no expone LBR | Ejecute el comando de detección desde Detecte su ruta. Si está en una máquina virtual de Hyper-V, ejecute Set-VMProcessor MyVMName -Perfmon @("pmu", "lbr") en el host. Si LBR no está disponible, use la vía del temporizador PMC o del SO. |
El procesador admite LBR, pero SPTAggregate muestra 0 ejemplos de LBR |
perfcore.ini Registro de DLL incompleto |
Complete la configuración de perfcore.ini en Configurar perfcore.ini. Asegúrese de que perf_lbr.dll está registrado. |
SPDConvert produce un error o genera un SPD vacío |
Marca incorrecta /mode o SPT contiene solo ejemplos en modo IP |
Confirme que SPTAggregate la salida muestra ejemplos de LBR. Si la salida solo muestra ejemplos en modo IP, cambie a /mode:IP. |
Problemas de ruta de acceso de PMC
| Problem | Causa probable | Corregir |
|---|---|---|
Cero muestras de PMC en SPTAggregate la salida |
perfcore.ini El registro de DLL es incorrecto |
Complete la configuración de perfcore.ini en Configurar perfcore.ini. Asegúrese de que perf_spt.dll está registrado. Sin este archivo DLL, xperf genera cero ejemplos de PMC sin un mensaje de error.Ejecute xperf.exe -pmcsources para ver la lista de orígenes de contadores de rendimiento disponibles en la CPU. Si no ve entradas como SPT_OP_RETIRE_INSTR o SPT_OP_RETIRE_BR_INSTRSPT_OP_ETW_INSTR, el registro de DLL en perfcore.ini podría estar incompleto o es posible que la CPU no admita PMC. Si no puede solucionar el registro de la DLL, pruebe en su lugar la vía del temporizador del sistema operativo. |
findstr InstructionRetired devuelve la salida, pero xperf no genera ejemplos |
Enmascaramiento de contadores PMC de máquina virtual | Compruebe si se ejecuta en una máquina virtual. Habilitar PMU en Hyper-V con Set-VMProcessor, o cambiar a la ruta del temporizador del sistema operativo. |
SPDConvert se produce un error en la ruta de acceso de PMC |
Uso de /mode:LBR en un SPT solo con IP |
Cambie a /mode:IP. |
Problemas en la ruta del temporizador del sistema operativo
| Problem | Causa probable | Corregir |
|---|---|---|
| Menor mejora de lo esperado | Previsto: el temporizador del sistema operativo tiene menor precisión. | Esto es normal. El optimizador tiene menos información de flujo de rama a partir de muestras de temporizador que de LBR o PMC. Las mejoras de rendimiento son más pequeñas. Considere la posibilidad de actualizar a PMC o LBR si el hardware lo admite. |
| Ejemplos de temporizador cero |
xperf no se ejecutó en un símbolo del sistema con privilegios elevados o PROFILE falta el proveedor |
Confirme que se está ejecutando como administrador. Confirme que se proporcionó -stackwalk profile al comando xperf. |
Problemas generales (todas las rutas de acceso)
| Problem | Causa probable | Corregir |
|---|---|---|
"failed to configure counters" error |
xperf no se ejecuta como administrador |
Reinicie el Símbolo del sistema como Administrador (haga clic con el botón derecho sobre > Ejecutar como administrador). xperf requiere privilegios elevados para configurar contadores de rendimiento de hardware. |
xperf no encontrado |
xperf.exe no está en PATH |
Confirme que Windows ADK está instalado. Compruebe C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\. Agregue ese directorio a path o ejecute xperf directamente desde él. |
textCount.etl no creado |
xperf falló sin mostrar ningún error | Confirme que se está ejecutando como administrador. Vuelva a ejecutar el comando xperf start y compruebe si hay resultados de error. |
SPTAggregate se produce un error con "binario no encontrado" |
textCount.exe no está en el directorio actual o la ruta de acceso es incorrecta |
Confirme que está en el mismo directorio que textCount.exeo proporcione la ruta de acceso completa al /binary parámetro . |
| No se ha creado el archivo SPD |
SPDConvert falló |
Compruebe que el tamaño textCount.spt no sea cero. Ejecute SPTDump.exe textCount.spt para inspeccionar su contenido. |
/spdin la compilación no produce ninguna mejora |
Error de coincidencia de GUID/edad entre SPD y binario | El SPD se creó a partir de otro textCount.exe. Perfile de nuevo la compilación actual para generar un nuevo SPD. |
Error de versión de MSVC en /spgo |
Conjunto de herramientas de MSVC anterior a v14.51 | Abra el instalador de Visual Studio >Componentes individuales> e instale MSVC v14.51 o una versión posterior. Vuelva a abrir el símbolo del sistema para desarrolladores. |
Pasos siguientes
Después de completar este tutorial, explore estas funcionalidades para obtener más información de SPGO:
-
Combinación de perfiles: Ejecute varias cargas de trabajo, acumule archivos SPT de cada ejecución y pase todos ellos a
SPDConvert. Un SPD combinado refleja la gama completa de patrones de uso reales y genera mejores optimizaciones que un perfil de escenario único. Use la opción/retire:Npara controlar hasta qué puntoSPDConvertresta importancia a los datos de perfil más antiguos al añadir nuevos archivos SPT. El valor predeterminado (/retire:8) pondera los datos más recientes en mayor medida. Use/retire:0para dar el mismo peso a todas las ejecuciones; use/retire:16para que solo se tengan en cuenta los datos más recientes. - Los mejores resultados proceden de combinar perfiles de varios orígenes, como pruebas comparativas que hacen hincapié en escenarios clave, además de datos reales (cuando están disponibles). Pase archivos SPT de todos los orígenes a
SPDConvert. Repita un archivo SPT en la lista de argumentos para darle más peso (por ejemplo,SPDConvert myapp.spd critical.spt critical.spt common.sptponderacritical.sptel doble quecommon.spt). -
Optimización iterativa: Cada recompilación con
/spdingenera un nuevo SPD. Puede repetir el ciclo de ejecución, perfil y recompilación. Las iteraciones posteriores pueden mostrar rendimientos decrecientes, pero una segunda pasada a veces puede detectar patrones que la primera no detectó. - Cambios de código: Tras cambios significativos en el código fuente, vuelva a recopilar los datos de perfil. El SPD existente está vinculado al binario con respecto al cual se creó el perfil. No coincidirá con un binario recompilado de forma significativa.
-
Vigencia del perfil: El enlazador informa del porcentaje de funciones perfiladas optimizadas mediante datos de perfil después de cada compilación
/spdin. Si este porcentaje cae significativamente, es una señal de que el código ha divergido del perfil. Vuelva a perfilar el binario actual.