Sdílet prostřednictvím


Řešení potíží s inlincí funkcí v době sestavení

Pomocí zobrazení funkcí Build Insights můžete řešit potíže s dopadem vkládání funkcí na čas sestavení v projektech C++.

Požadavky

  • Visual Studio 2022 17.8 nebo novější
  • Funkce C++ Build Insights je ve výchozím nastavení povolená, pokud nainstalujete vývoj desktopových aplikací s úlohou C++ nebo vývoj her s úlohou C++.

Snímek obrazovky s Instalační program pro Visual Studio s vybranou úlohou Desktop development with C++ (Vývoj desktopových aplikací s vybranou úlohou C++).

Zobrazí se seznam nainstalovaných komponent. Zvýrazní se přehledy sestavení C++ a vybere se, což znamená, že je nainstalované.

Snímek obrazovky Instalační program pro Visual Studio s vybranou úlohou Vývoj her s vybranou úlohou C++.

Zobrazí se seznam nainstalovaných komponent. Zvýrazní se přehledy sestavení C++ a vybere se, což znamená, že je nainstalované.

Přehled

Funkce Build Insights, která je teď integrovaná do sady Visual Studio, vám pomůže optimalizovat časy sestavení – zejména pro velké projekty, jako jsou hry AAA. Build Insights poskytuje analýzy, jako je zobrazení Functions , které pomáhá diagnostikovat nákladné generování kódu během doby sestavení. Zobrazí čas potřebný ke generování kódu pro každou funkci a ukazuje dopad __forceinline.

Direktiva __forceinline kompilátoru říká, aby funkci vloženého bez ohledu na jeho velikost nebo složitost. Vložení funkce může zlepšit výkon modulu runtime snížením režie volání funkce. Kompromisem je, že může zvětšit velikost binárního souboru a ovlivnit časy sestavení.

Pro optimalizované buildy významně přispívá doba strávená generováním kódu k celkovému času sestavení. Obecně platí, že optimalizace funkcí jazyka C++ probíhá rychle. Vevýjimečných

V tomto článku se dozvíte, jak pomocí zobrazení Funkce Build Insights najít v sestavení kritické body.

Nastavení možností sestavení

K měření výsledků __forceinlinepoužijte sestavení vydané verze , protože ladicí buildy nejsou vložené __forceinline , protože ladicí sestavení používají přepínač kompilátoru /Ob0 , který tuto optimalizaci zakáže. Nastavte sestavení pro verzi a x64:

  1. V rozevíracím seznamu Konfigurace řešení zvolte Verze.
  2. V rozevíracím seznamu Platformy řešení zvolte x64.

Snímek obrazovky s rozevíracím seznamem Konfigurace řešení nastaveným na Release (Release) a rozevírací seznam Solution Platform (Platforma řešení) nastavený na x64

Nastavte úroveň optimalizace na maximální počet optimalizací:

  1. V Průzkumník řešení klikněte pravým tlačítkem myši na název projektu a vyberte Vlastnosti.

  2. Ve vlastnostech projektu přejděte na C/C++>Optimization.

  3. Nastavte rozevírací seznam Optimalizace na Maximální optimalizaci (upřednostnění rychlosti) (/O2).

    Snímek obrazovky s dialogovým oknem stránek vlastností projektu Nastavení jsou otevřená pro optimalizaci vlastností > konfigurace C/C++ > . Rozevírací seznam Optimalizace je nastavený na maximální optimalizaci (rychlost upřednostnění) (/O2).

  4. Kliknutím na tlačítko OK zavřete dialogové okno.

Spuštění buildových přehledů

V projektu podle vašeho výběru a použití možností sestavení vydané verze nastavené v předchozí části spusťte Build Insights výběrem z hlavní nabídky Sestavení>Spustit přehledy při opětovném sestavení výběru.> Můžete také kliknout pravým tlačítkem myši na projekt v Průzkumníku řešení a zvolit Spustit opětovné sestavení Build Insights.> Místo sestavení zvolte Znovu sestavit, abyste změřili čas sestavení pro celý projekt, a ne jenom pro několik souborů, které teď můžou být zašpiněné.

Snímek obrazovky hlavní nabídky s vybranou možností Spustit přehledy sestavení při opětovném sestavení výběru >

Po dokončení sestavení se otevře soubor ETL (Event Trace Log). Uloží se do složky, na kterou odkazuje proměnná prostředí Windows TEMP . Vygenerovaný název vychází z času shromažďování.

Zobrazení funkcí

V okně pro soubor ETL zvolte kartu Funkce . Zobrazuje funkce, které byly zkompilovány, a dobu, kterou trvalo vygenerovat kód pro každou funkci. Pokud je množství kódu vygenerovaného pro funkci zanedbatelné, nezobrazí se v seznamu, aby nedošlo ke snížení výkonu shromažďování událostí sestavení.

Snímek obrazovky se souborem zobrazení funkce Build Insights

Ve sloupci Název funkce je zvýrazněná funkce performPhysicsCalculations() a označena ikonou fire.:::

Sloupec Time [sec, %] ukazuje, jak dlouho trvalo kompilaci jednotlivých funkcí v době odpovědnosti za nástěnné hodiny (WCTR). Tato metrika distribuuje nástěnný čas mezi funkce na základě jejich použití paralelních vláken kompilátoru. Pokud například dvě různá vlákna kompilují dvě různé funkce současně během jedné sekundy, zaznamená se WCTR každé funkce jako 0,5 sekundy. To odráží proporcionální podíl celkové doby kompilace každé funkce, přičemž bere v úvahu prostředky spotřebované během paralelního provádění. WcTR tedy poskytuje lepší míru dopadu jednotlivých funkcí na celkovou dobu sestavení v prostředích, kde současně probíhá více aktivit kompilace.

Ve sloupci Forceinline Size se přibližně zobrazuje, kolik instrukcí se pro funkci vygenerovalo. Kliknutím na dvojitou šipku před názvem funkce zobrazíte jednotlivé vložené funkce, které byly v této funkci rozbaleny, jak přibližně kolik instrukcí se pro každou z nich vygenerovalo.

Seznam můžete seřadit tak, že kliknete na sloupec Čas a zjistíte, které funkce zabírají nejvíce času kompilace. Ikona "fire" označuje, že náklady na generování této funkce jsou vysoké a stojí za to prozkoumat. Nadměrné používání __forceinline funkcí může výrazně zpomalit kompilaci.

Konkrétní funkci můžete vyhledat pomocí pole Filtrovat funkce . Pokud je čas generování kódu funkce příliš malý, nezobrazí se v zobrazení funkcí .

Vylepšení doby sestavení úpravou inliningu funkcí

V tomto příkladu performPhysicsCalculations trvá kompilace funkce nejvíce času.

Snímek obrazovky se zobrazením funkce Build Insights

Ve sloupci Název funkce je funkce performPhysicsCalculations() zvýrazněná a označená ikonou aktivace.

Prošetřujeme to podrobněji tak, že vyberete dvojitou šipku před danou funkcí a potom seřadíme sloupec Forceinline Size od nejvyššího po nejnižší, uvidíme největší přispěvatele problému.

Snímek obrazovky se zobrazením funkce Build Insights s rozbalenou funkcí

performPhysicsCalculations() je rozbalený a zobrazuje dlouhý seznam funkcí, které byly vloženy uvnitř. Existuje několik instancí funkcí, jako je complexOperation(), recursiveHelper() a sin(). Sloupec Forceinline Size ukazuje, že complexOperation() je největší vložená funkce v pokynech 315. recursiveHelper() má 119 instrukcí. Sin() má 75 instrukcí, ale existuje mnoho dalších instancí než ostatní funkce.

Existují některé větší vložené funkce, například Vector2D<float>::complexOperation() a Vector2D<float>::recursiveHelper() které přispívají k problému. Ale existuje mnoho dalších instancí (ne všechny zde uvedené) z Vector2d<float>::sin(float), Vector2d<float>::cos(float), Vector2D<float>::power(float,int), a Vector2D<float>::factorial(int). Když je sčítáte, celkový počet vygenerovaných instrukcí rychle překročí několik větších generovaných funkcí.

Když se podíváme na tyto funkce ve zdrojovém kódu, vidíme, že doba provádění se stráví uvnitř smyček. Tady je například kód pro 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;
}

Možná celkové náklady na volání této funkce jsou ve srovnání s náklady samotné funkce nevýznamné. Vytvoření vložené funkce je nejužitejší, když je doba, která trvá volání funkce (nasdílení argumentů do zásobníku, přeskakování na funkci, vrácení argumentů a vrácení z funkce) přibližně podobné době, která trvá spuštění funkce, a když se funkce nazývá hodně. Pokud tomu tak není, může dojít ke snížení výnosu, aby byl vložený. Můžeme zkusit odebrat direktivu __forceinline a zjistit, jestli pomáhá době sestavení. Kód pro powera sin()cos() je podobný v tom, že kód se skládá ze smyčky, která se provede mnohokrát. Můžeme zkusit odebrat i direktivu __forceinline z těchto funkcí.

Znovu spustíme Build Insights z hlavní nabídky tak, že zvolíme Sestavení>Spustit přehledy sestavení při opětovném sestavení výběru.> Můžete také kliknout pravým tlačítkem myši na projekt v Průzkumníku řešení a zvolit Spustit opětovné sestavení Build Insights.> Místo sestavení zvolíme možnost Znovu sestavit, abychom změřili čas sestavení pro celý projekt, jako předtím, a ne jenom u několika souborů, může být právě teď zašpiněný.

Čas sestavení trvá 25,181 sekund až 13,376 sekund a performPhysicsCalculations funkce se už v zobrazení Funkce nezobrazuje, protože nepřispívá dost času sestavení, který se má počítat.

Snímek obrazovky se souborem záhlaví vektoru 2D

Ve sloupci Název funkce je zvýrazněná funkce performPhysicsCalculations() a označena ikonou fire.:::

Čas relace diagnostiky je celkový čas potřebný k sestavení a veškeré režijní náklady na shromažďování dat Build Insights.

Dalším krokem bude profilace aplikace, aby se zjistilo, jestli je výkon aplikace negativně ovlivněný změnou. Pokud ano, můžeme podle potřeby selektivně přidat __forceinline zpět.

Poklikáním, kliknutím pravým tlačítkem myši nebo stisknutím klávesy Enter v souboru v zobrazení Functions otevřete zdrojový kód pro daný soubor.

Snímek obrazovky se kliknutím pravým tlačítkem myši na soubor v zobrazení Functions Možnost nabídky Přejít na zdrojový soubor je zvýrazněná.

Tipy

  • Soubor Uložit jako soubor ETL můžete >uložit do trvalejšího umístění, abyste si zachovali záznam o čase sestavení. Pak ho můžete porovnat s budoucími buildy a zjistit, jestli se vaše změny zlepšují čas sestavení.
  • Pokud neúmyslně zavřete okno Build Insights, znovu ho otevřete vyhledáním <dateandtime>.etl souboru v dočasné složce. TEMP Proměnná prostředí Windows poskytuje cestu ke složce dočasných souborů.
  • Chcete-li se podívat na data Build Insights s Windows Analyzátor výkonu (WPA), klikněte v pravém dolním rohu okna ETL na tlačítko Otevřít v WPA.
  • Přetažením sloupců můžete změnit pořadí sloupců. Můžete například raději přesunout sloupec Čas na první sloupec. Sloupce můžete skrýt tak, že kliknete pravým tlačítkem myši na záhlaví sloupce a zrušíte výběr sloupců, které nechcete zobrazit.
  • Zobrazení Funkce poskytuje pole filtru pro vyhledání funkce, která vás zajímá. Provede částečné shody u zadaného názvu.
  • Pokud zapomenete, jak interpretovat, co se vám zobrazení Functions snaží zobrazit, najeďte myší na kartu a zobrazte popis, který toto zobrazení popisuje. Pokud najedete myší na kartu Funkce , zobrazí se v popisu zobrazení statistiky pro funkce, ve kterých jsou podřízené uzly vynucené vložené funkce.

Řešení problému

  • Pokud se okno Build Insights nezobrazí, místo sestavení proveďte opětovné sestavení. Okno Build Insights se nezobrazí, pokud se ve skutečnosti nic nevytvorí; což může být případ, kdy se od posledního sestavení nezměnily žádné soubory.
  • Pokud zobrazení Functions nezobrazuje žádné funkce, nemusíte vytvářet správné nastavení optimalizace. Ujistěte se, že vytváříte verzi s úplnými optimalizacemi, jak je popsáno v části Nastavení možností sestavení. Pokud je čas generování kódu funkce příliš malý, nezobrazí se v seznamu.

Viz také

Tipy a triky k vytváření přehledů
Vložené funkce (C++)
Rychlejší sestavení jazyka C++, zjednodušená: nová metrika pro čas
Build Insights in Visual Studio video – Pure Virtual C++ 2023
Řešení potíží s dopadem hlavičkového souboru na čas sestavení
Zobrazení funkcí pro Build Insights v sadě Visual Studio 2022 17.8
Kurz: vcperf a Windows Analyzátor výkonu
Vylepšení doby generování kódu pomocí přehledů sestavení jazyka C++