kamiyaowl / rust-nes-emulator

NES Emulator written in Rust
MIT License
206 stars 12 forks source link

動作を高速化する #85

Open kamiyaowl opened 4 years ago

kamiyaowl commented 4 years ago

思い当たる節

kamiyaowl commented 4 years ago

FPSカウンターだけの表示だと秒10000いける

    for (uint32_t counter = 0 ; ; ++counter ) {
        // EmbeddedEmulator_update_screen(&fb);
        // print_framebuffer(150, 0, 2);

        sprintf(msg, "%d", counter);
        BSP_LCD_DisplayStringAt(5, 5, (uint8_t *)msg, LEFT_MODE);

        /* Touchscreen test */
        // TS_StateTypeDef  TS_State = {0};
        // BSP_TS_GetState(&TS_State);
        // if(TS_State.touchDetected) {
        //     const uint16_t x1 = TS_State.touchX[0];
        //     const uint16_t y1 = TS_State.touchY[0];
        //     BSP_LCD_SetTextColor(LCD_COLOR_BLUE);
        //     BSP_LCD_FillCircle(x1, y1, 10);
        // }
    }
kamiyaowl commented 4 years ago

エミュレーションだけ入れると10fps

    for (uint32_t counter = 0 ; ; ++counter ) {
        EmbeddedEmulator_update_screen(&fb);
        // print_framebuffer(150, 0, 2);

        sprintf(msg, "%d", counter);
        BSP_LCD_DisplayStringAt(5, 5, (uint8_t *)msg, LEFT_MODE);

        /* Touchscreen test */
        // TS_StateTypeDef  TS_State = {0};
        // BSP_TS_GetState(&TS_State);
        // if(TS_State.touchDetected) {
        //     const uint16_t x1 = TS_State.touchX[0];
        //     const uint16_t y1 = TS_State.touchY[0];
        //     BSP_LCD_SetTextColor(LCD_COLOR_BLUE);
        //     BSP_LCD_FillCircle(x1, y1, 10);
        // }
    }
kamiyaowl commented 4 years ago

print_framebuffer入れても8fps、これは最適化が効いている気がする

    for (uint32_t counter = 0 ; ; ++counter ) {
        EmbeddedEmulator_update_screen(&fb);
        print_framebuffer(150, 0, 2);

        sprintf(msg, "%d", counter);
        BSP_LCD_DisplayStringAt(5, 5, (uint8_t *)msg, LEFT_MODE);

        /* Touchscreen test */
        // TS_StateTypeDef  TS_State = {0};
        // BSP_TS_GetState(&TS_State);
        // if(TS_State.touchDetected) {
        //     const uint16_t x1 = TS_State.touchX[0];
        //     const uint16_t y1 = TS_State.touchY[0];
        //     BSP_LCD_SetTextColor(LCD_COLOR_BLUE);
        //     BSP_LCD_FillCircle(x1, y1, 10);
        // }
    }
kamiyaowl commented 4 years ago

ざっとこんな感じ。本当ならPPUは完全並列で動かしていいのだけれど、ポリシーに反するのでアレ

kamiyaowl commented 4 years ago

opt-level=3, debug_assertions=noで2msぐらい削れた

kamiyaowl commented 4 years ago

ICache/DCache有効にしてなさそう。core_cm7のSCB_xxxにキャッシュ操作周りのインライン関数がある

kamiyaowl commented 4 years ago

体感でわからんぐらいだな、なんかミスってるかも

    SCB_EnableDCache();
    SCB_EnableICache();
kamiyaowl commented 4 years ago

ART, Prefetch Buffer有効化して9fpsぐらい。framebuffer解決しても15fps届くかどうかぐらいか

kamiyaowl commented 4 years ago

思い当たる節

kamiyaowl commented 4 years ago

一旦デスクトップ向け環境でもいいから、ベンチ図る環境を構築すべき、100frame書くまでにどのぐらいかかるか。などで

kamiyaowl commented 4 years ago

u16のアンアラインドな読み書きは間違いなくパフォーマンス低下になっていそう

kamiyaowl commented 4 years ago

まぁあえてu32使わせるのももとのコード崩しすぎるから微妙。 あとppuのdraw_lineは剰余が使われていたりするので、ここもdisasm眺めてみたほうがいいかも

kamiyaowl commented 4 years ago
kamiyaowl commented 4 years ago

SRAM先頭はDTCMに乗ってるけど、FlashはITCM使ってなさそう 実際のところ、ROMの固定地はcassette構造体の配列にコピーして利用しているのでFlashのアクセス経路には依存しない DCacheを有効にしてもすでにDTCM上にあるので、ゼロウェイト非キャッシュで恩恵がなかったと見るべき

MEMORY

{ 

FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K

RAM (rwx) : ORIGIN = 0x200001F8, LENGTH = 512K - 0x1F8

}
kamiyaowl commented 4 years ago

https://youtu.be/73ciNT9tl-U f4で30fps前後は出ていそう

kamiyaowl commented 4 years ago

小手先の修正で劇的に速くならなかったので、以下案

mbedプラットフォーム上でブラッシュアップするもの

処理としてブラッシュアップできる物

rustとしてunsafeを伴うが高速化できるもの

arm向けに最適化するもの

既存のコードと整合取れなくなる点どうしよう...型まるごと置き換えたりすると原型は保てなさそう

kamiyaowl commented 4 years ago

現在、ベンチテストは60frame書くのにかかる時間

running 6 tests
test tests::test_run_hello_cpu ... ignored
test tests::test_run_hello_ppu ... ignored
test tests::test_run_mario_demo ... ignored
test tests::test_run_mario_title ... ignored
test tests::test_run_nestest ... ignored
test bench::bench_hello ... bench:  94,229,800 ns/iter (+/- 4,619,103)
kamiyaowl commented 4 years ago

ちょっと変わった...?

test bench::bench_hello ... bench:  92,228,830 ns/iter (+/- 7,182,915)    
test bench::bench_hello ... bench:  93,150,040 ns/iter (+/- 5,742,562)
kamiyaowl commented 4 years ago

剰余をbit andにするのはあまり変わらなそう

kamiyaowl commented 4 years ago

関数呼び出しをフェッチしてあげるのは結構明確に聞くっぽい、何でもかんでもinlineにするのはきらいだが

test bench::bench_hello ... bench:  89,489,360 ns/iter (+/- 7,959,146)
kamiyaowl commented 4 years ago

これみてたらやっぱunstable使ってでもconst fn使ったほうがいい気がしてきた

test bench::bench_hello ... bench:  76,373,280 ns/iter (+/- 3,452,911)
kamiyaowl commented 4 years ago

更に引数の数を減らしたりして2ms縮めた。多分これはarm相手だともっと効くはず。

test bench::bench_hello ... bench:  74,050,190 ns/iter (+/- 2,112,266)

動かしてみた感じ、体感でわかるぐらい気持ち早くなっていたがまだまだ

kamiyaowl commented 4 years ago

進捗

mbedプラットフォーム上でブラッシュアップするもの

処理としてブラッシュアップできる物

94.2ms -> 74.1msまで縮んだよ。やったね!

rustとしてunsafeを伴うが高速化できるもの

arm向けに最適化するもの

既存のコードと整合取れなくなる点どうしよう...型まるごと置き換えたりすると原型は保てなさそう

kamiyaowl commented 4 years ago

コードぶっ壊したくないとの兼ね合いが難しいしつらい。特にrustだと

kamiyaowl commented 4 years ago

境界チェック外しは、featureでマクロ切り替える方式が良さそう

kamiyaowl commented 4 years ago

あとusizeはターゲットのアドレス空間でサイズが決まる模様。arm向けなら4byte

kamiyaowl commented 4 years ago

カセットの読み書きをuncheckedにしたら1ms縮まった...

test bench::bench_hello ... bench:  73,403,310 ns/iter (+/- 2,966,874)
kamiyaowl commented 4 years ago

system/video_systemに適用したがあまり変わらず、全体的なアクセスはカセットを占めているので自明ではある。

kamiyaowl commented 4 years ago
test bench::bench_hello ... bench:  73,348,660 ns/iter (+/- 1,937,178)
kamiyaowl commented 4 years ago

きちんと確認していないけど条件的に範囲外例外を超えない可能性が高い領域だからかもしれない。 system_read/writeの中身はリージョンサイズで小さい順にifで引っ掛けているので、コンパイラが最後の条件までは範囲外にならないことを知っている。 なのでカセットに対してしか有効な高速化にならなかった。

kamiyaowl commented 4 years ago

system_ppu_regにinlineいれても早くならんな

kamiyaowl commented 4 years ago

x86だからかと思ったけど普通に遅くなった

kamiyaowl commented 4 years ago

(ARMでも