Programmering

SIMD Intrinsics er ikke så skummelt, men skal vi bruke dem?

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

Når jeg programmerer for bruk av vektorbehandling på en moderne prosessor, vil jeg ideelt sett skrive litt kode på favorittspråket mitt, og det vil kjøre så raskt som mulig "automatisk magisk."

Med mindre du nettopp begynte å programmere forrige uke, mistenker jeg at du vet at det ikke er slik verden fungerer. Topp ytelse kommer bare med innsats. Derav spørsmålet mitt: hvor lavt skal vi gå?

Vektoroperasjoner definert

En "vektor" -operasjon er en matteoperasjon som gjør mer enn en operasjon. Et vektortillegg kan legge til åtte par tall i stedet for det vanlige tillegget, som bare legger til ett par tall. Vurder å be datamaskinen om å legge to tall sammen. Vi kan gjøre det med en vanlig instruksjon. Vurder å be datamaskinen om å legge til åtte par tall til hverandre (beregne C1 = A1 + B1, C2 = A2 + B2, ... C8 = A8 + B8). Vi kan gjøre det med en vektor legge til instruksjon.

Vektorinstruksjoner inkluderer addisjon, subtraksjon, multiplikasjon og andre operasjoner.

 SIMD: parallellisme for vektorer

Dataforskere har et fancy navn på vektorinstruksjoner: SIMD, eller “Single Instruction Multiple Data.” Hvis vi tenker på en vanlig legg til instruksjon som en SISD (Single Instruction Single Data) hvor enkelt betyr et enkelt par datainnganger, så er et vektortillegg et SIMD hvor flere kan bety åtte par datainnganger.

Jeg liker å kalle SIMD "den andre maskinvareparallellismen", siden "parallellitet" i datamaskiner ofte blir sett på som å ha flere kjerner. Kjernetallene har økt jevnlig. Kjernetellinger på fire er vanlige, 20 eller flere er vanlige i prosessorer for servere, og Intels toppkjernetall i dag er 72 kjerner i en enkelt Intel® Xeon Phi ™ -prosessor.

Vectorinstruksjonsstørrelser har også økt. Tidlige vektorinstruksjoner, for eksempel SSE, utførte opptil fire operasjoner om gangen. Intels toppvektorbredde i dag, i AVX-512, utfører opptil 16 operasjoner om gangen.

 Hvor lavt skal vi gå?

Med så mye ytelse på spill, hvor mye arbeid skal vi gjøre for å utnytte denne forestillingen?

Svaret er mye, og her er hvorfor: Fire kjerner kan gi oss 4X hastighet på det meste. AVX (halvparten av størrelsen på AVX-512, men mye mer vanlig) kan gi oss opptil 8 ganger raskere hastighet. Kombinert kan de få opptil 32X. Å gjøre begge deler er veldig fornuftig.

Her er min enkle liste over hvordan du prøver å utnytte vektorinstruksjoner (i den rekkefølgen vi skal prøve å bruke dem):

 1.     Først, ring et bibliotek som utfører arbeidet (det ultimate innen implisitt vektorisering). Et eksempel på et slikt bibliotek er Intel® Math Kernel Library (Intel® MKL). Alt arbeidet med å bruke vektorinstruksjoner ble gjort av noen andre. Begrensningene er åpenbare: Vi må finne et bibliotek som gjør det vi trenger.

2.     For det andre, bruk implisitt vektorisering. Hold deg abstrakt og skriv det selv ved hjelp av maler eller kompilatorer for å hjelpe. Mange kompilatorer har vektoriseringsbrytere og alternativer. Kompilatorer er sannsynligvis den mest bærbare og stabile veien å gå. Det har vært mange maler for vektorisering, men ingen har sett nok bruk over tid til å være en klar vinner (en nylig oppføring er Intel® SIMD Data Layout Templates [Intel® SDLT]).

3.     For det tredje, bruk eksplisitt vektorisering. Dette har blitt veldig populært de siste årene, og prøver å løse problemet med å holde seg abstrakt, men tvinge kompilatoren til å bruke vektorinstruksjoner når den ellers ikke ville brukt dem. Støtten for SIMD i OpenMP er nøkkeleksemplet her, der vektoriseringsforespørsler for kompilatoren er gitt veldig eksplisitt. Ikke-standardutvidelser finnes i mange kompilatorer, ofte i form av opsjoner eller "pragmas". Hvis du tar denne ruten, er OpenMP veien å gå hvis du er i C, C ++ eller Fortran.

4.     Til slutt, bli lav og skitten. Bruk SIMD iboende. Det er som monteringsspråk, men skrevet i C / C ++ - programmet. SIMD-egenutstyr ser faktisk ut som et funksjonsanrop, men produserer vanligvis en enkelt instruksjon (en vektoroperasjonsinstruksjon, også kjent som en SIMD-instruksjon).

SIMD iboende er ikke onde; de er imidlertid en siste utvei. De tre første valgene er alltid mer vedlikeholdbare for fremtiden når de jobber. Men når de tre første ikke oppfyller våre behov, bør vi definitivt prøve å bruke SIMD-egenutstyr.

Hvis du vil komme i gang med SIMD-egenutstyr, vil du ha et alvorlig skritt hvis du er vant til å samle språkprogrammering. Dette skyldes hovedsakelig at du får lettere for å lese dokumentasjonen som forklarer operasjonene, inkludert Intels utmerkede online "Intrinsics Guide." Hvis du er helt ny på dette, kjørte jeg over en nylig blogg (“SSE: mind the gap!”) Som har en mild hånd i innføringen av egenart. Jeg liker også "Crunching Numbers with AVX and AVX2."

Hvis et bibliotek eller kompilator kan gjøre det du trenger, er ikke SIMD-egensnitt det beste valget. Imidlertid har de sin plass, og de er ikke vanskelige å bruke når du blir vant til dem. Prøv dem. Ytelsesfordelene kan være fantastiske. Jeg har sett SIMD-egenart brukt av smarte programmerere for kode som ingen kompilator sannsynligvis vil produsere.

Selv om vi prøver SIMD-egenskapene, og til slutt lar et bibliotek eller en kompilator gjøre jobben, kan det vi lærer være uvurderlig for å forstå den beste bruken av et bibliotek eller kompilator for vektorisering. Og det kan være den beste grunnen til å prøve SIMD-egenutstyr neste gang vi trenger noe for å bruke vektorinstruksjoner.

Klikk her for å laste ned en gratis 30-dagers prøveversjon av Intel Parallel Studio XE

$config[zx-auto] not found$config[zx-overlay] not found