Programmering

SIMD Intrinsics er ikke så skræmmende, men skal vi bruge dem?

Er programmering på lavt niveau en synd eller en dyd? Det kommer an på.

Når jeg programmerer til brug af vektorbehandling på en moderne processor, vil jeg ideelt set skrive kode på mit yndlingssprog, og den kører så hurtigt som muligt "automatisk magisk."

Medmindre du lige begyndte at programmere i sidste uge, formoder jeg, at du ved, at det ikke er, hvordan verden fungerer. Top ydeevne kommer kun med indsats. Derfor mit spørgsmål: hvor lavt skal vi gå?

Vektoroperationer defineret

En "vektor" -operation er en matematikoperation, der udfører mere end en operation. En vektortilføjelse kan tilføje otte par tal i stedet for den almindelige tilføjelse, som kun tilføjer et par tal. Overvej at bede computeren om at tilføje to tal sammen. Vi kan gøre det med en regelmæssig tilføjelsesinstruktion. Overvej at bede computeren om at tilføje otte par tal til hinanden (beregne C1 = A1 + B1, C2 = A2 + B2, ... C8 = A8 + B8). Vi kan gøre det med en vektor tilføj instruktion.

Vektorinstruktioner inkluderer addition, subtraktion, multiplikation og andre operationer.

 SIMD: parallelitet for vektorer

Computerforskere har et fancy navn til vektorinstruktioner: SIMD eller “Single Instruction Multiple Data.” Hvis vi tænker på en regelmæssig tilføj instruktion som en SISD (Single Instruction Single Data) hvor enkelt betyder et enkelt par dataindgange, så er en vektortilføjelse et SIMD hvor mange kunne betyde otte par dataindgange.

Jeg kan godt lide at kalde SIMD "den anden hardware-parallelisme", da "parallelisme" i computere så ofte betragtes som at komme fra at have flere kerner. Kernetal er steget støt. Kernetællinger på fire er almindelige, 20 eller flere er almindelige i processorer til servere, og Intels største kerneantal i dag er 72 kerner i en enkelt Intel® Xeon Phi ™ -processor.

Vektorinstruktionsstørrelser er også steget. Tidlige vektorinstruktioner, såsom SSE, udførte op til fire operationer ad gangen. Intels øverste vektorbredde i dag i AVX-512 udfører op til 16 operationer ad gangen.

 Hvor lavt skal vi gå?

Med så meget ydeevne på spil, hvor meget arbejde skal vi gøre for at udnytte denne præstation?

Svaret er meget, og her er hvorfor: Fire kerner kan give os 4X hurtigere hastighed. AVX (halv størrelse af AVX-512, men meget mere almindelig) kan give os op til 8X hurtigere hastighed. Kombineret kan de få op til 32X. At gøre begge dele giver meget mening.

Her er min enkle liste over, hvordan man prøver at udnytte vektorinstruktioner (i den rækkefølge, vi skal prøve at anvende dem):

 1.     Ring først til et bibliotek, der udfører arbejdet (det ultimative inden for implicit vektorisering). Et eksempel på et sådant bibliotek er Intel® Math Kernel Library (Intel® MKL). Alt arbejdet med at bruge vektorinstruktioner blev udført af en anden. Begrænsningerne er åbenlyse: Vi er nødt til at finde et bibliotek, der gør, hvad vi har brug for.

2.     For det andet skal du bruge implicit vektorisering. Bliv abstrakt og skriv det selv ved hjælp af skabeloner eller kompilatorer for at hjælpe. Mange compilere har vektoriseringskontakter og muligheder. Compilere er sandsynligvis den mest bærbare og stabile vej at gå. Der har været mange skabeloner til vektorisering, men ingen har set nok brug over tid til at være en klar vinder (en nylig post er Intel® SIMD Data Layout Templates [Intel® SDLT]).

3.     For det tredje skal du bruge eksplicit vektorisering. Dette er blevet meget populært i de senere år og forsøger at løse problemet med at forblive abstrakt, men tvinge compileren til at bruge vektorinstruktioner, når den ellers ikke bruger dem. Støtten til SIMD i OpenMP er nøgleeksemplet her, hvor vektoriseringsanmodninger til compileren gives meget eksplicit. Ikke-standardudvidelser findes i mange kompilatorer, ofte i form af optioner eller "pragmas". Hvis du tager denne rute, er OpenMP vejen at gå, hvis du er i C, C ++ eller Fortran.

4.     Bliv til sidst lav og snavset. Brug SIMD-iboende egenskaber. Det er som monteringssprog, men skrevet i dit C / C ++ - program. SIMD-iboende egenskaber ligner faktisk et funktionsopkald, men genererer generelt en enkelt instruktion (en vektoroperationsinstruktion, også kendt som en SIMD-instruktion).

SIMD-iboende egenskaber er ikke onde; de er dog en sidste udvej. De tre første valg er altid mere vedligeholdelige for fremtiden, når de arbejder. Men når de første tre ikke opfylder vores behov, bør vi bestemt prøve at bruge SIMD-iboende egenskaber.

Hvis du vil komme i gang med at bruge SIMD-iboende egenskaber, har du et seriøst ben, hvis du er vant til at samle sprogprogrammering. Dette skyldes hovedsageligt, at du får lettere ved at læse dokumentationen, der forklarer operationerne, inklusive Intels fremragende online "Intrinsics Guide." Hvis du er helt ny på dette, stødte jeg på en nylig blog ("SSE: mind the gap!"), Der har en blid hånd i introduktionen af ​​iboende egenskaber. Jeg kan også godt lide "Crunching Numbers with AVX and AVX2."

Hvis et bibliotek eller en kompilator kan gøre, hvad du har brug for, er SIMD-iboende ikke det bedste valg. De har dog deres plads, og de er ikke svære at bruge, når du først er vant til dem. Prøv dem. Ydelsesfordelene kan være fantastiske. Jeg har set SIMD-iboende egenskaber brugt af kloge programmerere til kode, som ingen compiler sandsynligvis vil producere.

Selvom vi prøver SIMD-iboende og til sidst lader et bibliotek eller en compiler udføre arbejdet, kan det, vi lærer, være uvurderligt for at forstå den bedste brug af et bibliotek eller en compiler til vektorisering. Og det kan være den bedste grund til at prøve SIMD-intrinsics næste gang vi har brug for noget til at bruge vektorinstruktioner.

Klik her for at downloade din gratis 30-dages prøveversion af Intel Parallel Studio XE