Bagikan melalui


Memecahkan masalah inlining fungsi pada waktu build

Gunakan tampilan Build Insights Functions untuk memecahkan masalah dampak inlining fungsi pada waktu build di proyek C++Anda.

Prasyarat

  • Visual Studio 2022 17.8 atau lebih tinggi.
  • Wawasan Build C++ diaktifkan secara default jika Anda menginstal pengembangan Desktop dengan beban kerja C++ atau pengembangan Game dengan beban kerja C++.

Cuplikan layar Alat Penginstal Visual Studio dengan pengembangan Desktop dengan beban kerja C++ dipilih.

Daftar komponen yang diinstal ditampilkan. C++ Build Insights disorot dan dipilih yang berarti telah diinstal.

Cuplikan layar Alat Penginstal Visual Studio dengan pengembangan Game dengan beban kerja C++ dipilih.

Daftar komponen yang diinstal ditampilkan. C++ Build Insights disorot dan dipilih yang berarti telah diinstal.

Gambaran Umum

Build Insights, yang sekarang terintegrasi ke dalam Visual Studio, membantu Anda mengoptimalkan waktu build Anda--terutama untuk proyek besar seperti game AAA. Build Insights menyediakan analitik seperti tampilan Functions , yang membantu mendiagnosis pembuatan kode yang mahal selama waktu build. Ini menampilkan waktu yang diperlukan untuk menghasilkan kode untuk setiap fungsi, dan menunjukkan dampak .__forceinline

Direktif __forceinline memberi tahu pengkompilasi untuk menginline fungsi terlepas dari ukuran atau kompleksitasnya. Inlining fungsi dapat meningkatkan performa runtime dengan mengurangi overhead panggilan fungsi. Tradeoff adalah dapat meningkatkan ukuran biner dan berdampak pada waktu build Anda.

Untuk build yang dioptimalkan, waktu yang dihabiskan untuk menghasilkan kode berkontribusi secara signifikan pada total waktu build. Secara umum, pengoptimalan fungsi C++ terjadi dengan cepat. Dalam kasus luar biasa, beberapa fungsi dapat menjadi cukup besar dan cukup kompleks untuk memberikan tekanan pada pengoptimal dan terlihat memperlambat build Anda.

Dalam artikel ini, pelajari cara menggunakan tampilan Build Insights Functions untuk menemukan hambatan inlining di build Anda.

Mengatur opsi build

Untuk mengukur hasil __forceinline, gunakan build Rilis karena build debug tidak sebaris __forceinline karena build debug menggunakan sakelar kompilator, yang menonaktifkan pengoptimalan tersebut /Ob0 . Atur build untuk Rilis dan x64:

  1. Di menu dropdown Konfigurasi Solusi, pilih Rilis.
  2. Di menu dropdown Platform Solusi, pilih x64.

Cuplikan layar dropdown Konfigurasi Solusi diatur ke Rilis, dan dropdown Platform Solusi diatur ke x64.

Atur tingkat pengoptimalan ke pengoptimalan maksimum:

  1. Di Penjelajah Solusi, klik kanan nama proyek dan pilih Properti.

  2. Di properti proyek, navigasikan ke C/C++>Optimization.

  3. Atur dropdown Pengoptimalan ke Pengoptimalan Maksimum (Kecepatan Dukungan) (/O2).

    Cuplikan layar dialog halaman properti proyek. Pengaturan terbuka untuk Pengoptimalan C/C++ > Properti > Konfigurasi. Dropdown Pengoptimalan diatur ke Pengoptimalan Maksimum (Kecepatan Dukungan) (/O2).

  4. Klik OK untuk menutup kotak dialog.

Jalankan Build Insights

Pada proyek yang Anda pilih, dan menggunakan opsi Build rilis yang diatur di bagian sebelumnya, jalankan Build Insights dengan memilih dari menu utama Build>> Anda juga dapat mengklik kanan proyek di penjelajah solusi dan memilih Jalankan Pembangunan Ulang Build Insights Pilih Bangun Ulang alih-alih Bangun untuk mengukur waktu build untuk seluruh proyek dan bukan hanya untuk beberapa file yang mungkin kotor sekarang.

Cuplikan layar menu utama dengan Jalankan Build Insights pada Pembangunan Ulang Pilihan > dipilih.

Setelah build selesai, file Log Jejak Peristiwa (ETL) terbuka. Ini disimpan dalam folder yang ditujukkan oleh variabel lingkungan Windows TEMP . Nama yang dihasilkan didasarkan pada waktu pengumpulan.

Tampilan fungsi

Di jendela untuk file ETL, pilih tab Fungsi . Ini menunjukkan fungsi yang dikompilasi dan waktu yang diperlukan untuk menghasilkan kode untuk setiap fungsi. Jika jumlah kode yang dihasilkan untuk fungsi dapat diabaikan, kode tersebut tidak akan muncul dalam daftar untuk menghindari penurunan performa pengumpulan peristiwa build.

Cuplikan layar file tampilan Build Insights Functions.

Di kolom Nama Fungsi, performPhysicsCalculations() disorot dan ditandai dengan ikon kebakaran.

Kolom Waktu [detik, %] menunjukkan berapa lama waktu yang dibutuhkan untuk mengompilasi setiap fungsi dalam waktu tanggung jawab jam dinding (WCTR). Metrik ini mendistribusikan waktu jam dinding di antara fungsi berdasarkan penggunaan utas kompilator paralel. Misalnya, jika dua utas yang berbeda mengompilasi dua fungsi yang berbeda secara bersamaan dalam periode satu detik, WCTR setiap fungsi dicatat sebagai 0,5 detik. Ini mencerminkan bagian proporsional setiap fungsi dari total waktu kompilasi, dengan mempertimbangkan sumber daya yang masing-masing digunakan selama eksekusi paralel. Dengan demikian, WCTR memberikan ukuran dampak yang lebih baik yang dimiliki setiap fungsi pada waktu build keseluruhan di lingkungan di mana beberapa aktivitas kompilasi terjadi secara bersamaan.

Kolom Ukuran Forceinline menunjukkan kira-kira berapa banyak instruksi yang dihasilkan untuk fungsi tersebut. Klik chevron sebelum nama fungsi untuk melihat fungsi inlined individual yang diperluas dalam fungsi itu seberapa kira-kira berapa banyak instruksi yang dihasilkan untuk masing-masing.

Anda dapat mengurutkan daftar dengan mengeklik kolom Waktu untuk melihat fungsi mana yang membutuhkan waktu paling lama untuk dikompilasi. Ikon 'kebakaran' menunjukkan bahwa biaya menghasilkan fungsi tersebut tinggi dan layak diselidiki. Penggunaan __forceinline fungsi yang berlebihan dapat secara signifikan memperlambat kompilasi.

Anda dapat mencari fungsi tertentu dengan menggunakan kotak Fungsi Filter . Jika waktu pembuatan kode fungsi terlalu kecil, waktu pembuatan kode tidak muncul di Tampilan Fungsi .

Meningkatkan waktu build dengan menyesuaikan inlining fungsi

Dalam contoh ini, performPhysicsCalculations fungsi ini membutuhkan waktu paling lama untuk dikompilasi.

Cuplikan layar tampilan Build Insights Functions.

Di kolom Nama Fungsi, performPhysicsCalculations() disorot dan ditandai dengan ikon kebakaran.

Menyelidiki lebih lanjut, dengan memilih chevron sebelum fungsi itu , lalu mengurutkan kolom Ukuran Forceinline dari tertinggi ke terendah, kita melihat kontributor terbesar untuk masalah tersebut.

Cuplikan layar tampilan Build Insights Functions dengan fungsi yang diperluas.

performPhysicsCalculations() diperluas dan menunjukkan daftar panjang fungsi yang sebaris di dalamnya. Ada beberapa instans fungsi seperti complexOperation(), recursiveHelper(), dan sin() yang ditampilkan. Kolom Ukuran Forceinline menunjukkan bahwa complexOperation() adalah fungsi inlin terbesar pada instruksi 315. recursiveHelper() memiliki 119 instruksi. Sin() memiliki 75 instruksi, tetapi ada lebih banyak instans daripada fungsi lainnya.

Ada beberapa fungsi inlined yang lebih besar, seperti Vector2D<float>::complexOperation() dan Vector2D<float>::recursiveHelper() yang berkontribusi pada masalah. Tetapi ada lebih banyak instans (tidak semua ditampilkan di sini) dari Vector2d<float>::sin(float), , Vector2d<float>::cos(float)Vector2D<float>::power(float,int), dan Vector2D<float>::factorial(int). Ketika Anda menambahkannya, jumlah total instruksi yang dihasilkan dengan cepat melebihi beberapa fungsi yang dihasilkan yang lebih besar.

Melihat fungsi-fungsi tersebut dalam kode sumber, kita melihat bahwa waktu eksekusi akan dihabiskan di dalam perulangan. Misalnya, berikut adalah kode untuk 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;
}

Mungkin biaya keseluruhan untuk memanggil fungsi ini tidak signifikan dibandingkan dengan biaya fungsi itu sendiri. Membuat fungsi sebaris paling bermanfaat ketika waktu yang diperlukan untuk memanggil fungsi (mendorong argumen pada tumpukan, melompat ke fungsi, memunculkan argumen pengembalian, dan mengembalikan dari fungsi) kira-kira mirip dengan waktu yang diperlukan untuk menjalankan fungsi, dan ketika fungsi dipanggil banyak. Ketika itu tidak terjadi, mungkin ada penurunan pengembalian pada membuatnya sebaris. Kita dapat mencoba menghapus arahan __forceinline darinya untuk melihat apakah itu membantu waktu build. Kode untuk power, sin() dan cos() serupa dengan kode yang terdiri dari perulangan yang akan dijalankan berkali-kali. Kita dapat mencoba menghapus arahan __forceinline dari fungsi-fungsi tersebut juga.

Kami menjalankan ulang Build Insights dari menu utama dengan memilih >Rebuild. Anda juga dapat mengklik kanan proyek di penjelajah solusi dan memilih Jalankan Pembangunan Ulang Build Insights Kami memilih Bangun ulang alih-alih Build untuk mengukur waktu build untuk seluruh proyek, seperti sebelumnya, dan bukan hanya untuk beberapa file yang mungkin kotor sekarang.

Waktu build berlangsung dari 25,181 detik menjadi 13,376 detik dan performPhysicsCalculations fungsi tidak muncul lagi dalam tampilan Functions karena tidak cukup berkontribusi pada waktu build yang akan dihitung.

Cuplikan layar file header vektor 2D.

Di kolom Nama Fungsi, performPhysicsCalculations() disorot dan ditandai dengan ikon kebakaran.

Waktu Sesi Diagnostik adalah waktu keseluruhan yang diperlukan untuk melakukan build ditambah overhead apa pun untuk mengumpulkan data Build Insights.

Langkah selanjutnya adalah membuat profil aplikasi untuk melihat apakah performa aplikasi terpengaruh secara negatif oleh perubahan. Jika ya, kita dapat secara selektif menambahkan __forceinline kembali sesuai kebutuhan.

Klik dua kali, klik kanan, atau tekan Enter saat berada di file dalam tampilan Fungsi untuk membuka kode sumber untuk file tersebut.

Cuplikan layar klik kanan pada file dalam tampilan Functions. Opsi menu Buka File Sumber disorot.

Petunjuk

  • Anda dapat Menyimpan File>Sebagai file ETL ke lokasi yang lebih permanen untuk menyimpan catatan waktu build. Anda kemudian dapat membandingkannya dengan build di masa mendatang untuk melihat apakah perubahan Anda meningkatkan waktu build.
  • Jika Anda secara tidak sengaja menutup jendela Build Insights, buka kembali dengan menemukan <dateandtime>.etl file di folder sementara Anda. Variabel TEMP lingkungan Windows menyediakan jalur folder file sementara Anda.
  • Untuk menggali data Build Insights dengan Windows Penganalisis Kinerja (WPA), klik tombol Buka di WPA di kanan bawah jendela ETL.
  • Seret kolom untuk mengubah urutan kolom. Misalnya, Anda mungkin lebih suka memindahkan kolom Waktu menjadi kolom pertama. Anda bisa menyembunyikan kolom dengan mengklik kanan header kolom dan membatalkan pilihan kolom yang tidak ingin Anda lihat.
  • Tampilan Fungsi menyediakan kotak filter untuk menemukan fungsi yang Anda minati. Ini melakukan kecocokan parsial pada nama yang Anda berikan.
  • Jika Anda lupa cara menginterpretasikan apa yang coba ditampilkan tampilan Functions kepada Anda, arahkan mouse ke atas tab untuk melihat tipsalat yang menjelaskan tampilan. Jika Anda mengarahkan mouse ke atas tab Functions , tipsalat mengatakan: "Tampilan yang memperlihatkan statistik untuk fungsi di mana simpul anak adalah fungsi yang di-inlin paksa."

Pemecahan Masalah

  • Jika jendela Build Insights tidak muncul, lakukan pembangunan ulang alih-alih build. Jendela Build Insights tidak muncul jika tidak ada yang benar-benar dibangun; yang mungkin terjadi jika tidak ada file yang berubah sejak build terakhir.
  • Jika tampilan Functions tidak menampilkan fungsi apa pun, Anda mungkin tidak membangun dengan pengaturan pengoptimalan yang tepat. Pastikan Anda membuat Rilis dengan pengoptimalan penuh, seperti yang dijelaskan dalam Mengatur opsi build. Selain itu, jika waktu pembuatan kode fungsi terlalu kecil, waktu tersebut tidak muncul dalam daftar.

Lihat juga

Membuat tips dan trik Wawasan
Fungsi sebaris (C++)
Build C++ yang lebih cepat, disederhanakan: metrik baru untuk waktu
Build Insights di video Visual Studio - Murni Virtual C++ 2023
Memecahkan masalah dampak file header pada waktu build
Tampilan Fungsi untuk Wawasan Build di Visual Studio 2022 17.8
Tutorial: vcperf dan Windows Penganalisis Kinerja
Meningkatkan waktu pembuatan kode dengan C++ Build Insights