2017-08-05 51 views
0

我必須在我的圖像的每個點上應用一個變換矩陣來獲得新的點座標。如何優化矩陣3乘以3與SSE點?

爲此,我創建了一個自定義Matrix3by3類,其中包含大小爲9的浮點數組。

到矩陣應用到每個點,首先,我創造了這個功能:

constexpr auto apply_matrix(const Matrix3by3 & m, const Vec2i & p) -> Vec2f 
{ 
    const auto x = m.at(0, 0) * p.x + m.at(0, 1) * p.y + m.at(0, 2); 
    const auto y = m.at(1, 0) * p.x + m.at(1, 1) * p.y + m.at(1, 2); 
    const auto z = m.at(2, 0) * p.x + m.at(2, 1) * p.y + m.at(2, 2); 

    return { x/z, y/z }; 
} 

正如你所看到的,這個函數會做簡單的矩陣乘法沒有最後乘法,因爲在我的2D沒有Z值圖片。

這個偉大的工程,但由於這部分代碼是熱碼,我試圖去優化它,所以我創建它的SSE版本:

constexpr auto apply_matrix(const Matrix3by3 & m, const Vec2i & p) -> Vec2f 
{ 
    using SSEVec3 = union { 
    struct 
    { 
     float z, y, x; 

    }; 
    __m128 values_ = _mm_setzero_ps(); 
    }; 

    const auto mvec1 = _mm_set_ps(0, m.at(0, 0), m.at(0, 1), m.at(0, 2)); 
    const auto mvec2 = _mm_set_ps(0, m.at(1, 0), m.at(1, 1), m.at(1, 2)); 
    const auto mvec3 = _mm_set_ps(0, m.at(2, 0), m.at(2, 1), m.at(2, 2)); 

    const auto pvec1 = _mm_set1_ps(static_cast<float>(p.x)); 
    const auto pvec2 = _mm_set1_ps(static_cast<float>(p.y)); 

    auto result = SSEVec3{}; 
    result.values_ = _mm_add_ps(_mm_add_ps(_mm_mul_ps(mvec1, pvec1), _mm_mul_ps(mvec2, pvec2)), mvec3); 

    return { result.x/result.z, result.y/result.z }; 
} 

這工作過,但它是比第一個版本慢,而且由於我正在學習SSE,所以我不明白爲什麼會出現這種情況。

我對這第二個版本的想法是並行執行x,y和z值計算。

所以,這是我的問題,爲什麼SSE版本更慢,我怎麼能優化它儘可能快?

謝謝!

+0

每當在此級別進行優化時,您應該檢查生成的彙編代碼:'gcc -S'。你可以讓你的代碼更完整:周圍的代碼是什麼樣的?你幾次從跑步中獲得什麼?另外,當試圖比較它們的性能時,我會避免聲明函數constexpr。 – dlasalle

+0

我認爲這可能是由z最終劃分的主宰。無論如何,你應該首先看看你的明顯版本的反彙編輸出。考慮到現代C++風格,你可能正在使用一個非常新近的編譯器,其中可能會啓用自動矢量化。 根據你有什麼芯片,使用mm_set_ps和m.at的手動存儲也會殺了你。 SSE沒有「收集」指令,因此做一個未對齊的加載,然後掩蓋掉最低的單詞或者忽略結果。 – cnettel

+2

以這種方式濫用'_mm_set_ps'是一種主要的反模式,應該確實是一個適當的寬負載(如果需要,它會加載一個通道太多,填充)。 – harold

回答

2

一般來說,只優化需要優化的內容,而不是你所需要的。

可能是(原始)代碼中的單個最差點,而您的「優化」根本沒有幫助,它是重複的分區。除此之外,浮點數或雙精度比這段代碼中的所有內容都要差,因此最佳優化方法是通過計算1/z(將除以)並將其與結果相乘兩次,從而減少漂移或雙精度。

但是 - 正如開始時所說 - 您可能不需要任何優化,或者您可能需要其他優化。測試,配置文件,並尋找最慢的編碼。猜測結果通常是浪費精力和不必要的代碼複雜性。

+2

當然,既然我們在做SSE,那麼這兩個部門可以安排在同一個指令中完成,這可能比乘以相互的更好(除非使用大約收件人) – harold