2010-07-14 100 views
2

我想知道如果簡單地編譯我的msvc項目與sse/sse2將有任何影響。我做例如矢量規範化和點積,但我做這些數學,而不是任何特定的功能。有沒有像我應該使用sse_dot()和sse_normalize()來真正利用,還是編譯器知道?如何使用SSE(1,2,3,4)優化?

感謝

+1

你爲什麼不直接嘗試一下? – Nils 2011-07-23 20:14:06

回答

6

據我所知,使用sse2編譯器選項將導致編譯器使用標量而非向量sse2指令代替正常的fpu代碼。我不認爲它會做矢量化。 sse2標量的東西肯定比fpu快。

要使用矢量單位,您需要直接使用內在函數(xmmintrin.h)或使用第三方庫。如果你只是做簡單的矢量/矩陣的東西進行渲染,Bullet SDK有一個優化的向量數學庫,這並不壞。 IIRC DirectX/XNAmath庫也進行了優化。

如果這兩者都不看好,Google應該提出一些替代方案。

+1

作爲一種語言擴展,gcc具有內置向量類型和用sse指令實現的僞函數(如果可用)。只要gcc在體系結構上運行,它應該是可移植的,並且也應該適用於像icc這樣的派生編譯器。 – 2010-07-15 05:20:12

3

或者你可以避免通過使用高性能庫像徵,BLAS,英特爾MKL,...明確寫入SSE東西除非你是嵌入式系統的工作,這些庫會更好比你想出的任何東西都要多。

-10

如果啓用SSE2,那麼編譯器會在後面使用它。除非您打算在沒有SSE2的情況下支持CPU,否則您將永遠不會注意也不需要知道。這與任何其他底層CPU指令相同。

+2

只需在x87上使用SSE2代碼路徑遠不能自動矢量化代碼。自動矢量化是一個非常棘手的話題,編譯器很差(當它支持所有的時候) – 2010-07-15 00:43:32

+0

哇,-7和OP選擇... – 2010-12-21 15:48:29

+0

@ ring0:我能說什麼?我顯然只是一部史詩般的WinRAR。 – Puppy 2010-12-21 16:26:54

1

不是所有的編譯器都像你想象的那麼聰明。即使gcc可能並不總是優化最明顯的代碼。看下面的例子,並自己嘗試。 Icc似乎能夠優化內部循環,但gcc,因爲我嘗試了幾個設置,不能。必要時,您必須使用SSE功能手動調用SSE/SSE2指令。人們告訴我this是一個很好的教程。

編輯:下面的例子適用於Mac/Linux gcc。但它在linux上失敗了icc。我不知道爲什麼。順便說一句,icc被認爲比矢量化gcc更好。

#include <stdlib.h> 
#include <stdio.h> 
#include <time.h> 
#include <math.h> 
#include <emmintrin.h> 

float **mm_init(int n) 
{ 
    float **m; 
    int i; 
    m = (float**)malloc(n * sizeof(void*)); 
    for (i = 0; i < n; ++i) 
     m[i] = calloc(n, sizeof(float)); 
    return m; 
} 
void mm_destroy(int n, float **m) 
{ 
    int i; 
    for (i = 0; i < n; ++i) free(m[i]); 
    free(m); 
} 
float **mm_gen(int n) 
{ 
    float **m; 
    int i, j; 
    m = mm_init(n); 
    for (i = 0; i < n; ++i) 
     for (j = 0; j < n; ++j) 
      m[i][j] = 2 * drand48() - 1.0; 
    return m; 
} 
// better cache performance by transposing the second matrix 
float **mm_mul2(int n, float *const *a, float *const *b) 
{ 
    int i, j, k; 
    float **m, **c; 
    m = mm_init(n); c = mm_init(n); 
    for (i = 0; i < n; ++i) // transpose 
     for (j = 0; j < n; ++j) 
      c[i][j] = b[j][i]; 
    for (i = 0; i < n; ++i) { 
     float *p = a[i], *q = m[i]; 
     for (j = 0; j < n; ++j) { 
      float t = 0.0, *r = c[j]; 
      for (k = 0; k < n; ++k) 
       t += p[k] * r[k]; 
      q[j] = t; 
     } 
    } 
    mm_destroy(n, c); 
    return m; 
} 
// explicit SSE optimization for the inner loop 
float **mm_mul3(int n, float *const *a, float *const *b) 
{ 
    int i, j, k; 
    float **m, **c, x[4]; 
    m = mm_init(n); c = mm_init(n); 
    for (i = 0; i < n; ++i) // transpose 
     for (j = 0; j < n; ++j) 
      c[i][j] = b[j][i]; 
    for (i = 0; i < n; ++i) { 
     float *p = a[i], *q = m[i]; 
     for (j = 0; j < n; ++j) { 
      __m128 t = _mm_setzero_ps(); 
      float *r = c[j]; 
      for (k = 0; k < n; k += 4) // four operations in one CPU cycle 
       t = _mm_add_ps(t, _mm_mul_ps(_mm_load_ps(p+k), _mm_load_ps(r+k))); 
      _mm_store_ps(x, t); 
      q[j] = x[0] + x[1] + x[2] + x[3]; 
     } 
    } 
    mm_destroy(n, c); 
    return m; 
} 

int main(int argc, char *argv[]) 
{ 
    int n = 100; 
    float **a, **b, **m; 
    clock_t t; 
    if (argc > 1) n = atoi(argv[1]); 
    n = (n + 3)/4 * 4; // for simplicity, n can be divided by 4 
    srand48(11); 
    a = mm_gen(n); b = mm_gen(n); 

    t = clock(); 
    m = mm_mul2(n, a, b); 
    fprintf(stderr, "cache: %lf sec; M[%d][%d]=%f\n", (double)(clock() - t)/CLOCKS_PER_SEC, n/2, n/2, m[n/2][n/2]); 

    t = clock(); 
    m = mm_mul3(n, a, b); 
    fprintf(stderr, "SSE: %lf sec; M[%d][%d]=%f\n", (double)(clock() - t)/CLOCKS_PER_SEC, n/2, n/2, m[n/2][n/2]); 

    mm_destroy(n, a); mm_destroy(n, b); mm_destroy(n, m); 
    return 0; 
} 
3

無論是自己寫的代碼SSE(ASM或內在),使用第三方SSE優化的庫(例如IPP,MKL,等等),或使用自動向量化編譯器如Intel的ICC。