Panduan: Menelusuri kesalahan aplikasi C++ AMP
Artikel ini menunjukkan cara men-debug aplikasi yang menggunakan C++ Accelerated Massive Parallelism (C++ AMP) untuk memanfaatkan unit pemrosesan grafis (GPU). Ini menggunakan program pengurangan paralel yang menjumlahkan sejumlah besar bilangan bulat. Panduan ini mengilustrasikan tugas-tugas berikut:
- Meluncurkan debugger GPU.
- Memeriksa utas GPU di jendela Utas GPU.
- Menggunakan jendela Tumpukan Paralel untuk mengamati tumpukan panggilan beberapa utas GPU secara bersamaan.
- Menggunakan jendela Parallel Watch untuk memeriksa nilai ekspresi tunggal di beberapa utas secara bersamaan.
- Menandai, membekukan, mencairkan, dan mengelompokkan utas GPU.
- Menjalankan semua utas petak ke lokasi tertentu dalam kode.
Prasyarat
Sebelum Anda memulai panduan ini:
Catatan
Header AMP C++ tidak digunakan lagi dimulai dengan Visual Studio 2022 versi 17.0.
Menyertakan header AMP apa pun akan menghasilkan kesalahan build. Tentukan _SILENCE_AMP_DEPRECATION_WARNINGS
sebelum menyertakan header AMP apa pun untuk membungkam peringatan.
- Baca Gambaran Umum C++ AMP.
- Pastikan nomor baris ditampilkan di editor teks. Untuk informasi selengkapnya, lihat Cara: Menampilkan nomor baris di editor.
- Pastikan Anda menjalankan setidaknya Windows 8 atau Windows Server 2012 untuk mendukung penelusuran kesalahan pada emulator perangkat lunak.
Catatan
Komputer Anda mungkin memperlihatkan nama atau lokasi yang berbeda untuk beberapa elemen antarmuka pengguna Visual Studio dalam petunjuk berikut. Edisi Visual Studio yang Anda miliki dan setelan yang Anda gunakan menentukan elemen-elemen ini. Untuk informasi selengkapnya, lihat Mempersonalisasi IDE.
Untuk membuat proyek sampel
Instruksi untuk membuat proyek bervariasi tergantung pada versi Visual Studio mana yang Anda gunakan. Pastikan Anda memiliki versi dokumentasi yang benar yang dipilih di atas daftar isi pada halaman ini.
Untuk membuat proyek sampel di Visual Studio
Pada bilah menu, pilih File>New>Project untuk membuka kotak dialog Create a New Project.
Di bagian atas dialog, atur Bahasa ke C++, atur Platform ke Windows, dan atur jenis Project ke Konsol.
Dari daftar jenis proyek yang difilter, pilih Aplikasi Konsol lalu pilih Berikutnya. Di halaman berikutnya, masukkan
AMPMapReduce
di kotak Nama untuk menentukan nama proyek, dan tentukan lokasi proyek jika Anda menginginkan yang berbeda.Pilih tombol Buat untuk membuat proyek klien.
Untuk membuat proyek sampel di Visual Studio 2017 atau Visual Studio 2015
Mulai Visual Studio.
Dari bilah menu, pilih File>New>Project.
Di bawah Terinstal di panel templat, pilih Visual C++.
Pilih Aplikasi Konsol Win32, ketik
AMPMapReduce
di kotak Nama , lalu pilih tombol OK .Pilih tombol Berikutnya.
Kosongkan kotak centang Header yang telah dikompilasi sebelumnya, lalu pilih tombol Selesai .
Di Penjelajah Solusi, hapus stdafx.h, targetver.h, dan stdafx.cpp dari proyek.
Berikutnya:
Buka AMPMapReduce.cpp dan ganti kontennya dengan kode berikut.
// AMPMapReduce.cpp defines the entry point for the program. // The program performs a parallel-sum reduction that computes the sum of an array of integers. #include <stdio.h> #include <tchar.h> #include <amp.h> const int BLOCK_DIM = 32; using namespace concurrency; void sum_kernel_tiled(tiled_index<BLOCK_DIM> t_idx, array<int, 1> &A, int stride_size) restrict(amp) { tile_static int localA[BLOCK_DIM]; index<1> globalIdx = t_idx.global * stride_size; index<1> localIdx = t_idx.local; localA[localIdx[0]] = A[globalIdx]; t_idx.barrier.wait(); // Aggregate all elements in one tile into the first element. for (int i = BLOCK_DIM / 2; i > 0; i /= 2) { if (localIdx[0] < i) { localA[localIdx[0]] += localA[localIdx[0] + i]; } t_idx.barrier.wait(); } if (localIdx[0] == 0) { A[globalIdx] = localA[0]; } } int size_after_padding(int n) { // The extent might have to be slightly bigger than num_stride to // be evenly divisible by BLOCK_DIM. You can do this by padding with zeros. // The calculation to do this is BLOCK_DIM * ceil(n / BLOCK_DIM) return ((n - 1) / BLOCK_DIM + 1) * BLOCK_DIM; } int reduction_sum_gpu_kernel(array<int, 1> input) { int len = input.extent[0]; //Tree-based reduction control that uses the CPU. for (int stride_size = 1; stride_size < len; stride_size *= BLOCK_DIM) { // Number of useful values in the array, given the current // stride size. int num_strides = len / stride_size; extent<1> e(size_after_padding(num_strides)); // The sum kernel that uses the GPU. parallel_for_each(extent<1>(e).tile<BLOCK_DIM>(), [&input, stride_size] (tiled_index<BLOCK_DIM> idx) restrict(amp) { sum_kernel_tiled(idx, input, stride_size); }); } array_view<int, 1> output = input.section(extent<1>(1)); return output[0]; } int cpu_sum(const std::vector<int> &arr) { int sum = 0; for (size_t i = 0; i < arr.size(); i++) { sum += arr[i]; } return sum; } std::vector<int> rand_vector(unsigned int size) { srand(2011); std::vector<int> vec(size); for (size_t i = 0; i < size; i++) { vec[i] = rand(); } return vec; } array<int, 1> vector_to_array(const std::vector<int> &vec) { array<int, 1> arr(vec.size()); copy(vec.begin(), vec.end(), arr); return arr; } int _tmain(int argc, _TCHAR* argv[]) { std::vector<int> vec = rand_vector(10000); array<int, 1> arr = vector_to_array(vec); int expected = cpu_sum(vec); int actual = reduction_sum_gpu_kernel(arr); bool passed = (expected == actual); if (!passed) { printf("Actual (GPU): %d, Expected (CPU): %d", actual, expected); } printf("sum: %s\n", passed ? "Passed!" : "Failed!"); getchar(); return 0; }
Pada bilah menu, pilih Simpan Semua File>.
Di Penjelajah Solusi, buka menu pintasan untuk AMPMapReduce, lalu pilih Properti.
Dalam kotak dialog Halaman Properti, di bawah Properti Konfigurasi, pilih C/C++>Header yang Telah Dikompilasi sebelumnya.
Untuk properti Header yang Telah Dikompilasi sebelumnya, pilih Tidak Menggunakan Header yang Telah Dikompilasi sebelumnya, lalu pilih tombol OK.
Pada bilah menu, pilih Bangun>Bangun Solusi.
Men-debug Kode CPU
Dalam prosedur ini, Anda akan menggunakan Local Windows Debugger untuk memastikan bahwa kode CPU dalam aplikasi ini sudah benar. Segmen kode CPU dalam aplikasi ini yang sangat menarik adalah perulangan for
dalam reduction_sum_gpu_kernel
fungsi. Ini mengontrol pengurangan paralel berbasis pohon yang dijalankan pada GPU.
Untuk men-debug kode CPU
Di Penjelajah Solusi, buka menu pintasan untuk AMPMapReduce, lalu pilih Properti.
Dalam kotak dialog Halaman Properti, di bawah Properti Konfigurasi, pilih Penelusuran Kesalahan. Verifikasi bahwa Debugger Windows Lokal dipilih di daftar Debugger untuk diluncurkan .
Kembali ke Editor Kode.
Atur titik henti pada baris kode yang diperlihatkan dalam ilustrasi berikut (sekitar baris 67 baris 70).
Titik henti CPUPada bilah menu, pilih Debug>Mulai Penelusuran Kesalahan.
Di jendela Lokal , amati nilai hingga
stride_size
titik henti di baris 70 tercapai.Pada bilah menu, pilih Debug>Hentikan Penelusuran Kesalahan.
Men-debug Kode GPU
Bagian ini menunjukkan cara men-debug kode GPU, yang merupakan kode yang terkandung dalam sum_kernel_tiled
fungsi . Kode GPU menghitung jumlah bilangan bulat untuk setiap "blok" secara paralel.
Untuk men-debug kode GPU
Di Penjelajah Solusi, buka menu pintasan untuk AMPMapReduce, lalu pilih Properti.
Dalam kotak dialog Halaman Properti, di bawah Properti Konfigurasi, pilih Penelusuran Kesalahan.
Di daftar Debugger yang akan diluncurkan, pilih Debugger Windows Lokal.
Di daftar Jenis Debugger, verifikasi bahwa Otomatis dipilih.
Otomatis adalah nilai default. Dalam versi sebelum Windows 10, GPU Saja adalah nilai yang diperlukan alih-alih Otomatis.
Pilih tombol OK.
Atur titik henti di baris 30, seperti yang diperlihatkan dalam ilustrasi berikut.
Titik henti GPUPada bilah menu, pilih Debug>Mulai Penelusuran Kesalahan. Titik henti dalam kode CPU pada baris 67 dan 70 tidak dieksekusi selama penelusuran kesalahan GPU karena baris kode tersebut berjalan pada CPU.
Untuk menggunakan jendela Utas GPU
Untuk membuka jendela Utas GPU, pada bilah menu, pilih Debug>Utas GPU Windows>.
Anda dapat memeriksa status utas GPU di jendela Utas GPU yang muncul.
Dock jendela Utas GPU di bagian bawah Visual Studio. Pilih tombol Perluas Pengalihan Utas untuk menampilkan kotak teks petak dan utas. Jendela Utas GPU menunjukkan jumlah total utas GPU aktif dan diblokir, seperti yang ditunjukkan pada ilustrasi berikut.
Jendela Utas GPU313 petak peta dialokasikan untuk komputasi ini. Setiap petak peta berisi 32 utas. Karena penelusuran kesalahan GPU lokal terjadi pada emulator perangkat lunak, ada empat utas GPU aktif. Empat utas menjalankan instruksi secara bersamaan dan kemudian melanjutkan bersama-sama ke instruksi berikutnya.
Di jendela Utas GPU, ada empat utas GPU aktif dan 28 utas GPU yang diblokir di pernyataan tile_barrier::wait yang ditentukan pada sekitar baris 21 (
t_idx.barrier.wait();
). Semua 32 utas GPU milik petak peta pertama,tile[0]
. Panah menunjuk ke baris yang menyertakan utas saat ini. Untuk beralih ke utas yang berbeda, gunakan salah satu metode berikut:Di baris untuk utas yang akan dialihkan di jendela Utas GPU, buka menu pintasan dan pilih Beralih Ke Utas. Jika baris mewakili lebih dari satu utas, Anda akan beralih ke utas pertama sesuai dengan koordinat utas.
Masukkan nilai ubin dan utas utas dalam kotak teks terkait lalu pilih tombol Alihkan Utas .
Jendela Call Stack menampilkan tumpukan panggilan utas GPU saat ini.
Untuk menggunakan jendela Tumpukan Paralel
Untuk membuka jendela Tumpukan Paralel, pada bilah menu, pilih Debug>Tumpukan Paralel Windows>.
Anda dapat menggunakan jendela Tumpukan Paralel untuk secara bersamaan memeriksa bingkai tumpukan beberapa utas GPU.
Dock jendela Parallel Stacks di bagian bawah Visual Studio.
Pastikan bahwa Utas dipilih dalam daftar di sudut kiri atas. Dalam ilustrasi berikut, jendela Tumpukan Paralel memperlihatkan tampilan fokus tumpukan panggilan dari utas GPU yang Anda lihat di jendela Utas GPU.
Jendela Tumpukan Paralel32 utas pergi dari
_kernel_stub
ke pernyataan lambda dalamparallel_for_each
panggilan fungsi dan kemudian kesum_kernel_tiled
fungsi, di mana pengurangan paralel terjadi. 28 dari 32 utas telah berkembang ketile_barrier::wait
pernyataan dan tetap diblokir pada baris 22, sementara empat utas lainnya tetap aktif dalamsum_kernel_tiled
fungsi pada baris 30.Anda dapat memeriksa properti utas GPU. Mereka tersedia di jendela Utas GPU di Tip Data kaya dari jendela Tumpukan Paralel. Untuk melihatnya, arahkan penunjuk ke bingkai
sum_kernel_tiled
tumpukan . Ilustrasi berikut ini memperlihatkan Tips Data.
Tips Data Utas GPUUntuk informasi selengkapnya tentang jendela Tumpukan Paralel, lihat Menggunakan Jendela Tumpukan Paralel.
Untuk menggunakan jendela Parallel Watch
Untuk membuka jendela Parallel Watch, pada bilah menu, pilih Debug>Windows>Parallel Watch>Parallel Watch 1.
Anda dapat menggunakan jendela Parallel Watch untuk memeriksa nilai ekspresi di beberapa utas.
Dock jendela Parallel Watch 1 ke bagian bawah Visual Studio. Ada 32 baris dalam tabel jendela Parallel Watch . Masing-masing sesuai dengan utas GPU yang muncul di jendela Utas GPU dan jendela Tumpukan Paralel. Sekarang, Anda dapat memasukkan ekspresi yang nilainya ingin Anda periksa di semua 32 utas GPU.
Pilih header tambahkan kolom Watch, masukkan
localIdx
, lalu pilih tombol Enter.Pilih header kolom Tambahkan Watch lagi, ketik
globalIdx
, lalu pilih tombol Enter.Pilih header kolom Tambahkan Watch lagi, ketik
localA[localIdx[0]]
, lalu pilih tombol Enter.Anda dapat mengurutkan menurut ekspresi tertentu dengan memilih header kolom yang sesuai.
Pilih header kolom localA[localIdx[0]] untuk mengurutkan kolom. Ilustrasi berikut menunjukkan hasil pengurutan menurut localA[localIdx[0]].
Hasil pengurutanAnda bisa mengekspor konten di jendela Parallel Watch ke Excel dengan memilih tombol Excel lalu memilih Buka di Excel. Jika Anda memiliki Excel yang terinstal di komputer pengembangan Anda, tombol akan membuka lembar kerja Excel yang berisi isi.
Di sudut kanan atas jendela Parallel Watch , ada kontrol filter yang dapat Anda gunakan untuk memfilter konten dengan menggunakan ekspresi Boolean. Masukkan
localA[localIdx[0]] > 20000
dalam kotak teks kontrol filter lalu pilih tombol Enter .Jendela sekarang hanya berisi utas di mana
localA[localIdx[0]]
nilainya lebih besar dari 20000. Konten masih diurutkan menurutlocalA[localIdx[0]]
kolom, yang merupakan tindakan pengurutan yang Anda pilih sebelumnya.
Menandai Utas GPU
Anda dapat menandai utas GPU tertentu dengan menandainya di jendela Utas GPU, jendela Parallel Watch , atau DataTip di jendela Tumpukan Paralel. Jika baris di jendela Utas GPU berisi lebih dari satu utas, menandai baris tersebut menandai semua utas yang terkandung dalam baris.
Untuk menandai utas GPU
Pilih header kolom [Utas] di jendela Parallel Watch 1 untuk mengurutkan menurut indeks petak peta dan indeks utas.
Pada bilah menu, pilih Debug>Lanjutkan, yang menyebabkan empat utas yang aktif untuk maju ke hambatan berikutnya (didefinisikan pada baris 32 AMPMapReduce.cpp).
Pilih simbol bendera di sisi kiri baris yang berisi empat utas yang sekarang aktif.
Ilustrasi berikut menunjukkan empat utas aktif yang ditandai di jendela Utas GPU.
Utas aktif di jendela Utas GPUJendela Parallel Watch dan DataTip jendela Parallel Stacks menunjukkan utas yang ditandai.
Jika Anda ingin fokus pada empat utas yang Anda benderai, Anda dapat memilih untuk hanya menampilkan utas yang ditandai. Ini membatasi apa yang Anda lihat di jendela Utas GPU, Parallel Watch, dan Parallel Stacks .
Pilih tombol Perlihatkan Hanya yang Ditandai di salah satu jendela atau pada toolbar Lokasi Debug. Ilustrasi berikut ini memperlihatkan tombol Perlihatkan Hanya yang Ditandai pada toolbar Lokasi Debug.
Perlihatkan tombol Hanya Yang DitandaiSekarang jendela Utas GPU, Parallel Watch, dan Parallel Stacks hanya menampilkan utas yang ditandai.
Utas GPU Pembeku dan Pencairan
Anda dapat membekukan (menangguhkan) dan mencairkan (melanjutkan) utas GPU dari jendela Utas GPU atau jendela Parallel Watch . Anda dapat membekukan dan mencairkan utas CPU dengan cara yang sama; untuk informasi, lihat Cara: Menggunakan Jendela Utas.
Untuk membekukan dan mencairkan utas GPU
Pilih tombol Perlihatkan Hanya yang Ditandai untuk menampilkan semua utas.
Pada bilah menu, pilih Debug>Lanjutkan.
Buka menu pintasan untuk baris aktif lalu pilih Bekukan.
Ilustrasi jendela Utas GPU berikut menunjukkan bahwa keempat utas dibekukan.
Utas beku di jendela Utas GPUDemikian pula, jendela Parallel Watch menunjukkan bahwa keempat utas dibekukan.
Pada bilah menu, pilih Debug>Lanjutkan untuk memungkinkan empat utas GPU berikutnya untuk maju melewati pembatas pada baris 22 dan untuk mencapai titik henti pada baris 30. Jendela Utas GPU menunjukkan bahwa empat utas yang sebelumnya dibekukan tetap beku dan dalam keadaan aktif.
Pada bilah menu, pilih Debug, Lanjutkan.
Dari jendela Parallel Watch , Anda juga dapat mencairkan utas GPU individual atau beberapa.
Untuk mengelompokkan utas GPU
Pada menu pintasan untuk salah satu utas di jendela Utas GPU, pilih Kelompokkan Menurut, Alamat.
Utas di jendela Utas GPU dikelompokkan menurut alamat. Alamat sesuai dengan instruksi dalam pembongkaran tempat setiap grup utas berada. 24 utas berada di baris 22 di mana Metode tile_barrier::wait dijalankan. 12 utas berada pada instruksi untuk hambatan di baris 32. Empat utas ini ditandai. Delapan utas berada di titik henti pada baris 30. Empat utas ini dibekukan. Ilustrasi berikut menunjukkan utas yang dikelompokkan di jendela Utas GPU.
Utas yang dikelompokkan di jendela Utas GPUAnda juga dapat melakukan operasi Kelompokkan Menurut dengan membuka menu pintasan untuk kisi data jendela Parallel Watch . Pilih Kelompokkan Menurut, lalu pilih item menu yang sesuai dengan cara yang Anda inginkan untuk mengelompokkan utas.
Menjalankan Semua Utas ke Lokasi Tertentu dalam Kode
Anda menjalankan semua utas dalam petak peta tertentu ke baris yang berisi kursor dengan menggunakan Jalankan Petak Peta Saat Ini Ke Kursor.
Untuk menjalankan semua utas ke lokasi yang ditandai oleh kursor
Pada menu pintasan untuk utas beku, pilih Cairkan.
Di Editor Kode, letakkan kursor di baris 30.
Pada menu pintasan untuk Editor Kode, pilih Jalankan Petak Peta Saat Ini Ke Kursor.
24 utas yang sebelumnya diblokir pada penghalang di baris 21 telah maju ke baris 32. Ini ditampilkan di jendela Utas GPU.
Lihat juga
Gambaran umum C++ AMP
Men-debug kode GPU
Cara: Menggunakan jendela Utas GPU
Cara: Menggunakan Jendela Parallel Watch
Menganalisis kode AMP C++ dengan Visualizer Konkurensi