2015-12-06 1 views
1

Je suis nouveau à utiliser le coprocesseur XeonPhi Intel. Je veux écrire du code pour une somme de Vector simple en utilisant les instructions du bit AVX 512. J'utilise k1om-mpss-linux-gcc en tant que compilateur et je veux écrire en ligne. Ici c'est mon code:Somme de vecteur utilisant AVX Inline Assembly sur XeonPhi

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/time.h> 
#include <assert.h> 
#include <stdint.h> 

void* aligned_malloc(size_t size, size_t alignment) { 

    uintptr_t r = (uintptr_t)malloc(size + --alignment + sizeof(uintptr_t)); 
    uintptr_t t = r + sizeof(uintptr_t); 
    uintptr_t o =(t + alignment) & ~(uintptr_t)alignment; 
    if (!r) return NULL; 
    ((uintptr_t*)o)[-1] = r; 
    return (void*)o; 
} 

int main(int argc, char* argv[]) 
{ 
    printf("Starting calculation...\n"); 
    int i; 
    const int length = 65536; 

    unsigned *A = (unsigned*) aligned_malloc(length * sizeof(unsigned), 64); 
    unsigned *B = (unsigned*) aligned_malloc(length * sizeof(unsigned), 64); 
    unsigned *C = (unsigned*) aligned_malloc(length * sizeof(unsigned), 64); 

    for(i=0; i<length; i++){ 
      A[i] = 1; 
      B[i] = 2; 
    } 

    const int AVXLength = length/16; 
    unsigned char * pA = (unsigned char *) A; 
    unsigned char * pB = (unsigned char *) B; 
    unsigned char * pC = (unsigned char *) C; 
    for(i=0; i<AVXLength; i++){ 
      __asm__("vmovdqa32 %1,%%zmm0\n" 
        "vmovdqa32 %2,%%zmm1\n" 
        "vpaddd %0,%%zmm0,%%zmm1;" 
      : "=m" (pC) : "m" (pA), "m" (pB)); 

      pA += 64; 
      pB += 64; 
      pC += 64; 
    } 

    // To prove that the program actually worked 
    for (i=0; i <5 ; i++) 
    { 
      printf("C[%d] = %f\n", i, C[i]); 
    } 

} 

Cependant quand je cours le programme, j'ai la panne de segmentation de la partie d'asm. Quelqu'un peut-il m'aider avec ça ???

Merci

+2

KNC ne prend pas en charge AVX-512. Vous devez attendre KNL pour cela. Vous devrez regarder si et comment le faire avec KNC en utilisant son ISA. – Jeff

+1

Et essayez intrinsèques d'abord avec le compilateur Intel. – Jeff

+0

Merci Jeff, mais ce n'est pas la source de mon erreur de segmentation. J'ai essayé 256 bits aussi, mais je n'ai pas réussi –

Répondre

2

Bien que Knights Corner (KNC) ne possède pas AVX512, il a quelque chose de très similaire. Beaucoup de mnémoniques sont les mêmes. En fait, dans le cas de l'OP, les mnémotechniques vmovdqa32 et vpaddd sont les mêmes pour AVX512 et KNC.

Les opcodes sont probablement différents mais le compilateur/assembleur s'en charge. Dans le cas d'OP, il/elle utilise une version spéciale de GCC, k1om-mpss-linux-gcc qui fait partie du many core software stack KNC qui génère vraisemblablement les opcodes corrects. On peut compiler sur l'hôte en utilisant k1om-mpss-linux-gcc puis scp le binaire à la carte KNC. J'ai appris à ce sujet à partir d'un commentaire au this question.


Quant à savoir pourquoi le code ne parvient pas OPs je ne peux pas faire deviner que je n'ai pas une carte KNC pour tester avec. Dans mon expérience limitée avec l'assemblage en ligne GCC, j'ai appris qu'il est bon de regarder l'assemblage généré dans le fichier objet pour s'assurer que le compilateur a fait ce que vous attendiez.

Lorsque je compile votre code avec une version normale de GCC, je vois que la ligne "vpaddd %0,%%zmm0,%%zmm1;" produit l'assemblage avec le point-virgule. Je ne pense pas que le point-virgule devrait être là. Cela pourrait être un problème.

Mais depuis organophosphorés mnémoniques sont les mêmes que AVX512 nous pouvons en utilisant intrinsics AVX512 pour comprendre l'assemblage correct

#include <x86intrin.h> 
void foo(int *A, int *B, int *C) { 
    __m512i a16 = _mm512_load_epi32(A); 
    __m512i b16 = _mm512_load_epi32(B); 
    __m512i s16 = _mm512_add_epi32(a16,b16); 
    _mm512_store_epi32(C, s16); 
} 

et gcc -mavx512f -O3 -S knc.c procudes

vmovdqa64 (%rsi), %zmm0 
vpaddd  (%rdi), %zmm0, %zmm0 
vmovdqa64 %zmm0, (%rdx) 

GCC a choisi vmovdqa64 au lieu de vmovdqa32 même si la documentaion Intel dit qu'il devrait être vmovdqa32. Je ne suis pas sûr pourquoi. Je ne sais pas quelle est la différence. J'aurais pu utiliser le _mm512_load_si512 intrinsèque qui existe et selon Intel devrait correspondre à vmovdqa32 mais GCC le mappe également à vmovdqa64. Je ne suis pas sûr pourquoi il y a aussi _mm512_load_epi32 et _mm512_load_epi64 maintenant. SSE et AVX n'ont pas ces intrinsèques correspondants.

Basé sur le code de GCC est l'ensemble en ligne ici, j'utiliser

__asm__ ("vmovdqa64 (%1), %%zmm0\n" 
     "vpaddd  (%2), %%zmm0, %%zmm0\n" 
     "vmovdqa64 %%zmm0, (%0)" 
     : 
     : "r" (pC), "r" (pA), "r" (pB) 
     : "memory" 
); 

Peut-être vmovdqa32 doit être utilisé au lieu de vmovdqa64 mais je pense qu'il n'a pas d'importance.

J'ai utilisé le modificateur de registre r au lieu du modificateur de mémoire m parce que l'expérience passée m le modificateur de mémoire n'a pas produit l'ensemble je m'y attendais.


Une autre possibilité d'envisager est d'utiliser une version de GCC qui prend en charge pour générer intrinsics AVX512 l'assemblage, puis utiliser la version KNC spéciale de GCC pour convertir l'ensemble en binaire. Par exemple

gcc-5.1 -O3 -S foo.c 
k1om-mpss-linux-gcc foo.s 

Cela peut avoir des ennuis depuis k1om-mpss-linux-gcc est probablement une ancienne version de GCC. Je n'ai jamais fait quelque chose comme ça avant mais ça peut marcher.


Comme expliqué here la raison pour laquelle les intrinsics AVX512

_mm512_load/store(u)_epi32 
_mm512_load/store(u)_epi64 
_mm512_load/store(u)_si512 

est que les paramètres ont été convertis en void*. Par exemple avec SSE vous devez jeter

int *x; 
__m128i v; 
__mm_store_si128((__m128*)x,v) 

alors qu'avec SSE vous ne devez plus

int *x; 
__m512i; 
__mm512_store_epi32(x,v); 
//__mm512_store_si512(x,v); //this is also fine 

Il est toujours pas clair pour moi pourquoi il est vmovdqa32 et vmovdqa64 (GCC semble seulement utiliser vmovdqa64 actuellement) mais il est probablement similaire à movaps et movapd dans SSE qui n'ont pas de réelle différence et n'existe que dans le cas où ils peuvent faire une différence dans le futur.


Le but de vmovdqa32 et vmovdqa64 est pour le masquage qui peut être fait avec ces intrsics

_mm512_mask_load/store_epi32 
_mm512_mask_load/store_epi64 

Sans masque les instructions sont équivalentes.

4

Xeon Phi Knights d'angle ne prend pas en charge AVX. Il ne prend en charge qu'un ensemble spécial d'extensions vectorielles, appelé Intel Initial Many Core Instructions (Intel IMCI) avec une taille de vecteur de 512b. Essayer de placer n'importe quel type d'assemblage spécifique à AVX dans un code KNC entraînera des plantages.

Attendez simplement Knights Landing. Il prendra en charge les extensions vectorielles AVX-512.

+1

Les mnésiques pour KNX 512 bits KNC et AVX512 sont les mêmes dans de nombreux cas. C'est vrai dans le cas des OP. Le PO doit donc avoir un compilateur qui génère les bons opcodes en supposant que son assemblage est correct. –