Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här artikeln visar hur du felsöker ett program som använder C++ Accelerated Massive Parallelism (C++ AMP) för att dra nytta av grafikprocessorn (GPU). Den använder ett parallellreduktionsprogram som summerar en stor matris med heltal. I den här genomgången tas följande aktiviteter upp:
- Starta GPU-felsökningsprogrammet.
- Inspektera GPU-trådarna i GPU-trådarna-fönstret.
- Använd fönstret Parallella staplar för att samtidigt observera anropsstackarna för flera GPU-trådar.
- Använd fönstret Parallell bevakning för att inspektera värden för ett enda uttryck i flera trådar samtidigt.
- Flagga, frysa, tina och gruppera GPU-trådar.
- Kör alla trådar i en panel till en viss plats i koden.
Förutsättningar
Innan du påbörjar den här genomgången:
Anmärkning
C++ AMP-huvuden är inaktuella från och med Visual Studio 2022 version 17.0.
Om du inkluderar AMP headers uppstår byggfel. Definiera _SILENCE_AMP_DEPRECATION_WARNINGS innan du inkluderar AMP-huvuden för att undvika varningarna.
- Läs översikt över C++ AMP.
- Kontrollera att radnumren visas i textredigeraren. Mer information finns i Så här: Visa radnummer i redigeraren.
- Kontrollera att du kör minst Windows 8 eller Windows Server 2012 för att stödja felsökning på programvaruemulatorn.
Anmärkning
Datorn kan visa olika namn eller platser för vissa av Visual Studio-användargränssnittselementen i följande instruktioner. Den Visual Studio-utgåva som du har och de inställningar som du använder avgör dessa element. Mer information finns i Anpassning av utvecklingsmiljön.
Så här skapar du exempelprojektet
Instruktionerna för att skapa ett projekt varierar beroende på vilken version av Visual Studio du använder. Kontrollera att du har valt rätt dokumentationsversion ovanför innehållsförteckningen på den här sidan.
Så här skapar du exempelprojektet i Visual Studio
I menyraden väljer du Arkiv>Nytt>projekt för att öppna dialogrutan Skapa ett nytt projekt .
Längst upp i dialogrutan anger du Språk till C++, anger Plattform till Windows och anger Projekttyp till Konsol.
I den filtrerade listan över projekttyper väljer du Konsolapp och sedan Nästa. På nästa sida anger du
AMPMapReducei rutan Namn för att ange ett namn för projektet och anger projektplatsen om du vill ha en annan.
Välj knappen Skapa för att skapa klientprojektet.
Skapa exempelprojektet i Visual Studio 2017 eller Visual Studio 2015
Starta Visual Studio.
På menyraden väljer du Arkiv>Nytt>projekt.
Under Installerat i mallfönstret väljer du Visual C++.
Välj Win32-konsolprogram, skriv
AMPMapReducei rutan Namn och välj sedan knappen OK .Välj knappen Nästa .
Avmarkera kryssrutan Förkompilerad rubrik och välj sedan knappen Slutför .
I Solution Explorer tar du bort stdafx.h, targetver.h och stdafx.cpp från projektet.
Nästa:
Öppna AMPMapReduce.cpp och ersätt innehållet med följande kod.
// 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; }På menyraden, välj Arkiv>Spara alla.
Öppna snabbmenyn för AMPMapReduce i Solution Explorer och välj sedan Egenskaper.
I dialogrutan Egenskapssidor går du till Konfigurationsegenskaper och väljer C/C++>Förkompilerade rubriker.
För egenskapen Förkompilerad rubrik väljer du Inte använda förkompilerade rubriker och väljer sedan knappen OK .
På menyraden väljer du Skapa>bygglösning.
Felsöka CPU-koden
I den här proceduren använder du det lokala Windows-felsökningsprogrammet för att se till att CPU-koden i det här programmet är korrekt. Den del av CPU-koden i det här programmet som är särskilt intressant är loopen i funktionen forreduction_sum_gpu_kernel. Den styr den trädbaserade parallella minskning som körs på GPU:n.
Så här felsöker du CPU-koden
Öppna snabbmenyn för AMPMapReduce i Solution Explorer och välj sedan Egenskaper.
I dialogrutan Egenskapssidor går du till Konfigurationsegenskaper och väljer Felsökning. Kontrollera att Det lokala Windows-felsökningsprogrammet har valts i felsökningsprogrammet för att starta listan.
Gå tillbaka till kodredigeraren.
Ange brytpunkter på de kodrader som visas i följande bild (ungefär rad 67 rad 70).
CPU-brytpunkterPå menyraden väljer du Felsöka>Starta felsökning.
I fönstret Lokalt observerar du värdet för
stride_sizetills brytpunkten på rad 70 har nåtts.På menyraden väljer du Felsöka>sluta felsöka.
Felsöka GPU-koden
Det här avsnittet visar hur du felsöker GPU-koden, som är koden som finns i sum_kernel_tiled funktionen. GPU-koden beräknar summan av heltal för varje "block" parallellt.
Så här felsöker du GPU-koden
Öppna snabbmenyn för AMPMapReduce i Solution Explorer och välj sedan Egenskaper.
I dialogrutan Egenskapssidor går du till Konfigurationsegenskaper och väljer Felsökning.
I listan Debugger to launch (Felsökare för att starta ) väljer du Lokalt Windows-felsökningsprogram.
Kontrollera att Auto är markerat i listan Felsökningstyp.
Auto är standardvärdet. I versioner före Windows 10 är endast GPU det nödvändiga värdet i stället för Automatiskt.
Välj knappen OK.
Ange en brytpunkt på rad 30, enligt följande bild.
GPU-brytpunktPå menyraden väljer du Felsöka>Starta felsökning. Brytpunkterna i CPU-koden på raderna 67 och 70 körs inte under GPU-felsökningen eftersom dessa kodrader körs på processorn.
Så här använder du fönstret GPU-trådar
Om du vill öppna fönstret GPU-trådar går du till menyraden och väljer Felsöka>Windows>GPU-trådar.
Du kan kontrollera tillståndet för GPU-trådarna i fönstret GPU-trådar som visas.
Docka fönstret GPU-trådar längst ned i Visual Studio. Välj knappen Expandera trådväxel för att visa panel- och trådtextrutorna. Fönstret GPU-trådar visar det totala antalet aktiva och blockerade GPU-trådar, enligt följande bild.
Fönstret GPU-trådar313 plattor allokeras för den här beräkningen. Varje panel innehåller 32 trådar. Eftersom lokal GPU-felsökning sker på en programvaruemulator finns det fyra aktiva GPU-trådar. De fyra trådarna kör anvisningarna samtidigt och går sedan vidare tillsammans till nästa instruktion.
I fönstret GPU-trådar finns det fyra GPU-trådar aktiva och 28 GPU-trådar blockerade vid tile_barrier::wait-instruktionen definierad på ungefär rad 21 (
t_idx.barrier.wait();). Alla 32 GPU-trådar tillhör den första panelen,tile[0]. En pil pekar på raden som innehåller den aktuella tråden. Om du vill växla till en annan tråd använder du någon av följande metoder:På raden för tråden som ska växlas till i GPU-trådfönstret öppnar du snabbmenyn och väljer Växla till tråd. Om raden representerar mer än en tråd växlar du till den första tråden enligt trådkoordinaterna.
Ange trådens panel- och trådvärden i motsvarande textrutor och välj sedan knappen Växla tråd .
I fönstret Samtalsstack visas anropsstacken för den aktuella GPU-tråden.
Så här använder du fönstret Parallella staplar
Om du vill öppna fönstret Parallella staplar går du till menyraden och väljer Felsöka>Windows>Parallel Stacks.
Du kan använda fönstret Parallella staplar för att samtidigt inspektera stackramarna för flera GPU-trådar.
Docka fönstret Parallella staplar längst ned i Visual Studio.
Kontrollera att Trådar är markerade i listan i det övre vänstra hörnet. I följande bild visar fönstret Parallella staplar en anropsstackfokuserad vy över GPU-trådarna som du såg i GPU-trådar-fönstret.
Fönstret Parallella stackar32 trådar gick från
_kernel_stubtill lambda-instruktionen i funktionsanropetparallel_for_eachoch sedan tillsum_kernel_tiledfunktionen, där den parallella minskningen sker. 28 av de 32 trådarna har gått vidare till uttalandettile_barrier::waitoch förblir blockerade på rad 22, medan de övriga fyra trådarna förblir aktiva i funktionensum_kernel_tiledpå rad 30.Du kan kontrollera egenskaperna för en GPU-tråd. De finns i fönstret GPU-trådar i det detaljerade DataTip i fönstret Parallella staplar. Om du vill se dem, flytta pekaren över stackramen på
sum_kernel_tiled. Följande bild visar DataTip.
GPU-tråddatatipsMer information om fönstret Parallella staplar finnsi Använda fönstret Parallella staplar.
Så här använder du fönstret Parallell bevakning
Om du vill öppna fönstret Parallell bevakning går du till menyraden och väljer Felsöka>Windows>Parallel Watch>Parallel Watch 1.
Du kan använda fönstret Parallell bevakning för att inspektera värdena för ett uttryck i flera trådar.
Docka fönstret Parallel Watch 1 längst ned i Visual Studio. Det finns 32 rader i tabellen i fönstret Parallell bevakning . Var och en motsvarar en GPU-tråd som visades i både fönstret GPU-trådar och fönstret Parallella staplar . Nu kan du ange uttryck vars värden du vill granska i alla 32 GPU-trådar.
Välj kolumnrubriken Lägg till klocka, ange
localIdx, och välj sedan Enter-tangenten.Välj kolumnrubriken Lägg till klocka igen, skriv
globalIdx, och välj sedan returtangenten.Välj kolumnrubriken Lägg till klocka igen, skriv
localA[localIdx[0]], och välj sedan returtangenten.Du kan sortera efter ett angivet uttryck genom att välja dess motsvarande kolumnrubrik.
Välj kolumnrubriken localA[localIdx[0]] för att sortera kolumnen. Följande bild visar resultatet av sortering efter localA[localIdx[0]].
SorteringsresultatDu kan exportera innehållet i fönstret Parallell bevakning till Excel genom att välja Excel-knappen och sedan välja Öppna i Excel. Om du har Installerat Excel på utvecklingsdatorn öppnar knappen ett Excel-kalkylblad som innehåller innehållet.
I det övre högra hörnet i fönstret Parallell bevakning finns det en filterkontroll som du kan använda för att filtrera innehållet med hjälp av booleska uttryck. Ange
localA[localIdx[0]] > 20000i textrutan filterkontroll och välj sedan returnyckeln .Fönstret innehåller nu endast trådar där
localA[localIdx[0]]värdet är större än 20000. Innehållet sorteras fortfarande efterlocalA[localIdx[0]]kolumnen, vilket är den sorteringsåtgärd som du valde tidigare.
Flaggning av GPU-trådar
Du kan markera specifika GPU-trådar genom att flagga dem i fönstret GPU-trådar , fönstret Parallell bevakning eller DataTip i fönstret Parallella staplar . Om en rad i fönstret GPU-trådar innehåller fler än en tråd, så kommer flaggning av den raden att flagga alla trådar som finns i raden.
Att flagga GPU-trådar
Välj kolumnrubriken [Tråd] i fönstret Parallell bevakning 1 för att sortera efter panelindex och trådindex.
På menyraden väljer du Felsöka>Fortsätt, vilket gör att de fyra trådar som var aktiva går vidare till nästa barriär (definieras på rad 32 i AMPMapReduce.cpp).
Välj flaggsymbolen till vänster på raden som innehåller de fyra trådar som nu är aktiva.
Följande bild visar de fyra aktiva flaggade trådarna i fönstret GPU-trådar .
Aktiva trådar i fönstret GPU-trådarFönstret Parallel Watch och DataTip i fönstret Parallella staplar anger båda de flaggade trådarna.
Om du vill fokusera på de fyra trådar som du har flaggat kan du välja att endast visa de flaggade trådarna. Det begränsar vad du ser i fönstren GPU Threads, Parallel Watch och Parallel Stacks .
Välj knappen Visa flaggad endast i något av fönstren eller i verktygsfältet Felsökningsplats . Följande bild visar knappen Visa flaggad endast i verktygsfältet Felsökningsplats .
Visa endast flaggadeNu visar GPU-trådarna, Parallel Watch- och Parallel Stacks-fönstren endast de flaggade trådarna.
Frysning och upptining av GPU-trådar
Du kan låsa (pausa) och tina (återuppta) GPU-trådar från antingen GPU-trådfönstret eller fönstret Parallel Watch . Du kan låsa och tina CPU-trådar på samma sätt. Mer information finns i How to: Use the Threads Window (Använda trådfönstret).
Att frysa och tina GPU-trådar
Välj knappen Visa flaggad endast för att visa alla trådar.
På menyraden väljer du Felsöka>Fortsätt.
Öppna snabbmenyn för den aktiva raden och välj sedan Lås.
Följande bild av fönstret GPU-trådar visar att alla fyra trådarna är frysta.
Frysta trådar i GPU-trådar-vinduetPå samma sätt visar fönstret Parallel Watch att alla fyra trådarna är låsta.
På menyraden väljer du Felsök>Fortsätt för att tillåta att de följande fyra GPU-trådarna går förbi barriären på rad 22 och når brytpunkten på rad 30. Fönstret GPU-trådar visar att de fyra tidigare låsta trådarna förblir låsta och i aktivt tillstånd.
På menyraden väljer du Felsök, Fortsätt.
Från fönstret Parallell bevakning kan du också tina enskilda eller flera GPU-trådar.
Gruppera GPU-trådar
På snabbmenyn för en av trådarna i fönstret GPU-trådar väljer du Gruppera efter, Adress.
Trådarna i fönstret GPU-trådar grupperas efter adress. Adressen motsvarar instruktionen i disassembly där varje grupp av trådar finns. 24 trådar finns på rad 22 där metoden tile_barrier::wait körs. 12 trådar är enligt instruktionen för barriären på rad 32. Fyra av dessa trådar flaggas. Åtta trådar finns vid brytpunkten på rad 30. Fyra av dessa trådar är frusna. Följande bild visar de grupperade trådarna i fönstret GPU-trådar .
Grupperade trådar i fönstret GPU-trådarDu kan också utföra operationen Gruppera efter genom att öppna snabbmenyn för Parallel Watch-fönstrets datarutnät. Välj Gruppera efter och välj sedan menyalternativet som motsvarar hur du vill gruppera trådarna.
Köra alla trådar till en specifik plats i kod
Du kör alla trådar i en viss panel till den rad som innehåller markören med hjälp av Kör aktuell panel till markör.
Så här kör du alla trådar till den plats som markeras av markören
På snabbmenyn för de låsta trådarna väljer du Thaw.
I kodredigeraren placerar du markören på rad 30.
På snabbmenyn för kodredigeraren väljer du Kör aktuell panel till markör.
De 24 trådar som tidigare blockerades vid barriären vid linje 21 har gått vidare till linje 32. Det visas i fönstret GPU-Trådar.
Se även
Översikt över C++ AMP
Felsöka GPU-kod
Så här använder du fönstret GPU-trådar
Gör så här: Använd fönstret Parallell bevakning
Analysera C++ AMP-kod med Concurrency Visualizer