日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

verilog 浮点转定点_定点数优化:性能成倍提升

發布時間:2024/9/30 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 verilog 浮点转定点_定点数优化:性能成倍提升 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

定點數這玩意兒并不是什么新東西,早年 CPU 浮點性能不夠,定點數技巧大量活躍于各類圖形圖像處理的熱點路徑中。今天 CPU 浮點上來了,但很多情況下整數仍然快于浮點,因此比如:libcario (gnome/quartz 后端)及 pixman 之類的很多庫里你仍然找得到定點數的身影。那么今天我們就來看看使用定點數到底能快多少。

簡單用一下的話,下面這幾行宏就夠了:

#define cfixed_from_int(i) (((cfixed)(i)) << 16) #define cfixed_from_float(x) ((cfixed)((x) * 65536.0f)) #define cfixed_from_double(d) ((cfixed)((d) * 65536.0)) #define cfixed_to_int(f) ((f) >> 16) #define cfixed_to_float(x) ((float)((x) / 65536.0f)) #define cfixed_to_double(f) ((double)((f) / 65536.0)) #define cfixed_const_1 (cfixed_from_int(1)) #define cfixed_const_half (cfixed_const_1 >> 1) #define cfixed_const_e ((cfixed)(1)) #define cfixed_const_1_m_e (cfixed_const_1 - cfixed_const_e) #define cfixed_frac(f) ((f) & cfixed_const_1_m_e) #define cfixed_floor(f) ((f) & (~cfixed_const_1_m_e)) #define cfixed_ceil(f) (cfixed_floor((f) + 0xffff)) #define cfixed_mul(x, y) ((cfixed)((((int64_t)(x)) * (y)) >> 16)) #define cfixed_div(x, y) ((cfixed)((((int64_t)(x)) << 16) / (y))) #define cfixed_const_max ((int64_t)0x7fffffff) #define cfixed_const_min (-((((int64_t)1) << 31))) typedef int32_t cfixed;

類型狂可以寫成 inline 函數,封裝狂可以封裝成一系列 operator xx,如果需要更高的精度,可以將上面用 int32_t 表示的 16.16 定點數改為用 int64_t 表示的 32.32 定點數。

那么我們找個浮點數的例子優化一下吧,比如 libyuv 中的 ARGBAffineRow_C 函數:

void ARGBAffineRow_C(const uint8_t* src_argb,int src_argb_stride,uint8_t* dst_argb,const float* uv_dudv,int width) {int i;// Render a row of pixels from source into a buffer.float uv[2];uv[0] = uv_dudv[0];uv[1] = uv_dudv[1];for (i = 0; i < width; ++i) {int x = (int)(uv[0]);int y = (int)(uv[1]);*(uint32_t*)(dst_argb) = *(const uint32_t*)(src_argb + y * src_argb_stride + x * 4);dst_argb += 4;uv[0] += uv_dudv[2];uv[1] += uv_dudv[3];} }

這個函數是干什么用的呢?給圖像做 仿射變換(affine transformation) 用的,比如 2D 圖像庫或者 ActionScript 中可以給 Bitmap 設置一個 3x3 的矩陣,然后讓 Bitmap 按照該矩陣進行變換繪制:

基本上二維圖像所有:縮放,旋轉,扭曲都是通過仿射變換完成,這個函數就是從圖像的起點(u, v)開始按照步長(du, dv)進行采樣,放入臨時緩存中,方便下一步一次性整行寫入 frame buffer。

這個采樣函數有幾個特點:

  • 運算簡單:沒有復雜的運算,計算無越界,不需要求什么 log/exp 之類的復雜函數。
  • 范圍可控:大部分圖像長寬尺寸都在 32768 范圍內,用 16.16 的定點數即可。
  • 轉換頻繁:每個點的坐標都需要從浮點轉換成整數,這個操作很費事。

適合用定點數簡單重寫一下:

void ARGBAffineRow_Fixed(const uint8_t* src_argb,int src_argb_stride,uint8_t* dst_argb,const float* uv_dudv,int width) {int32_t u = (int32_t)(uv_dudv[0] * 65536); // 浮點數轉定點數int32_t v = (int32_t)(uv_dudv[1] * 65536);int32_t du = (int32_t)(uv_dudv[2] * 65536);int32_t dv = (int32_t)(uv_dudv[3] * 65536);for (; width > 0; width--) {int x = (int)(u >> 16); // 定點數坐標轉整數坐標int y = (int)(v >> 16);*(uint32_t*)(dst_argb) = *(const uint32_t*)(src_argb + y * src_argb_stride + x * 4);dst_argb += 4;u += du; // 定點數加法v += dv;} }

局部用一下定點數都不需要定義前面那一堆宏,按相關原理直接寫就是了。

我們用 llvm-mca 分析一下,浮點數版本 gcc 9.0 的循環主體部分用 -O3 的代碼生成:

Iterations: 100 Instructions: 1300 Total Cycles: 458 Total uOps: 1500Dispatch Width: 6 uOps Per Cycle: 3.28 IPC: 2.84 Block RThroughput: 3.0Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U)[1] [2] [3] [4] [5] [6] Instructions:2 6 1.00 cvttss2si eax, xmm11 1 0.25 add rsi, 41 4 0.50 addss xmm1, xmm22 6 1.00 cvttss2si edx, xmm01 4 0.50 addss xmm0, xmm31 3 1.00 imul eax, r9d1 1 0.50 shl edx, 21 1 0.25 cdqe1 1 0.25 add rax, rdi1 5 0.50 * mov eax, dword ptr [rax + rdx]1 1 1.00 * mov dword ptr [rsi - 4], eax1 1 0.25 cmp rsi, rcx1 1 0.50 jne .L3

鏈接:Compiler Explorer - Analysis (llvm-mca (trunk))

可以看到,雖然編譯器自動生成了 sse 代碼,但性能消耗的大戶,cvttss2si(浮點數轉整數指令),雖然只有一條命令,但會生成兩個微指令(uOP),延遲 6 個周期,rthroughput 很高 1.0 代表每周期只能同時運行一條該指令,其次是加法指令 addss, 延遲是 4 個周期,吞吐量 0.5 代表每周期可以并行執行 2 條,該代碼塊模擬運行 100 次,總消耗 458 個周期。

再看定點數版本:

Iterations: 100 Instructions: 1500 Total Cycles: 337 Total uOps: 1500Dispatch Width: 6 uOps Per Cycle: 4.45 IPC: 4.45 Block RThroughput: 2.5Instruction Info: [1]: #uOps [2]: Latency [3]: RThroughput [4]: MayLoad [5]: MayStore [6]: HasSideEffects (U)[1] [2] [3] [4] [5] [6] Instructions:1 1 0.25 mov eax, edi1 1 0.25 mov edx, ecx1 1 0.25 add rsi, 41 1 0.25 add ecx, r11d1 1 0.50 sar eax, 161 1 0.50 sar edx, 161 1 0.25 add edi, ebx1 3 1.00 imul eax, r10d1 1 0.50 shl edx, 21 1 0.25 cdqe1 1 0.25 add rax, r91 5 0.50 * mov eax, dword ptr [rax + rdx]1 1 1.00 * mov dword ptr [rsi - 4], eax1 1 0.25 cmp rsi, r81 1 0.50 jne .L8

鏈接:https://godbolt.org/z/Adj9gQ

指令雖然多了兩條,但是整數指令 latency 比浮點要低,并且吞吐量(并行性)比浮點更好,大部分指令都是 0.25,代表每周期可以并行執行四條,模擬運行 100 次,總消耗 337 個周期。

這里你可能要問,整數版本,第二列 latency 加起來有 21 個周期啊,為什么平均運行一次才 3.37 個周期呢?這就是多級流水線中很多指令可以并行運行,只要沒有運算結果依賴,以及沒有執行單元的資源沖突,很多運算都是可以并行的,所以優化里,運算解依賴很有用。

我們給 llmv-mca 加一個 -timeline 參數,能得到流水線分析報表,這里截取兩次循環:

[0,0] DeER . . . . . . . . . mov eax, edi [0,1] DeER . . . . . . . . . mov edx, ecx [0,2] DeER . . . . . . . . . add rsi, 4 [0,3] DeER . . . . . . . . . add ecx, r11d [0,4] D=eER. . . . . . . . . sar eax, 16 [0,5] D=eER. . . . . . . . . sar edx, 16 [0,6] .DeER. . . . . . . . . add edi, ebx [0,7] .D=eeeER . . . . . . . . imul eax, r10d [0,8] .D=eE--R . . . . . . . . shl edx, 2 [0,9] .D====eER . . . . . . . . cdqe [0,10] .D=====eER. . . . . . . . add rax, r9 [0,11] .D======eeeeeER. . . . . . . mov eax, dword ptr [rax + rdx] [0,12] . D==========eER . . . . . . mov dword ptr [rsi - 4], eax [0,13] . DeE----------R . . . . . . cmp rsi, r8 [0,14] . D=eE---------R . . . . . . jne .L8 [1,0] . DeE----------R . . . . . . mov eax, edi [1,1] . D=eE---------R . . . . . . mov edx, ecx [1,2] . D=eE---------R . . . . . . add rsi, 4 [1,3] . DeE---------R . . . . . . add ecx, r11d [1,4] . D=eE--------R . . . . . . sar eax, 16 [1,5] . D=eE--------R . . . . . . sar edx, 16 [1,6] . D=eE--------R . . . . . . add edi, ebx [1,7] . D==eeeE-----R . . . . . . imul eax, r10d [1,8] . D==eE-------R . . . . . . shl edx, 2 [1,9] . D====eE----R . . . . . . cdqe [1,10] . D=====eE---R . . . . . . add rax, r9 [1,11] . D======eeeeeER . . . . . . mov eax, dword ptr [rax + rdx] [1,12] . D===========eER . . . . . . mov dword ptr [rsi - 4], eax [1,13] . DeE-----------R . . . . . . cmp rsi, r8 [1,14] . D==eE---------R . . . . . . jne .L8

每條指令有下面幾個生存周期:

D : Instruction dispatched. e : Instruction executing. E : Instruction executed. R : Instruction retired. = : Instruction already dispatched, waiting to be executed. - : Instruction executed, waiting to be retired.

可以看到無依賴的頭四條指令:

[0,0] DeER . . . . . . . . . mov eax, edi [0,1] DeER . . . . . . . . . mov edx, ecx [0,2] DeER . . . . . . . . . add rsi, 4 [0,3] DeER . . . . . . . . . add ecx, r11d

從分發(D),執行(e),完成執行(E)到退休(R),基本都是同時進行的。后面兩條指令雖然也是和前面四條一起分發(D),但由于依賴頭兩條指令的運算結果,所以產生了一個周期的等待(=):

[0,4] D=eER. . . . . . . . . sar eax, 16 [0,5] D=eER. . . . . . . . . sar edx, 16

等到頭兩個指令執行成功(e結束),他們才能開始執行,第二次迭代 [1,0] 類似,多次迭代雖然用到了同樣的寄存器,但是在 CPU 里 eax 只是個名字,CPU 對無關運算的寄存器進行重命名后,其實背后對應到了不同的寄存器地址,第二次迭代又有很多地方可以和第一次迭代并行執行,所以我們會發現兩次迭代的最后一條指令 [0,14] 和 [1,14] 處理的退休時間 R 都差不多,兩次循環幾乎是并行執行的,如此多次循環平攤下來每次只要 3.37 個周期。

可以發現比浮點數版本的 4.58 個周期快了 35% 左右,注意一點,實際 I/O 操作會占用更多時間,所以在 mca 的分析里都標注了 MayLoad / MayStore,所以算上 I/O,兩邊的周期數都會略有增加,但是優勢還在那里。

使用 mca 進行分析的時候,你把編譯結果貼過去時,只能貼循環的主體部分,因為本身就要進行多次運行的流水線模擬,所以你貼了循環外的初始化部分就會干擾分析結果。

可能有人會說,媽呀,靜態性能分析還要計算流水線么?其實大部分時候不需要,沒有 llvm-mca 的時候我們做靜態性能分析一般就是查指令手冊:

大部分時候,看一下 uops 數量(越少越好),看一下周期 latency(越少越好),以及 throughput (決定并行效率,越低越好),心中對各類指令的占用消耗有一個基本概念,再細致一點的話還可以看看占用哪些硬件資源,p0156 代表可以再 0/1/5/6 幾個硬件單元里任意一個執行,然后對著紙面代碼進行一個大概評估。

后面有了 Intel IACA 以及 llvm-mca 后,自動化靜態分析可以更加簡單和準確。到這里,我們對仿射紋理映射做了一次性能靜態分析,可以看得出定點數版本確實快,于是我們得到了一個性能更好的仿射紋理映射函數:

那么這樣的靜態分析準不準確呢?我們接著對兩個函數進行動態性能評測:

鏈接:http://quick-bench.com/FqOYuExcXoyHe_r6Bl1oSm0wUPE

在 gcc 9.2 下面,定點數比浮點數快了 30%,比我們之前靜態分析的結論類似(4.58 比 3.37),但差距略稍許偏低沒有純周期計算出來的 35% 性能差距那么高,因為兩邊都平攤了 I/O 操作引入的延遲(這部分 mca 沒法計算進去)。

那么我們繼續切換編譯器,換成 clang 9.0 :

鏈接:http://quick-bench.com/RoUdH66MayHq6exmQ99mhODUN2w

可以看到性能提升了 2.2 倍,看代碼生成,因為在 clang 下進行了矢量展開,定點數和浮點數都進行了循環展開,每輪循環一次性計算兩個點,導致了更大的性能提升。

C 版本的定點數還可以繼續用 SIMD 一次性算四個點的定點數坐標,性能應該還能提升一級。

定點數除了能在特定地方讓你的代碼性能提升數倍外,在很多對結果嚴格要求一致的地方,也會比浮點數更好,比如幀間同步的游戲,需要在 arm/x86 下面不同客戶端保證同樣的計算結果,這樣浮點數就掛了,不同手機運算結果不同,只能用定點數來處理。

(PS:對于一些復雜運算比如 sin/cos 之類的三角函數,定點數一般用查表+插值進行)

最后,定點數是一個值得收藏到你編程百寶箱里的好工具,必要的時候能夠幫到你。

--

總結

以上是生活随笔為你收集整理的verilog 浮点转定点_定点数优化:性能成倍提升的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 九色精品视频 | av中字| 亚洲精品在线一区二区 | 成人aaaa | 日韩一级片中文字幕 | 91视频在线观看 | 精品一区电影国产 | 脱美女衣服亲摸揉视频 | 激情五月五月婷婷 | 我们俩电影网mp4动漫官网 | 欧美老肥妇做爰bbww | 久久尤物 | 色综合一区二区 | 亚洲欧美日韩精品色xxx | 福利网址在线 | av观看国产 | 日韩一卡 | 超碰成人免费在线 | 依依成人在线 | 日韩精品无码一区二区三区 | 完全免费av | 欧美在线二区 | 亚洲网站视频 | 中日韩男男gay无套 人人草人人干 | 成人精品免费网站 | 扩阴视频 | 亚洲综合色在线观看 | 欧美亚洲大片 | 婷婷伊人五月天 | 夜夜操夜夜干 | 中文字幕成人一区 | 久久九| 久久av高潮av| 亚洲午夜无码久久 | 亚洲第一字幕 | 男人的天堂在线视频 | 亚洲精品大片www | 美女草逼视频 | 特大黑人娇小亚洲女mp4 | 操丝袜少妇 | 天天激情 | 隣の若妻さん波多野结衣 | 天堂久久精品忘忧草 | 意大利性荡欲xxxxxx | 一及黄色大片 | 高跟91娇喘 | 97在线观看视频 | 看av免费毛片手机播放 | 久热精品免费视频 | 日本 片 成人 在线 九色麻豆 | 日韩男人的天堂 | 日本在线中文 | 精品亚洲综合 | 天堂av中文 | 婷婷色五 | 午夜福利电影 | 午夜视频a| 午夜成人在线视频 | 动漫毛片 | 亚洲黄视频 | 亚洲大胆视频 | 男人添女人荫蒂国产 | 538国产精品一区二区免费视频 | 寂寞少妇让水电工爽hd | 亚洲综合在线网 | 丰满少妇久久久久久久 | 永久av| 国产乱子伦农村叉叉叉 | 9久9久9久女女女九九九一九 | 欧美精品自拍视频 | av黄色免费观看 | 成人h动漫精品一区二区器材 | 97人人爽人人爽人人爽人人爽 | 亚洲高清免费观看 | 仙踪林久久久久久久999 | 免费在线看黄色片 | 中文字幕无码日韩专区免费 | 色77777| 精品理论片 | 狠狠天天 | 午夜黄色福利视频 | 操操操日日日 | 国产香蕉精品 | 亚洲综合网在线 | 久久福利影院 | 日韩欧美在线观看一区二区 | 青青草激情视频 | 国产尤物视频在线 | 国产免费看黄 | 久久免费精品国产 | 少妇一级淫片免费视频 | 欧美性生交大片免费看app麻豆 | babes性欧美69 | 国产一二三四五区 | 黄色一级片视频 | 久久久久久久久久网站 | 午夜小视频在线观看 | 男人用嘴添女人下身免费视频 | 日日夜夜天天综合 |