看板 C_and_CPP 關於我們 聯絡資訊
(是YUV轉RGB的其中一部份) short R; : : if(R < 0) R = 0; 上面這程式,能否不要用if呢? 我做法是這樣: #define MIMUS_SIGN 0x8000 /* 1000 0000 0000 0000*/ #define IS_POSITIVE(XX) ( 1 - ( (XX) & MIMUS_SIGN) >>15) ) char bitand_map[2] = {0x00, 0xff}; #define BYTE_AND(XX, SIGN) ( (XX) & bitand_map[(SIGN)] ) #define MINUS_BE_ZERO ( XX) BYTE_AND_BIT( XX, IS_POSITIVE (XX) ) : R = MINUS_BE_ZERO( R); 這程式用到了 bitand_map 這表,且在IS_POSITIVE 用了一個 bit and ,一個平移與一個減法,量有點多。 在想有沒辦法更精簡。 有人有建議的嗎? 另外,對於 if(R > 255) R = 255; 這要不用if來優化就難了。。 (R >> 8) | (R >> 9) | (R >> 10) | (R >> 11) | (R >> 12) | (R >> 13) | (R >> 14) 看0或是1再用上面的查表法做bit and.... 這樣做太多次平移與bit or 還不如直接用if 有人有類似經驗的嗎? 謝謝指教 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 58.115.143.194
legnaleurc:最近大家都跟 if 有仇就對了 02/14 01:48
legnaleurc:你探討的問題很低階, bit shift, bit and/or, 哪個比較 02/14 01:50
softwind:換組合語言or硬體繞線接 你想搞定問題 還是讓C搞你? 02/14 01:50
legnaleurc:快都要看你的機器和 compiler ... 如果你分析的結果 02/14 01:50
legnaleurc:hot spot 的確在那上面的話 ... 我想你也只能用組語 02/14 01:51
legnaleurc:搞定 ... SSE 或是 MMX 指令集都可以用 02/14 01:52
softwind:能用SIMD的 應該不會問這問題 XD 02/14 01:53
DrStein:最終使用環境不是x86平台 不能用SSE 02/14 01:54
※ 編輯: DrStein 來自: 58.115.143.194 (02/14 01:55)
DrStein:分析過hot spot,就是在這些if上。 02/14 01:56
legnaleurc:如果你平台上的指令集也不能解決這個問題 ... 換硬體 02/14 01:58
legnaleurc:可能會比較快 orz, 除非你要手動幹掉 hazard 或是 02/14 01:58
DrStein:arm的cpu + 機器人操作系統。。。 02/14 01:59
legnaleurc:cache miss 這種非人哉的偉業 02/14 01:59
※ 編輯: DrStein 來自: 58.115.143.194 (02/14 02:00)
DrStein:增加緩存命中率這方法試過,不過不同手機緩存大小不同 02/14 02:00
DrStein:很難有統一的優化法 02/14 02:00
legnaleurc:好吧, 如果你真的很堅持的話 ... 通常 cmp 是作 sub 02/14 02:07
legnaleurc:但如果改成只用 and 就會比較快, 所以 U > 255 的地方 02/14 02:08
※ 編輯: DrStein 來自: 58.115.143.194 (02/14 02:11)
legnaleurc:可能可以改成 U & 0xFF00, 避掉一次加法器 02/14 02:10
legnaleurc:結果會怎樣還是要看硬體 ... 02/14 02:11
DrStein:U & 0xFF00 不行吧,最後一個bit是正負號,該是0x7f00吧 02/14 02:14
legnaleurc:呃, 抓到意思就好, 我怎麼知道最後你是要不要 sign QQ 02/14 02:17
DrStein:以前試過在x86上,if用mask(and)來做會比用cmp來快約5趴 02/14 02:20
DrStein:但分析過主要開銷還是在branch上(緩存不命中) 02/14 02:21
DrStein:所以想有沒辦法根本不用if 02/14 02:21
VictorTom:小弟有點疑問, 請問您的轉換公式是?? 查了一下YUV2RGB或 02/14 02:24
VictorTom:反轉, 應該沒有用到branch啊?? 本來猜是不是用全整數運 02/14 02:25
VictorTom:算需要clamp, 可是處理的對象又是source....@_@" 02/14 02:25
DrStein:是YUV to RGB。。轉換時可能會暴表 所以要用if 02/14 02:26
※ 編輯: DrStein 來自: 58.115.143.194 (02/14 02:27)
VictorTom:啊對不起, 我查到fixed用的公式是有clamp沒錯....Orz 02/14 02:27
legnaleurc:有的CPU會在overflow的時候設為最大值,但我不知道ARM 02/14 02:27
DrStein:ARM確定是沒有 x86也沒有 :) 02/14 02:28
legnaleurc:有沒有...否則就是觀察branch miss看是哪邊的機率高 02/14 02:28
VictorTom:疑, 可是查了一下YUV2RGB是clamp結果不是source啊@_@" 02/14 02:28
legnaleurc:再手動 predict 02/14 02:29
VictorTom:看到修文了, 不好意思....:) 02/14 02:30
※ 編輯: DrStein 來自: 58.115.143.194 (02/14 02:32)
legnaleurc:不過這已經算是人工解決 control hazard 了吧 @@ 02/14 02:32
※ 編輯: DrStein 來自: 58.115.143.194 (02/14 02:36)
VictorTom:可能從定義域或值域的range來把bitmask設得更精簡嗎?? 02/14 02:37
DrStein:想過,因為暴出來就從256~251之間 所以理論上只要檢查第 02/14 02:41
DrStein:9個bit是否為0或1即可 02/14 02:41
DrStein:"若"是0就對第一到第八個bit做 bit and 0xff 02/14 02:42
DrStein:反之設為 0xff 02/14 02:43
DrStein:但這樣等於沒優化 因為用了個 if 02/14 02:43
VictorTom:為什麼?? 不是跟負數一樣用個bit array就好了嗎?? 02/14 02:45
VictorTom:小弟想到的是 OR 0x00 或 0xFF....@_@" 02/14 02:46
VictorTom:當然8th bit以上要一律AND 0掉, 這樣判斷<0先跑再跑>255 02/14 02:47
VictorTom:應該可以吧....@_@" 02/14 02:47
VictorTom:of=(R&0x0100)>>8; R = (R | bitmap[of]) & 0xFF; 02/14 02:52
VictorTom:of用途同SIGN, bitmap就是bitand_map[]那個這樣@_@" 02/14 02:53
DrStein:了解了 用or_map[2] = {0x00, 0xff}; 02/14 02:54
DrStein:在將節果與這個表bit or即可 02/14 02:55
DrStein:剛一直想到包絡線問題(另個類似的問題),兩個搞混,。。 02/14 02:55
DrStein:謝謝VictorTom :) 02/14 02:56
※ 編輯: DrStein 來自: 58.115.143.194 (02/14 02:57)
VictorTom:不會啦XD 02/14 02:59
akasan:哪一顆 ARM ? ARMv6 的指令有 sat 可以用阿... 02/14 09:45
akasan:google "yuv rgb arm" 有人家寫好的組合語言加速版 試試吧 02/14 09:49
genghiskii:要加速用CUDA不是比較快嗎... 02/14 13:23
DrStein:非x86,只有少數的平板電腦能用CUDA 02/14 13:37
softwind:如果能夠full lookup, 可以用查表指令 xlat試試 02/14 21:59
VictorTom:小弟也覺得, 要是有低階指令可以做sat可能是最快的XD 02/14 22:00
akasan:再看了一次推文發現你說 overhead 在branch, 但在 arm 上 02/14 22:05
akasan:這種 code 可以很直覺的交給 compiler 轉 cond execution 02/14 22:05
akasan:最佳化開下去那種 code 不應該生出 branch 的 02/14 22:06
akasan:手邊的 arm gcc 開個 -O1 就會轉了 02/14 22:07