一個故事看懂CPU的SIMD技術

軒轅之風發表於2022-03-24

好久不見,我叫阿Q,是CPU一號車間的員工。我所在的CPU有8個車間,也就是8個核心,我們們每個核心都可以同時執行兩個執行緒,就是8核16執行緒,那速度槓槓滴。

我所在的一號車間,除了負責執行指令的我,還有負責讀取指令的小A,負責指令譯碼的小胖和負責結果回寫的老K,我們幾個各司其職,一起完成執行程式的工作。

一個簡單的迴圈

那天,我們遇到了一段程式碼:

void array_add(int data[], int len) {
  for (int i = 0; i < len; i++) {
    data[i] += 1;
  }
}

迴圈了好幾百次之後,才把這段程式碼執行完成,每次迴圈都是做簡單又重複的工作,把我累得夠嗆。

一旁負責結果回寫的老K也是累的滿頭大汗,吐槽道:“每次都是取出來加1又寫回去,要是能一次多取幾個數,批量處理就好了”

老K的話讓我眼前一亮,對啊,能不能批量操作呢?

心裡一邊想著,一邊繼續幹活了。

繁忙的一天很快結束了,轉眼又到了晚上,計算機關機後,我把大家召集了起來。

“兄弟們,還記得我們們白天遇到的那個迴圈嗎?”

“你說哪個迴圈,我們們這一天可執行了不少迴圈呢”,小A說到。

“就是那個把整數陣列每個元素都加1的那個迴圈”

“我想起來了,那迴圈怎麼了?有什麼問題嗎?”

我看了老K一眼,說道:“我在想今天老K的話,像這種迴圈,每次都是取出來加1又寫回去,一次操作一個數,效率太低了,我們們要是升級改造一下,支援一次取出多個數,批量加1,這樣豈不是快很多?”

老K一聽來了興趣,“這敢情好,你打算怎麼做?”

“這我還沒想好,大家有什麼建議嗎?”

一旁負責指令譯碼的小胖說道:“可以新增一條指令,專門用來一次取出多個資料來加1”

“不行不行,不能限的這麼死,今天是加1,萬一下次是加2呢?指令裡面不能限制為1”

“那如果每個資料要加的是不一樣的怎麼辦?”

“你這麼一說,那萬一不是加法,是減法,乘法怎麼辦?”

“還有啊,···”

大家開始七嘴八舌討論了起來,沒想到一個小小的加法迴圈,一下子引出了這麼多問題來,這是我們沒想到的。

平行計算

隨著討論的深入,我覺得已經超出了我們們一號車間能把控的範圍,需要上報給領導,組織八個車間代表一起來商討。

領導一聽說有提高效能的新技術,馬上來了興趣,很快便開會組織大家一起來商討方案。

“都到齊了是吧,阿Q你給大家說一下這個會議的目的”,領導說到。

我站了起來,開始把我們遇到的問題和想法跟大家講了一遍。

“是這樣的,我們一號車間那天遇到了一段迴圈程式碼,迴圈體的內容很簡單,就是給陣列中的每一個元素加1。我們執行的時候,就是不斷取出每一個元素,然後將其執行加法計算後,再寫回去。這樣一個一個來加1,我們感覺太慢了, 要是可以一次多取幾個,並行加1,那一定比一個一個加快上不少。”

我剛說完,大家都開始小聲議論起來。

“我看出來了,這其實就是平行計算!”,二號車間小虎一語道出了關鍵。

六號車間小六問道:”阿Q,你們已經有方案了嗎?“

“還沒有,這正是今天開會的目的,因為情況有點複雜,還需要大家一起來出出主意”

“好像並不複雜嘛”

“我上面舉的例子只是一個簡單的情況,平行計算還可能不是固定的數,可能是一個陣列和另一個陣列相加。還有可能不是整數相加,而是浮點數,甚至,還可能不是加法,而是減法或者乘法,再或者不是算術運算,而是邏輯運算”

我剛一說完,大家又開始竊竊私語交流起來。

“我琢磨著你說的這一系列東西,我們們是要新增一套專門用來平行計算的指令集啊”,小虎說道。

“這可是大工程啊”

“是啊···”

這時,小六又問道:“我們們的計算的時候,都是把資料讀取到暫存器進行的,可這暫存器一次只能裝一個數,怎麼一次讀取多個資料呢?”

“可能需要新增一些容量大一些的暫存器,比如128bit長度,可以同時容納4個32位的整數”

“有這個必要嗎?我們們是通用CPU,又不是專門做數學計算的晶片,搞這些東西幹嘛?”,四號車間代表提出了質疑。

我也不甘示弱:“那可太有必要了,在影像、視訊、音訊處理等領域,有大量這樣的計算需求,我們們得提升處理這些資料的能力”

見我們爭執不下,領導拍了拍桌子,會場一下安靜了下來。

“我覺得阿Q說的有道理,我們們確實需要提升處理這類資料運算的能力了。不過不用一下搞那麼複雜,先支援整數並行運算就行了。新增暫存器這個也不用著急,可以先借用一下浮點數運算單元FPU的暫存器。這件事先這麼定下來,具體的方案你們再繼續討論。”,說完便離開了會議室。

領導不愧是領導,幾句話就把我們安排的明明白白。

SIMD

又經過一陣緊張的討論,我們終於敲定了方案。

我們借用浮點數運算單元的暫存器,還給它們起了新的名字:MM0-MM7。因為是64位的暫存器,所以可以同時儲存兩個32位的整數或者4個16位整數或者8個8位的整數。

我們還新增了一套叫MMX的指令集,用來並行執行整數的運算。

我們把這種在一條指令中同時處理多個資料的技術叫做單指令多資料流(Single Instruction Multiple Data),簡稱SIMD

有了這套指令集,我們們處理這類整數運算問題的速度快了不少。

不過漸漸地發現了兩個很麻煩的問題:

第一個問題,因為是借用FPU的暫存器,所以當執行SIMD指令的時候,就不能用FPU計算單元,反過來也一樣,同時使用的話就會出亂子,所以要經常在不同的模式之間切換,實在是有些麻煩。

另一個更重要的問題,我們們這套指令集只能處理整數的並行運算,可現在浮點數的並行運算越來越多,尤其是影像、視訊還有深度學習的一些資料處理,浮點數情況越來越多,這時候都派不上用場。

我們把這些問題給領導做了彙報,看到我們已經做出的成績,領導終於同意繼續升級。

這一次,我們擴充套件了一套新的SSE指令集出來,新增了XMM0-XMM7總共8個128位的暫存器,再也不用跟FPU共享暫存器了。而且位寬加了一倍,能容納的資料更多了,能同時處理的資料自然也變多了。

後來,我們又不斷的修改升級,不僅支援了對浮點數並行處理,還推出了新一代的AVX指令集,把暫存器再一次擴大為256位,現在我們的SIMD技術更加先進,處理資料運算的能力越來越強了!

 

往期TOP5文章

我是Redis,MySQL大哥被我害慘了!

CPU明明8個核,網路卡為啥拼命折騰一號核?

CPU被挖礦,Redis竟是內鬼!

主機板上來了一個新鄰居,CPU慌了!

雜湊表哪家強?幾大程式語言吵起來了!

相關文章