Bob Steagall a rĂ©cemment donnĂ© une confĂ©rence Ă la CppCon 2020 intitulĂ©e " Adventures in SIMD-thinking ", oĂč, entre autres, il a parlĂ© de son expĂ©rience d'utilisation d'AVX512 pour le filtrage mĂ©dian avec la fenĂȘtre 7. Cette confĂ©rence m'a causĂ© deux sentiments: d'un cĂŽtĂ©, c'est cool , et est censĂ© ĂȘtre presque 20x plus rapide que l'implĂ©mentation STL la plus stupide; D'un autre cĂŽtĂ©, en un seul passage de l'algorithme Ă partir de 16 Ă©chantillons d'entrĂ©e, il s'est avĂ©rĂ© que 2 sorties, bien que les donnĂ©es d'entrĂ©e Ă©taient suffisantes pour 10, et certains dĂ©tails d'implĂ©mentation m'ont donnĂ© envie d'essayer de les amĂ©liorer. J'ai pensĂ©, pensĂ© et ai trouvĂ© une idĂ©e, puis une autre, puis je les ai essayĂ©es "dans le logiciel" et j'ai rĂ©alisĂ© que j'avais quelque chose Ă partager :) Donc cet article s'est avĂ©rĂ©.
Implémentation de base
Je décrirai briÚvement comment cela a été fait par Bob (en fait, un court récit de la partie correspondante de son histoire, avec ses propres images). Il a créé les primitives suivantes en utilisant AVX512 (je vais omettre celles des primitives décrites par lui qui correspondent directement à la seule opération AVX512):
rotation: faites pivoter les éléments du registre AVX-512 dans un cercle
décalage avec report : décale les articles d'un registre, remplacement des articles d'un deuxiÚme registre
en place shift avec carry : comme shift avec carry, mais les registres d'entrée sont passés par référence et le résultat du décalage y reste
comparer avec échange : tri parallÚle jusqu'à 8 paires d'éléments dans un registre
, , : perm 0..15, ; mask 1 «» . : , perm. vmin , vmax Ì . , .
, , . :
1) shift with carry, «» , «» (.. 0 0..6, 1 â 1..7 . .)
2) , 0 , 1 â
3) 7 , â 6 compare and exchange, . â â .
0
- , . , , ( , L2). , . AVX-512âŠ
1
, â . 7 ; 6 !
, 6 r1-r6 , r0 r7? S[0..5], X, , S[3] .
X >= S[3]
, S[3] ,X <= S[2]
, S[2] S[3], S[2]S[2] < X < S[3]
, X S[3], , X. ,clamp(X, S[2], S[3])
=>min(max(X, S[2]), S[3])
!
:
«» 4 7- ( 0, 7, 2, 9) â X 4
6- 1..6 3..8 ( 0..7 8..15, )
6-
clamp 2 3 X[0] X[1], 2 3 X[2] X[3]
2x â 2 ( 6 5 , 7 â 6), clamp . : 1,86x . . ?
2
«» X . 6- ; 5 , 2 ( 3 ). â : S[0] <=> S[1], S[2] <=> S[3], S[4] <=> S[5]
2, . . , , !
â 2 , 2 . , : 1.06x. , .
3
- , 1, 6- .
, 4 ( ), 6; , 4- ?
2 , 4- . 6- : 2- Y 4- S, 2 3 ( Z). , min(Y[0], S[0]) => Z[0]
, ; max(Y[0], S[0])
Z[1]..Z[5] â . max(Y[1], S[3])
, min(Y[1], S[3])
.
4- S[1], S[2], min/max. , 4 , 1 2 â 2 3 6- . , «» 4- S[1] S[2], â . , 2 , Y.
:
r1-r2 . .
â Y, r1-2, r5-6, r7-8, r11-12; permute 4 , Y r0-1, r4-5 . .
( ) «» ; r3-r6 r7-r10
max min Y[0]/S[0], Y[1]/S[3]
mask_permute Y S, S[1] S[2] ,
4
1 2, min/max X 8
, , , 2. â 1.64x , 2, 3 , .
; ( - permute; , - ), .
, :)
benchmark:
512 : 3.1-3.2 ; 7.3 , memcpy avx-512
50 : 2.8-2.9 ; 1.8 , memcpy (!)
.
5? , (disclaimer: â ).
16- 12 .
- 3 ( âŠ)
1 , 4 ( 6 ) 4- â , . . 4 , 5 ; 8 .
2 , â 2 ; , .
3 , . , â , 12 . , «» â 24 , 12 .
9? 8 .
â
1 â 2 8- 4 , 4 ( 7 6 )
2 â , -
3 â , â 6- 2, 6- ( , ) , 8-.
, - . , https://github.com/tea/avx-median/. « », , -. , .
- , â . .
UPDATE
AVX2 . , , , , ( , 16 , ). , : 1.64x , .
Il s'est avĂ©rĂ© que tout n'est pas perdu - la premiĂšre Ă©tape d'optimisation peut Ă©galement ĂȘtre appliquĂ©e Ă cette variante! Vous devez collecter 32 arĂȘtes de X, vous devez brouiller les donnĂ©es pour le tri, les donnĂ©es triĂ©es doivent Ă©galement ĂȘtre permutĂ©es, etc., mais malgrĂ© tous ces gestes, nous avons obtenu une accĂ©lĂ©ration de 1,27 fois.
Je n'ai pas essayĂ© de faire les Ă©tapes 2 et 3, car ce sera Ă©videmment plus lent. Il est tout Ă fait possible que pour le cas, par exemple, de la fenĂȘtre 11, ils fonctionnent dans un plus (seulement si quelqu'un a besoin d'un filtre 1D-mĂ©dian rapide avec de grandes fenĂȘtres - je ne sais pas).