From 6e3da3c333c70acd6a8a9e88c9ee1502872dc72a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com>
Date: Tue, 1 Nov 2022 10:36:19 +0000
Subject: [PATCH] refactor: benchmark running structure

---
 examples/web/index.ts      | 46 +++++++++++++++++---------------------
 examples/web/react/app.tsx | 46 ++++++++++++++++++++++++++++----------
 src/cpu.rs                 |  2 +-
 3 files changed, 55 insertions(+), 39 deletions(-)

diff --git a/examples/web/index.ts b/examples/web/index.ts
index b3df5cfc..bc44e844 100644
--- a/examples/web/index.ts
+++ b/examples/web/index.ts
@@ -361,32 +361,6 @@ class GameboyEmulator extends Observable implements Emulator {
     }
 
     registerButtons() {
-        const buttonBenchmark = document.getElementById("button-benchmark")!;
-        buttonBenchmark.addEventListener("click", async () => {
-            buttonBenchmark.classList.add("enabled");
-            this.pause();
-            try {
-                const initial = Date.now();
-                const count = 500000000;
-                for (let i = 0; i < count; i++) {
-                    this.gameBoy!.clock();
-                }
-                const delta = (Date.now() - initial) / 1000;
-                const frequency_mhz = count / delta / 1000 / 1000;
-                this.trigger("message", {
-                    text: `Took ${delta.toFixed(
-                        2
-                    )} seconds to run ${count} ticks (${frequency_mhz.toFixed(
-                        2
-                    )} Mhz)!`,
-                    timeout: 7500
-                });
-            } finally {
-                this.resume();
-                buttonBenchmark.classList.remove("enabled");
-            }
-        });
-
         const buttonDebug = document.getElementById("button-debug")!;
         buttonDebug.addEventListener("click", () => {
             const sectionDebug = document.getElementById("section-debug")!;
@@ -567,6 +541,26 @@ class GameboyEmulator extends Observable implements Emulator {
         this.boot({ engine: null });
     }
 
+    benchmark() {
+        this.pause();
+        try {
+            const initial = Date.now();
+            const count = 500000000;
+            for (let i = 0; i < count; i++) {
+                this.gameBoy!.clock();
+            }
+            const delta = (Date.now() - initial) / 1000;
+            const frequency_mhz = count / delta / 1000 / 1000;
+            return {
+                delta: delta,
+                count: count,
+                frequency_mhz: frequency_mhz
+            };
+        } finally {
+            this.resume();
+        }
+    }
+
     async fetchRom(romPath: string): Promise<[string, Uint8Array]> {
         // extracts the name of the ROM from the provided
         // path by splitting its structure
diff --git a/examples/web/react/app.tsx b/examples/web/react/app.tsx
index 21fd1c2e..e37d6400 100644
--- a/examples/web/react/app.tsx
+++ b/examples/web/react/app.tsx
@@ -58,6 +58,12 @@ export type RomInfo = {
     extra?: Record<string, string | undefined>;
 };
 
+export type BenchmarkResult = {
+    delta: number;
+    count: number;
+    frequency_mhz: number;
+};
+
 export interface ObservableI {
     bind(event: string, callback: Callback<this>): void;
     trigger(event: string): void;
@@ -138,11 +144,20 @@ export interface Emulator extends ObservableI {
      * Returns the current logic framerate of the running
      * emulator.
      *
-     * @return The current logic framerate of the running
+     * @returns The current logic framerate of the running
      * emulator.
      */
     getFramerate(): number;
 
+    /**
+     * Boot (or reboots) the emulator according to the provided
+     * set of options.
+     *
+     * @param options The options that are going to be used for
+     * the booting operation of the emulator.
+     */
+    boot(options: any): void;
+
     /**
      * Toggle the running state of the emulator between paused
      * and running, prevents consumers from the need to access
@@ -160,13 +175,12 @@ export interface Emulator extends ObservableI {
     reset(): void;
 
     /**
-     * Boot (or reboots) the emulator according to the provided
-     * set of options.
+     * Runs a benchmark operation in the emulator, effectively
+     * measuring the performance of it.
      *
-     * @param options The options that are going to be used for
-     * the booting operation of the emulator.
+     * @returns The result metrics from the benchmark run.
      */
-    boot(options: any): void;
+    benchmark(): BenchmarkResult;
 }
 
 /**
@@ -274,9 +288,12 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
 
     const onFile = async (file: File) => {
         // @todo must make this more flexible and not just
-        // Game Boy only
+        // Game Boy only (using the emulator interface)
         if (!file.name.endsWith(".gb")) {
-            showToast("This is probably not a Game Boy ROM file!", true);
+            showToast(
+                `This is probably not a ${emulator.getDevice()} ROM file!`,
+                true
+            );
             return;
         }
 
@@ -316,11 +333,16 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
             "Are you sure you want to start a benchmark?\nThe benchmark is considered an expensive operation!",
             "Confirm"
         );
+        if (!result) return;
+        const { delta, count, frequency_mhz } = emulator.benchmark();
         await showToast(
-            result
-                ? "Will run the benchmark as fast as possible"
-                : "Will not run the benchmark",
-            !result
+            `Took ${delta.toFixed(
+                2
+            )} seconds to run ${count} ticks (${frequency_mhz.toFixed(
+                2
+            )} Mhz)!`,
+            undefined,
+            7500
         );
     };
     const onFullscreenClick = () => {
diff --git a/src/cpu.rs b/src/cpu.rs
index b6b0a32f..8acb6c0c 100644
--- a/src/cpu.rs
+++ b/src/cpu.rs
@@ -112,7 +112,7 @@ impl Cpu {
         }
 
         // @todo this is so bad, need to improve this by an order
-        // of magnitude
+        // of magnitude, to be able to have better performance
         if self.halted {
             if ((self.mmu.ie & 0x01 == 0x01) && self.mmu.ppu().int_vblank())
                 || ((self.mmu.ie & 0x02 == 0x02) && self.mmu.ppu().int_stat())
-- 
GitLab