作者erspicu (.)
標題Re: [討論] 寫三元判斷式code review被打槍
時間2022-12-26 23:04:05
※ 引述《unixxxx (皓皓)》之銘言:
: 標題: Re: [討論] 寫三元判斷式code review被打槍
: 時間: Sat Dec 17 03:51:38 2022
: 很多Javascript 高手都是用 switch 取代
"特定"情況下的確是好方式
舉個例子 以前我在調校能時候有用過這種方式 這是c#的code部分節錄
void Mem_w(ushort address, byte value)
{
if (address < 0x2000) NES_MEM[address & 0x7ff] = value;
else if (address < 0x4020) IO_write(address, value);
else if (address < 0x6000) MapperRouterW_ExpansionROM(address,value);
else if (address < 0x8000) MapperRouterW_RAM(address, value);
else MapperRouterW_PRG(address, value);
}
這個是一個非常頻繁被呼叫的method 如果address 大於等於0x8000
其實前面就浪費好幾次計算在判斷式上
因此改成 功能上是相等的
static void Mem_w(ushort address, byte value)
{
switch (address & 0xf000)
{
case 0:
case 0x1000:
NES_MEM[address & 0x7ff] = value;
break;
case 0x2000:
case 0x3000:
case 0x4000:
IO_write(address, value);
break;
case 0x5000:
MapperObj.MapperW_ExpansionROM(address, value);
break;
case 0x6000:
case 0x7000:
MapperObj.MapperW_RAM(address, value);
break;
case 0x8000:
case 0x9000:
case 0xa000:
case 0xb000:
case 0xc000:
case 0xd000:
case 0xe000:
case 0xf000:
MapperObj.MapperW_PRG(address, value);
break;
}
}
但再簡化快速下去還有大招
初始化執行一次就好
static void init_function()
{
mem_write_fun = new Action<ushort, byte>[0x10000];
for (int address = 0; address < 0x10000; address++)
{
if (address < 0x2000) mem_write_fun[address] =
new Action<ushort, byte>((addr, val) => { NES_MEM[addr & 0x7ff] = val; });
else if (address < 0x4020) mem_write_fun[address] =
new Action<ushort,byte>(IO_write);
else if (address < 0x6000) mem_write_fun[address] =
new Action<ushort, byte>(MapperObj.MapperW_ExpansionROM);
else if (address < 0x8000) mem_write_fun[address] =
new Action<ushort, byte>(MapperObj.MapperW_RAM);
else mem_write_fun[address] =
new Action<ushort, byte>(MapperObj.MapperW_PRG);
}
}
之後讀取
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void Mem_w(ushort address, byte value)
{
mem_write_fun[address](address, value);
}
實際上跟switch原理很相似 但直接把mapper的實作 哪個address對應啥動作
直接寫到記憶址array去了
我是不知道你所謂的javascript高手用switch替代判斷式是碰到啥議題
但特定議題用改用switch 甚至自己刻死路由效能是會快非常多
以前有筆記在這邊...
https://dotblogs.com.tw/enet/2017/01/21/emu_optimization_1
--
※ 發信站: 批踢踢實業坊(pttsite.org.tw), 來自: 39.15.64.117 (臺灣)
※ 文章網址: https://pttsite.org.tw/Soft_Job/M.1672067047.A.133
※ 編輯: erspicu (39.15.64.117 臺灣), 12/26/2022 23:04:55
※ 編輯: erspicu (39.15.64.117 臺灣), 12/26/2022 23:13:24
→ MoonCode: ... 12/26 23:47
→ MoonCode: 快不快還是 benchmark 或看編譯出來什麼東西吧 12/26 23:48
推 MoonCode: 12/27 00:01
推 jason222333: 推 12/27 06:32
推 DarkIllusion: 好奇問 為什麼這裡switch-case會比多重if-else快? 12/27 06:48
推 Toth: 有人被洋鬼子包養過嗎 12/27 06:48 → DarkIllusion: 以及 為什麼這裡用function map比switch-case快? 12/27 06:50
推 DarkIllusion: 如果頻繁判斷address大於等於0x8000 那這判斷放前面 12/27 06:55
→ DarkIllusion: 為什麼不會是個好的解法? 12/27 06:56
推 Jichang: 這不是大一計概就會教的 if else 是循序判斷 switch 是ju 12/27 06:58
→ Jichang: mp map是hash 但是好的compiler可以直接最佳化if else 12/27 06:58
推 Asterix: 到底要多有錢才會想包養 12/27 06:58 推 DarkIllusion: 抱歉 我比較沒有計概常識 12/27 07:01
→ DarkIllusion: 看來原PO用的是沒那麼好的compiler :( 12/27 07:07
→ leolarrel: 單純補充一下,這應該不適合在C. 剛用gcc 看組語內容, 12/27 13:44
→ leolarrel: switch 仍然用比較且跳躍來實作 12/27 13:44
推 MyNion: 你下面陣列開了六萬多個再用for去跑,真的需要那麼多個? 12/27 15:54
推 AdamShi: 閨蜜上包養網還推薦我... 12/27 15:54 → MyNion: 因為你的case只有五種,要不要數字進來都/5,這樣較省空間 12/27 15:56
推 chuegou: 就算是C 還可以問你優化編譯有沒有開 12/27 22:08
→ peter98: 這種其實沒甚麼好討論的 就算真的這樣做有用 也只是單 12/27 22:35
→ peter98: 一case適用 另外 profiling的情況是有規定的 不是隨便 12/27 22:35
→ peter98: 跑 上次不知道哪個人開debug mode做profiling 原本想說 12/27 22:36
推 lezabo: 包養? 12/27 22:36 → peter98: 甚麼 後來想想還是算了 12/27 22:36
→ peter98: 打錯 我是指開IDE去run程式做profiling 12/27 22:38
推 wulouise: 開IDE跟profiling是之間沒有關係,除非開debug build 12/28 12:27
→ leolarrel: chuegou, 我用gcc -O0跟-O3測試.你也可以自己試試看 12/28 13:19
推 ku399999: 好奇效能差很多最後是快多少 func功能還是比條件判斷 12/30 09:37
推 silberger: 現在包養網都這麼直接嗎 12/30 09:37 → ku399999: 佔更多執行時間才對 12/30 09:38