Dela via


Felsöka funktionspåverkan på byggtiden

Använd vyn Build Insights Functions för att felsöka effekten av funktionsinlinering på byggtiden i dina C++-projekt.

Förutsättningar

  • Visual Studio 2022 17.8 eller senare.
  • C++ Build Insights är aktiverat som standard om du installerar antingen Skrivbordsutveckling med C++-arbetsbelastning eller Spelutveckling med C++-arbetsbelastning.

Skärmbild av Visual Studio Installer med skrivbordsutvecklingen med C++-arbetsbelastningen vald.

Listan över installerade komponenter visas. C++ Build Insights är markerat och valt, vilket innebär att det är installerat.

Skärmbild av Visual Studio Installer med arbetsuppgiftspaketet för spelutveckling med C++ valt.

Listan över installerade komponenter visas. C++ Build Insights är markerat och valt, vilket innebär att det är installerat.

Översikt

Build Insights, som nu är integrerat i Visual Studio, hjälper dig att optimera dina byggtider – särskilt för stora projekt som AAA-spel. Build Insights tillhandahåller analyser som Functions-vyn , som hjälper till att diagnostisera dyr kodgenerering under byggtiden. Den visar den tid det tar att generera kod för varje funktion och visar effekten av __forceinline.

Direktivet __forceinline uppmanar kompilatorn att infoga en funktion oavsett storlek eller komplexitet. Att ange en funktion kan förbättra körningsprestanda genom att minska kostnaderna för att anropa funktionen. Kompromissen är att det kan öka storleken på binärfilen och påverka dina kompileringstider.

För optimerade versioner bidrar den tid som ägnas åt att generera kod avsevärt till den totala byggtiden. I allmänhet sker C++-funktionsoptimering snabbt. I undantagsfall kan vissa funktioner bli tillräckligt stora och komplexa för att sätta press på optimeraren och märkbart sakta ned dina byggen.

I den här artikeln får du lära dig hur du använder vyn Build Insights Functions för att hitta flaskhalsar i bygget.

Ange byggalternativ

Om du vill mäta resultatet av __forceinlineanvänder du en Versionsversion eftersom felsökningsversioner inte är infogade __forceinline eftersom felsökningsversioner använder kompilatorväxeln, vilket inaktiverar optimeringen /Ob0 . Ställ in byggalternativen för Release och x64:

  1. I listrutan Lösningskonfigurationer väljer du Släpp.
  2. I listrutan Lösningsplattformar väljer du x64.

Skärmbild av listrutan Lösningskonfiguration inställd på Release och listrutan Solution Platform inställd på x64.

Ange optimeringsnivån till maximala optimeringar:

  1. Högerklicka på projektnamnet i Solution Explorer och välj Egenskaper.

  2. I projektegenskaperna navigerar du till C/C++>Optimization.

  3. Ange listrutan Optimering till Maximal optimering (favorhastighet) (/O2).

    Skärmbild av dialogrutan för projektegenskapssidor. Inställningarna är öppna för Konfigurationsegenskaper > C/C++ > Optimering. Listrutan Optimering är inställd på Maximal optimering (gynna hastighet) (/O2).

  4. Stäng dialogrutan genom att klicka på OK .

Kör Build Insights

I ett projekt som du väljer, och med hjälp av Release versionsalternativen som angavs i föregående avsnitt, kör du Build Insights genom att välja från huvudmenyn Build>Run Build Insights on Selection>Rebuild. Du kan också högerklicka på ett projekt i Solution Explorer och välja Kör Build Insights>Rebuild. Välj Återskapa i stället för Skapa för att mäta byggtiden för hela projektet och inte bara för de få filer som kan vara smutsiga just nu.

Skärmbild av huvudmenyn med Run Build Insights on Selection > Återskapa vald.

När bygget är klart öppnas en ETL-fil (Event Trace Log). Den sparas i mappen som pekas på av Miljövariabeln Windows TEMP . Det genererade namnet baseras på insamlingstiden.

Funktionsvy

I fönstret för ETL-filen väljer du fliken Funktioner . Den visar de funktioner som kompilerades och den tid det tog att generera koden för varje funktion. Om mängden kod som genereras för en funktion är försumbar visas den inte i listan för att undvika att prestanda för kompileringshändelsesamlingen försämras.

Skärmbild av Build Insights Functions-vyfilen.

I kolumnen Funktionsnamn är performPhysicsCalculations() markerad med en eldmarkering.

Kolumnen Time [sec, %] visar hur lång tid det tog att kompilera varje funktion i WCTR (Wall Clock Responsibility Time). Det här måttet fördelar väggklocktiden mellan funktioner baserat på deras användning av parallella kompilatortrådar. Om två olika trådar till exempel kompilerar två olika funktioner samtidigt inom en sekund, registreras varje funktions WCTR som 0,5 sekunder. Detta återspeglar varje funktions proportionella andel av den totala kompileringstiden, med hänsyn till de resurser som var och en förbrukas under parallell körning. WCTR ger därför ett bättre mått på vilken inverkan varje funktion har på den övergripande byggtiden i miljöer där flera kompileringsaktiviteter sker samtidigt.

Kolumnen Forceinline Size visar ungefär hur många instruktioner som genererades för funktionen. Klicka på sparren före funktionsnamnet för att se de enskilda inlined-funktionerna som expanderades i den funktionen och ungefär hur många instruktioner som genererades för var och en.

Du kan sortera listan genom att klicka på kolumnen Tid för att se vilka funktioner som tar mest tid att kompilera. En "fire"-ikon anger att kostnaden för att generera funktionen är hög och är värd att undersöka. Överdriven användning av __forceinline funktioner kan avsevärt sakta kompilering.

Du kan söka efter en specifik funktion med hjälp av rutan Filterfunktioner . Om en funktions kodgenereringstid är för liten visas den inte i funktionsvyn .

Förbättra byggtiden genom justering av funktionens inlining

I det här exemplet tar funktionen performPhysicsCalculations mest tid att kompilera.

Skärmbild av visningen Build Insights-funktioner.

I kolumnen Funktionsnamn är performPhysicsCalculations() markerad med en eldmarkering.

Genom att välja sparren före den funktionen och sedan sortera kolumnen Forceinline Size från högsta till lägsta ser vi de största bidragsgivarna till problemet.

Skärmbild av vyn Build Insights Functions med en expanderad funktion.

performPhysicsCalculations() expanderas och visar en lång lista över funktioner som har infogats i den. Det finns flera instanser av funktioner som complexOperation(), rekursiveHelper() och sin() som visas. Kolumnen Forceinline Size visar att complexOperation() är den största infogade funktionen med 315 instruktioner. recursiveHelper() har 119 instruktioner. Sin() har 75 instruktioner, men det finns många fler instanser av den än de andra funktionerna.

Det finns några större inlined funktioner, till exempel Vector2D<float>::complexOperation() och Vector2D<float>::recursiveHelper() som bidrar till problemet. Men det finns många fler instanser (inte alla som visas här) av Vector2D<float>::sin(float), Vector2D<float>::cos(float), Vector2D<float>::power(float,int)och Vector2D<float>::factorial(int). När du lägger till dessa överskrider det totala antalet genererade instruktioner snabbt de få större genererade funktionerna.

När vi tittar på dessa funktioner i källkoden ser vi att körningstiden kommer att spenderas i loopar. Här är till exempel koden för factorial():

static __forceinline T factorial(int n)
{
    T result = 1;
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j < i; ++j) {
            result *= (i - j) / (T)(j + 1);
        }
    }
    return result;
}

Kanske är den totala kostnaden för att anropa den här funktionen obetydlig jämfört med kostnaden för själva funktionen. Att göra en funktion inline är mest fördelaktigt när tiden det tar att anropa funktionen (pusha argument till stacken, hoppa till funktionen, poppa returargument och återgå från funktionen) ungefär liknar tiden det tar att köra funktionen och när funktionen anropas ofta. När så inte är fallet kan det finnas minskande avkastning på att göra det infogat. Vi kan försöka ta bort __forceinline direktivet från det för att se om det hjälper byggtiden. Koden för power, sin()och cos() är liknande eftersom koden består av en loop som körs många gånger. Vi kan också försöka att ta bort __forceinline direktivet från dessa funktioner.

Vi kör om Build Insights från huvudmenyn genom att välja Build>Kör Build Insights på markering>Återskapa. Du kan också högerklicka på ett projekt i Solution Explorer och välja Kör Build Insights>Rebuild. Vi väljer Återskapa i stället för Skapa för att mäta byggtiden för hela projektet, som tidigare, och inte bara för de få filer som kan vara smutsiga just nu.

Byggtiden går från 25,181 sekunder till 13,376 sekunder och performPhysicsCalculations funktionen visas inte längre i vyn Funktioner eftersom den inte bidrar tillräckligt till den byggtid som ska räknas.

Skärmbild av 2D-vektorhuvudfilen.

I kolumnen Funktionsnamn är performPhysicsCalculations() markerad med en eldmarkering.

Tiden för diagnostiksessionen är den totala tid det tog att utföra bygget plus eventuella omkostnader för att samla in Build Insights-data.

Nästa steg är att profilera programmet för att se om programmets prestanda påverkas negativt av ändringen. I så fall kan vi selektivt lägga tillbaka __forceinline efter behov.

Dubbelklicka, högerklicka eller tryck på Retur när du är på en fil i vyn Funktioner för att öppna källkoden för filen.

Skärmbild av en högerklicka på en fil i vyn Funktioner. Menyalternativet Gå till källfil är markerat.

Råd

  • Använd Spara som-fil> för att spara ETL-filen på en mer permanent plats för att spara information om byggtiden. Du kan sedan jämföra det med framtida versioner för att se hur dina ändringar förbättrar saker och ting.
  • Om du stänger fönstret Build Insights öppnar du det igen genom att hitta filen i den <dateandtime>.etl tillfälliga mappen. Miljövariabeln TEMP Windows innehåller sökvägen till mappen temporära filer.
  • Om du vill ta en titt på Build Insights-data med Windows Performance Analyzer (WPA) klickar du på knappen Öppna i WPA längst ned till höger i ETL-fönstret.
  • Dra kolumner för att ändra ordningen på kolumnerna. Du kanske till exempel föredrar att flytta kolumnen Tid till den första kolumnen. Du kan dölja kolumner genom att högerklicka på kolumnrubriken och avmarkera de kolumner som du inte vill se.
  • Vyn Funktioner innehåller en filterruta för att hitta en funktion som du är intresserad av. Den matchar delvis det namn som du anger.
  • Om du glömmer hur du tolkar vad vyn Funktioner försöker visa dig hovrar du över fliken för att se en knappbeskrivning som beskriver vyn. Om du hovrar över fliken Funktioner, visar knappbeskrivningen: "En vy som visar statistik för funktioner där underordnade noder är funktioner som tvingats att inline."

Felsökning

  • Om fönstret Build Insights inte visas, gör du en ombyggnad i stället för en bygg. Fönstret Build Insights visas inte om ingenting faktiskt byggs. vilket kan vara fallet om inga filer har ändrats sedan den senaste versionen.
  • Om vyn Funktioner inte visar några funktioner kanske du inte skapar med rätt optimeringsinställningar. Se till att du skapar Release med fullständiga optimeringar enligt beskrivningen i Ange byggalternativ. Om en funktions kodgenereringstid är för liten visas den inte i listan.

Se även

Tips och tricks för Att skapa insikter
Infogade funktioner (C++)
Snabbare C++-versioner, förenklat: ett nytt mått för tid
Skapa insikter i Visual Studio-video – Pure Virtual C++ 2023
Felsöka header-filens byggtidspåverkan
Funktionsvy för Build Insights i Visual Studio 2022 17.8
Självstudie: vcperf och Windows Performance Analyzer
Förbättra kodgenereringstiden med C++ Build Insights