0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

gemv優(yōu)化總結(jié)

perfxlab ? 來(lái)源:澎峰科技PerfXLab ? 2023-05-25 09:08 ? 次閱讀

有朋友來(lái)信說(shuō):

1. “除了以NVIDIA(英偉達(dá))為例,能不能談點(diǎn)國(guó)產(chǎn)GPU優(yōu)化的經(jīng)驗(yàn)分享?”

2. “老講國(guó)外的東西,你們能不能支持一下國(guó)產(chǎn)CPU和加速卡?“

這里解釋一下原因:

1. N卡的資料和環(huán)境大家都比較好找,對(duì)于學(xué)習(xí)GPU并行優(yōu)化編程的朋友比較友善。

2. 暫時(shí)受限于商業(yè)保密,我們相信后續(xù)會(huì)逐步開(kāi)放起來(lái),學(xué)習(xí)的平臺(tái)和環(huán)境也容易找到。到時(shí)就可以分享一些國(guó)產(chǎn)CPU和加速卡的優(yōu)化經(jīng)驗(yàn)出來(lái)。

------ 正文分割線 ------

本文主要是介紹如何對(duì)gemv算法進(jìn)行優(yōu)化。gemv,即矩陣向量乘,即計(jì)算一個(gè)矩陣A與一個(gè)向量x的乘積,這是并行計(jì)算中的經(jīng)典話題。個(gè)人感覺(jué),gemv的優(yōu)化核心是需要考慮不同shape的情況,然后針對(duì)型地進(jìn)行優(yōu)化。本篇文章會(huì)先介紹一下針對(duì)不同shape設(shè)計(jì)不同的并行算法,然后說(shuō)明一下優(yōu)化思路和相關(guān)優(yōu)化技巧,最后說(shuō)一下實(shí)驗(yàn)效果,在A矩陣列數(shù)為16 128的時(shí)候,我寫(xiě)的gemv能擁有超越cublas的性能表現(xiàn)。

一、前言

首先介紹一下gemv算法。給定矩陣A和向量x,gemv需要計(jì)算兩者的乘積,示意圖如下:

6a2366c2-fa8c-11ed-90ce-dac502259ad0.png

gemv

二、針對(duì)不同shape的并行算法設(shè)計(jì)

這次講到并行算法設(shè)計(jì),什么叫并行算法設(shè)計(jì)。每個(gè)人的理解都不太一樣,在GPU中,我的理解就是:設(shè)計(jì)block和thread的workload,說(shuō)白了就是要搞清楚一個(gè)block負(fù)責(zé)哪部分的計(jì)算,一個(gè)thread要負(fù)責(zé)哪部分的計(jì)算。而設(shè)計(jì)的原則就是盡可能地減少訪存,提高數(shù)據(jù)的復(fù)用概率,然后讓所有的處理器都滿負(fù)荷地進(jìn)行工作,不能浪費(fèi)。

2.1 針對(duì)n=32

對(duì)于n=32的情況,我們將每個(gè)block設(shè)置為256個(gè)線程,4個(gè)warp,然后每個(gè)warp負(fù)責(zé)一行元素的計(jì)算。每個(gè)warp要對(duì)x進(jìn)行訪問(wèn),然后在warp內(nèi)部進(jìn)行一次reduce求和操作。

6a38baf4-fa8c-11ed-90ce-dac502259ad0.jpg

n=32

代碼如下:

template 
__device__ __forceinline__ float warpReduceSum(float sum) {
    if (WarpSize >= 32)sum += __shfl_down_sync(0xffffffff, sum, 16); // 0-16, 1-17, 2-18, etc.
    if (WarpSize >= 16)sum += __shfl_down_sync(0xffffffff, sum, 8);// 0-8, 1-9, 2-10, etc.
    if (WarpSize >= 8)sum += __shfl_down_sync(0xffffffff, sum, 4);// 0-4, 1-5, 2-6, etc.
    if (WarpSize >= 4)sum += __shfl_down_sync(0xffffffff, sum, 2);// 0-2, 1-3, 4-6, 5-7, etc.
    if (WarpSize >= 2)sum += __shfl_down_sync(0xffffffff, sum, 1);// 0-1, 2-3, 4-5, etc.
    return sum;
}

// if N == 32
__global__ void Sgemv_v0( 
    float * __restrict__ A,
    float * __restrict__ x,
    float * __restrict__ y, 
    const int M,
    const int N) {
    // Block index
    int bx = blockIdx.x;

    // Thread index
    int tx = threadIdx.x;
    int ty = threadIdx.y;

    const int warp_size=32;
    int laneId= tx % warp_size;
    int current_row = blockDim.y * bx + ty;

    if(current_row < M){
        float res=0;
        int kIteration = N/warp_size;
        if(kIteration==0) kIteration=1;
        #pragma unroll
        for(int i=0; i< kIteration; i++){
            int current_col = i*warp_size + laneId;
            res += A[current_row*N + current_col] * x[current_col];
        }
        res = warpReduceSum(res);
        if(laneId==0) y[current_row]=res;
    }
}

2.2 針對(duì)n=128

對(duì)于n=128的情況,同樣讓warp負(fù)責(zé)一行元素的計(jì)算,但是因?yàn)槊啃械脑乇容^多,所以采用了float4進(jìn)行向量化的訪存。能夠有更高的訪存效率。

6a53326c-fa8c-11ed-90ce-dac502259ad0.jpg

n=128

代碼如下:

template 
__device__ __forceinline__ float warpReduceSum(float sum) {
    if (WarpSize >= 32)sum += __shfl_down_sync(0xffffffff, sum, 16); // 0-16, 1-17, 2-18, etc.
    if (WarpSize >= 16)sum += __shfl_down_sync(0xffffffff, sum, 8);// 0-8, 1-9, 2-10, etc.
    if (WarpSize >= 8)sum += __shfl_down_sync(0xffffffff, sum, 4);// 0-4, 1-5, 2-6, etc.
    if (WarpSize >= 4)sum += __shfl_down_sync(0xffffffff, sum, 2);// 0-2, 1-3, 4-6, 5-7, etc.
    if (WarpSize >= 2)sum += __shfl_down_sync(0xffffffff, sum, 1);// 0-1, 2-3, 4-5, etc.
    return sum;
}

// if N>= 128
__global__ void Sgemv_v1( 
    float * __restrict__ A,
    float * __restrict__ x,
    float * __restrict__ y, 
    const int M,
    const int N) {
    // Block index
    int bx = blockIdx.x;

    // Thread index
    int tx = threadIdx.x;
    int ty = threadIdx.y;

    const int warp_size=32;
    int laneId= tx % warp_size;
    int current_row = blockDim.y * bx + ty;

    if(current_row < M){
        float res=0;
        int kIteration = (N/warp_size)/4;
        if(kIteration==0) kIteration=1;
        A = &A[current_row*N];
        #pragma unroll
        for(int i=0; i< kIteration; i++){
            int current_col_vec = (i*warp_size + laneId);
            float4 current_val= reinterpret_cast(A)[current_col_vec];
            float4 current_x = reinterpret_cast(x)[current_col_vec];
            res += current_val.x*current_x.x;
            res += current_val.y*current_x.y;
            res += current_val.z*current_x.z;
            res += current_val.w*current_x.w;
        }
        res = warpReduceSum(res);
        if(laneId==0) y[current_row]=res;
    }
}

2.3 針對(duì)n=16

對(duì)于n=16的情況,讓一個(gè)warp負(fù)責(zé)兩行元素的計(jì)算。以warp0為例,0-15號(hào)線程負(fù)責(zé)第0行元素的計(jì)算,而16-31號(hào)線程負(fù)責(zé)第1行元素的計(jì)算。

6a6a3796-fa8c-11ed-90ce-dac502259ad0.jpg

n=16

代碼如下:

template 
__device__ __forceinline__ float warpReduceSum(float sum) {
    if (WarpSize >= 32)sum += __shfl_down_sync(0xffffffff, sum, 16); // 0-16, 1-17, 2-18, etc.
    if (WarpSize >= 16)sum += __shfl_down_sync(0xffffffff, sum, 8);// 0-8, 1-9, 2-10, etc.
    if (WarpSize >= 8)sum += __shfl_down_sync(0xffffffff, sum, 4);// 0-4, 1-5, 2-6, etc.
    if (WarpSize >= 4)sum += __shfl_down_sync(0xffffffff, sum, 2);// 0-2, 1-3, 4-6, 5-7, etc.
    if (WarpSize >= 2)sum += __shfl_down_sync(0xffffffff, sum, 1);// 0-1, 2-3, 4-5, etc.
    return sum;
}

// if N <= 16
template <
    const int ROW_PER_WARP
    > 
__global__ void Sgemv_v2( 
    float * __restrict__ A,
    float * __restrict__ x,
    float * __restrict__ y, 
    const int M,
    const int N) {
    // Block index
    int bx = blockIdx.x;

    // Thread index
    int tx = threadIdx.x;
    int ty = threadIdx.y;

    const int warp_size=32;
    int laneId= tx % warp_size;
    int current_warp_row = (blockDim.y * bx + ty) * ROW_PER_WARP;
    const int kWarp_size = warp_size / ROW_PER_WARP;
    int kLaneId = laneId % kWarp_size;
    int current_thread_row = current_warp_row + laneId / kWarp_size;

    if(current_thread_row < M){
        float res=0;
        int current_col = kLaneId;
        res += A[current_thread_row * N + current_col] * x[current_col];
        res = warpReduceSum(res);
        if(kLaneId==0) y[current_thread_row]=res;
    }
}

三、優(yōu)化思路:

上一節(jié)說(shuō)明了如何針對(duì)不同維度的n進(jìn)行優(yōu)化,這一節(jié)說(shuō)明一下為什么要這么設(shè)計(jì),以及這樣的設(shè)計(jì)方式能夠帶來(lái)什么樣的好處。主要考慮的因素有兩個(gè),如下:

3.1 盡可能地讓warp中的32個(gè)線程忙碌

這個(gè)主要是針對(duì)n<32的情況,例如n=16,如果使用一個(gè)warp來(lái)負(fù)責(zé)一行元素的計(jì)算,那么warp中有一半的元素都是浪費(fèi)的。所以讓一個(gè)warp來(lái)負(fù)責(zé)多行元素的計(jì)算,這樣讓32個(gè)線程全部忙碌起來(lái)。

3.2 盡可能地提高訪存效率

① global mem->register

將數(shù)據(jù)從global memory搬運(yùn)到寄存器上時(shí),最重要的就是考慮是不是進(jìn)行了合并訪存。在這里,我們只考慮矩陣數(shù)據(jù)在global mem中是地址對(duì)齊的,即n是2的多次冪。上述的三種并行實(shí)現(xiàn)中,warp中的32個(gè)線程都是連續(xù)地訪問(wèn)32個(gè)float或者128個(gè)float,因而滿足了合并訪存的條件,確保了global -> register的訪存效率。

② shared mem->register

說(shuō)到這里,可能會(huì)有讀者好奇,上述的代碼都沒(méi)有用到shared mem。為啥要說(shuō)這個(gè)點(diǎn)。我們可以再仔細(xì)看看上述的三種并行實(shí)現(xiàn),以第2種為例,一個(gè)block中有4個(gè)warp,每個(gè)warp都需要對(duì)x進(jìn)行一次global上的訪存,所以一個(gè)block有4次訪存。如果將x存儲(chǔ)到shared mem中,4個(gè)warp都去訪問(wèn)shared mem上的x,這樣的話,對(duì)于global的訪存就從4次變成1次。直觀上會(huì)有性能提升,但不幸的是,如果用shared mem的話,將global mem的數(shù)據(jù)搬運(yùn)至shared mem需要有同步操作,這又會(huì)導(dǎo)致性能的下降??偟膩?lái)說(shuō),使用shared mem并沒(méi)有得到顯著的提升,不過(guò)還是在這里說(shuō)明一下。

③ 向量化訪存

向量化訪存就是一個(gè)老生常談的話題了,說(shuō)白了就是盡可能地使用128bit的訪存指令,這個(gè)在reduce、sgemm、elementwise專題上說(shuō)了很多,就不再多說(shuō)。

四、實(shí)驗(yàn)與總結(jié)

筆者在V100上進(jìn)行了實(shí)驗(yàn),迭代1000次,用nsight進(jìn)行了測(cè)試,性能數(shù)據(jù)如下:

sgemv M N my_sgemv time(ns) cublas(ns) my_sgemv/cublas
v0 16384 32 10341 8386 81.1%
v1 16384 128 14284 15848 110.9%
v2 16384 16 6903 7576 109.7%

可以看出,在n=16以及n=128的情況下,都比cublas性能要好。n=32的情況要差于cublas。如果再加上向量化訪存應(yīng)該能夠有更好的性能表現(xiàn)。由于我實(shí)在沒(méi)時(shí)間再進(jìn)行深入,有心的同學(xué)可以改改代碼看看效果 :)。

審核編輯:彭靜
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10890

    瀏覽量

    212413
  • 存儲(chǔ)
    +關(guān)注

    關(guān)注

    13

    文章

    4338

    瀏覽量

    85999
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3634

    瀏覽量

    93858
  • 澎峰科技
    +關(guān)注

    關(guān)注

    0

    文章

    55

    瀏覽量

    3193

原文標(biāo)題:深入淺出GPU優(yōu)化系列:gemv優(yōu)化

文章出處:【微信號(hào):perfxlab,微信公眾號(hào):perfxlab】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    HBase性能優(yōu)化方法總結(jié)

    hbase響應(yīng)速度;9. 避免出現(xiàn)region熱點(diǎn)現(xiàn)象,啟動(dòng)按照table級(jí)別進(jìn)行balance。以上是對(duì)HBase性能優(yōu)化方法的概要總結(jié),有HBase性能優(yōu)化需求的,可以在此基礎(chǔ)上延伸學(xué)習(xí),會(huì)有一定收獲的!
    發(fā)表于 04-20 17:16

    改善深層神經(jīng)網(wǎng)絡(luò)--超參數(shù)優(yōu)化、batch正則化和程序框架 學(xué)習(xí)總結(jié)

    《深度學(xué)習(xí)工程師-吳恩達(dá)》02改善深層神經(jīng)網(wǎng)絡(luò)--超參數(shù)優(yōu)化、batch正則化和程序框架 學(xué)習(xí)總結(jié)
    發(fā)表于 06-16 14:52

    文檔基于DSP的視頻監(jiān)控系統(tǒng)的優(yōu)化仿真的設(shè)計(jì)總結(jié)文檔

    該文檔為基于DSP的視頻監(jiān)控系統(tǒng)的優(yōu)化仿真的設(shè)計(jì)總結(jié)文檔,是一份很不錯(cuò)的參考資料,具有較高參考價(jià)值,感興趣的可以下載看看………………針對(duì)目前IGBT驅(qū)動(dòng)電路復(fù)雜的缺點(diǎn),本文以德國(guó)西門康公司
    發(fā)表于 08-27 16:19

    嵌入式Java虛擬機(jī)優(yōu)化技術(shù)總結(jié)的太棒了

    嵌入式Java虛擬機(jī)優(yōu)化技術(shù)總結(jié)的太棒了
    發(fā)表于 04-25 06:47

    總結(jié)下電機(jī)控制中對(duì)程序算法優(yōu)化的辦法

    (用到了三角函數(shù))都比較消耗電機(jī)主控芯片的計(jì)算能力。在考慮算法實(shí)現(xiàn)的時(shí)候,都需要針對(duì)主控芯片的實(shí)際性能進(jìn)行一定優(yōu)化,才能確保算法能夠順利運(yùn)行。這里我總結(jié)下電機(jī)控制中對(duì)程序算法優(yōu)化的辦法。數(shù)據(jù)的概念浮點(diǎn)數(shù)
    發(fā)表于 08-27 06:37

    電機(jī)控制中對(duì)程序算法優(yōu)化的辦法總結(jié)

    (用到了三角函數(shù))都比較消耗電機(jī)主控芯片的計(jì)算能力。在考慮算法實(shí)現(xiàn)的時(shí)候,都需要針對(duì)主控芯片的實(shí)際性能進(jìn)行一定優(yōu)化,才能確保算法能夠順利運(yùn)行。這里我總結(jié)下電機(jī)控制中對(duì)程序算法優(yōu)化的辦法。數(shù)據(jù)的概念...
    發(fā)表于 09-07 06:19

    GPRS優(yōu)化思路總結(jié)報(bào)告

    GPRS優(yōu)化思路總結(jié)報(bào)告:一、概述 2二、無(wú)線優(yōu)化的思路 2三、(E)GPRS網(wǎng)絡(luò)資源容量分析優(yōu)化 53.1、(E)GPRS網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu) 63.
    發(fā)表于 07-27 21:29 ?26次下載

    DSP程序優(yōu)化總結(jié)

    DSP程序優(yōu)化總結(jié)
    發(fā)表于 10-23 14:24 ?2次下載
    DSP程序<b class='flag-5'>優(yōu)化</b><b class='flag-5'>總結(jié)</b>

    區(qū)塊鏈共識(shí)算法的效能優(yōu)化研究及總結(jié)

    。由于共識(shí)算法的資源花銷、能源耗費(fèi)以及性能之間相互關(guān)聯(lián)且關(guān)系復(fù)雜,因此有必要從¨效能”的角度對(duì)現(xiàn)有區(qū)塊鏈的共識(shí)算法加以分析,并總結(jié)研究思路。文中總結(jié)了區(qū)塊鏈共識(shí)算法的效能優(yōu)化研究進(jìn)展。首先定義區(qū)塊鏈共識(shí)算法的效
    發(fā)表于 04-25 11:35 ?4次下載
    區(qū)塊鏈共識(shí)算法的效能<b class='flag-5'>優(yōu)化</b>研究及<b class='flag-5'>總結(jié)</b>

    TD-LTE網(wǎng)絡(luò)優(yōu)化經(jīng)驗(yàn)總結(jié)解析

    TD-LTE網(wǎng)絡(luò)優(yōu)化經(jīng)驗(yàn)總結(jié)解析說(shuō)明。
    發(fā)表于 04-27 10:30 ?23次下載

    DC-DC電源系統(tǒng)的優(yōu)化設(shè)計(jì)總結(jié)

    DC-DC電源系統(tǒng)的優(yōu)化設(shè)計(jì)總結(jié)(電源技術(shù)期刊咋樣)-該文檔為DC-DC電源系統(tǒng)的優(yōu)化設(shè)計(jì)總結(jié)文檔,是一份不錯(cuò)的參考資料,感興趣的可以下載看看,,,,,,,,,,,,,,,,,
    發(fā)表于 09-22 11:45 ?26次下載
    DC-DC電源系統(tǒng)的<b class='flag-5'>優(yōu)化</b>設(shè)計(jì)<b class='flag-5'>總結(jié)</b>

    接口優(yōu)化的常見(jiàn)方案實(shí)戰(zhàn)總結(jié)

    針對(duì)老項(xiàng)目,去年做了許多降本增效的事情,其中發(fā)現(xiàn)最多的就是接口耗時(shí)過(guò)長(zhǎng)的問(wèn)題,就集中搞了一次接口性能優(yōu)化。本文將給小伙伴們分享一下接口優(yōu)化的通用方案。
    的頭像 發(fā)表于 03-06 09:22 ?589次閱讀

    深入淺出GPU優(yōu)化系列:gemv優(yōu)化

    這次講到并行算法設(shè)計(jì),什么叫并行算法設(shè)計(jì)。每個(gè)人的理解都不太一樣,在GPU中,我的理解就是:設(shè)計(jì)block和thread的workload,說(shuō)白了就是要搞清楚一個(gè)block負(fù)責(zé)哪部分的計(jì)算,一個(gè)thread要負(fù)責(zé)哪部分的計(jì)算。
    的頭像 發(fā)表于 05-25 09:03 ?2337次閱讀
    深入淺出GPU<b class='flag-5'>優(yōu)化</b>系列:<b class='flag-5'>gemv</b><b class='flag-5'>優(yōu)化</b>

    總結(jié)FasterTransformer Encoder優(yōu)化技巧

    FasterTransformer BERT 包含優(yōu)化的 BERT 模型、高效的 FasterTransformer 和 INT8 量化推理。
    的頭像 發(fā)表于 05-30 15:15 ?1322次閱讀
    <b class='flag-5'>總結(jié)</b>FasterTransformer Encoder<b class='flag-5'>優(yōu)化</b>技巧

    性能優(yōu)化之路總結(jié)

    針對(duì)老項(xiàng)目,去年做了許多降本增效的事情,其中發(fā)現(xiàn)最多的就是接口耗時(shí)過(guò)長(zhǎng)的問(wèn)題,就集中搞了一次接口性能優(yōu)化。本文將給小伙伴們分享一下接口優(yōu)化的通用方案。 ? ? 一、接口優(yōu)化方案總結(jié) 1
    的頭像 發(fā)表于 06-17 15:00 ?361次閱讀