2017-03-07 15 views
2

Xeon-Phi Knights 랜딩 코어는 exp2 명령어 vexp2pd (내장형 _mm512_exp2a23_pd)을 가지고 있습니다. 인텔 C++ 컴파일러는 컴파일러와 함께 제공되는 SVML (Short Vector Math Library)을 사용하여 exp 함수를 벡터화 할 수 있습니다. 특히, fx __svml_exp8을 호출합니다.은 SVML의 함수 호출을 오버라이드합니다.

그러나 디버거를 거치면 은 vexp2pd 명령어를 사용하고 있지 않습니다. 이는 많은 FMA 작업과 관련된 복잡한 기능입니다. 나는 vexp2pdexp보다 덜 정확하다는 것을 이해합니다. 그러나 -fp-model fast=1 (기본값) 또는 fp-model fast=2을 사용하면 컴파일러가이 명령어를 사용하지만 예상하지는 않습니다.

두 가지 질문이 있습니다.

  1. 컴파일러를 사용하여 vexp2pd을 얻는 방법이 있습니까?
  2. __svml_exp8에 대한 호출을 안전하게 재정의하려면 어떻게해야합니까?

두 번째 질문에 대해서는 이것이 지금까지 내가 한 것입니다.

//exp(x) = exp2(log2(e)*x) 
extern "C" __m512d __svml_exp8(__m512d x) {   
    return _mm512_exp2a23_pd(_mm512_mul_pd(_mm512_set1_pd(M_LOG2E), x)); 
} 

이 안전한가요? 예를 들어 더 나은 솔루션이 있습니까? 기능을 인라인하는 사람? 아래의 테스트 코드에서 오버 라이드하지 않은 경우보다 약 3 배 빠릅니다.

//https://godbolt.org/g/adI11c 
//icpc -O3 -xMIC-AVX512 foo.cpp 
#include <math.h> 
#include <stdio.h> 
#include <x86intrin.h> 

extern "C" __m512d __svml_exp8(__m512d x) { 
    //exp(x) = exp2(log2(e)*x) 
    return _mm512_exp2a23_pd(_mm512_mul_pd(_mm512_set1_pd(M_LOG2E), x)); 
} 

void foo(double * __restrict x, double * __restrict y) { 
    __assume_aligned(x, 64); 
    __assume_aligned(y, 64); 
    for(int i=0; i<1024; i++) y[i] = exp(x[i]); 
} 

int main(void) { 
    double x[1024], y[1024]; 
    for(int i=0; i<1024; i++) x[i] = 1.0*i; 
    for(int r=0; r<1000000; r++) foo(x,y); 
    double sum=0; 
    //for(int i=0; i<1024; i++) sum+=y[i]; 
    for(int i=0; i<8; i++) printf("%f ", y[i]); puts(""); 
    //printf("%lf",sum); 
} 
+0

'vexp2pd'를 사용하여 30 비트 정밀도를 버리도록 컴파일러에게 요청합니다. 그것은 빠른 수학으로도 그렇게하지 않을 것입니다. – Mysticial

+0

@Mysticial 컴파일러에서'vrcp28pd' (실제로는 [https://godbolt.org/g/Wya9Ic])를 볼 수 있습니다. 그래서 빠른 상호를 사용한다면 왜 빠른 'exp'가 아니겠습니까? 그 코드를 보면서 상호 코드를 살펴보면 뉴턴이나 다른 것의 반복을하는 것처럼 보일 수도 있습니다 (그렇지 않으면 모든 FMA와 관련이 있습니다).그것은 왜 그것이 빠른 상호가 아닌 빠른'exp'를 사용하는지 설명 할 수 있습니다. –

+0

나는'vfixupimmpd'에 대해 들어 본 적이 없다. 이상한 지시. 본질 가이드에 따르면 AVXVL이 필요하지만 AVXVL이없는 KNL 용으로 생성합니다. –

답변

4

ICC는 vexp2pd를 생성하지만 대상이 지정된 -fimf * 스위치에 지정된 것처럼 매우 완화 된 수학 요구 사항을 충족합니다.

#include <math.h> 

void vfoo(int n, double * a, double * r) 
{ 
    int i; 
    #pragma simd 
    for (i = 0; i < n; i++) 
    { 
     r[i] = exp(a[i]); 
    } 
} 

예 : = 1 -fimf 정확도 비트 = 22

..B1.12: 
     vmovups (%rsi,%rax,8), %zmm0 
     vmulpd .L_2il0floatpacket.2(%rip){1to8}, %zmm0, %zmm1 
     vexp2pd %zmm1, %zmm2 
     vmovupd %zmm2, (%rcx,%rax,8) 
     addq  $8, %rax 
     cmpq  %r8, %rax 
     jb  ..B1.12 

로 정확도에 미치는 영향을 이해하시기 바랍니다 -xMIC-AVX512 -fimf 도메인 배제 컴파일뿐만 아니라 최종 결과는 22 비트 정확, 그러나 vexp2pd는 MXCSR에 설정된 FTZ/DAZ 비트와 관계없이 비정규 화 된 결과를 0으로 플러시합니다.

두 번째 질문 : "__svml_exp8에 대한 호출을 어떻게 안전하게 재정의합니까?" 접근 방법은 일반적으로 안전하지 않습니다. SVML 루틴은 인텔 컴파일러의 내부 도구이며 사용자 정의 호출 규칙에 의존하므로 동일한 이름을 가진 일반 루틴이 라이브러리 루틴보다 레지스터를 더 많이 차지할 수 있으며 디버깅하기 어려운 ABI 불일치로 끝날 수 있습니다.

자신의 벡터 함수를 제공하는 더 좋은 방법은 #pragma omp declare simd를 활용하는 것입니다. 내장 함수를 사용한 코딩을 선호하는 경우 https://software.intel.com/en-us/node/524514 및 가능한 경우 vector_variant 특성을 참조하십시오 (https://software.intel.com/en-us/node/523350 참조). 표준 수학 이름을 무시하려고 시도하지 마십시오. 오류가 발생합니다.

+0

당신의 코드는 ICC 17을 가지고 나를 위해'vexp2pd'를 생성하지 않습니다. 많은 변형을 시도했습니다. 그러나 만약 당신의 답안에서'exp'를'exp2'로 바꾸면'vexp2pd'가 생성됩니다. –

+1

18.0 (현재 베타 버전)으로 시도하십시오. – NikitaA