// test_fceux_0001.cpp // Unit test for fceux-0001: SubCheatsRead O(C) linear scan -> O(1) direct lookup // // Reproduces the defect in isolation, verifies the fix gives correct results, // and benchmarks the operation ratio at C=256 cheats. #include #include #include #include #include // ---- Reproduction of the defect ---- struct CHEATF_SUBFAST { uint16_t addr; uint8_t val; int compare; // -1 means no compare }; static const int MAX_CHEATS = 256; // ---- DEFECT: O(C) linear scan per read ---- static CHEATF_SUBFAST SubCheats_defect[MAX_CHEATS]; static int numsubcheats_defect = 0; static uint8_t defect_SubCheatsRead(uint16_t A) { CHEATF_SUBFAST *s = SubCheats_defect; int x = numsubcheats_defect; do { if (s->addr == A) { return s->val; } s++; } while (--x); return 0; // should not reach } // ---- FIX: O(1) direct index lookup ---- static CHEATF_SUBFAST SubCheats_fixed[MAX_CHEATS]; static int numsubcheats_fixed = 0; static int cheat_idx[0x10000]; static void fixed_init() { memset(cheat_idx, -1, sizeof(cheat_idx)); } static void fixed_add(uint16_t addr, uint8_t val, int compare) { int idx = numsubcheats_fixed; SubCheats_fixed[idx] = { addr, val, compare }; cheat_idx[addr] = idx; numsubcheats_fixed++; } static uint8_t fixed_SubCheatsRead(uint16_t A) { int idx = cheat_idx[A]; if (idx < 0) return 0; return SubCheats_fixed[idx].val; } // ---- Helpers ---- static long clock_ns() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (long)ts.tv_sec * 1000000000L + ts.tv_nsec; } static void build_defect(int n_cheats) { numsubcheats_defect = 0; for (int i = 0; i < n_cheats; i++) { uint16_t addr = (uint16_t)(0x0300 + i); SubCheats_defect[numsubcheats_defect++] = { addr, (uint8_t)(i & 0xFF), -1 }; } } static void build_fixed(int n_cheats) { fixed_init(); numsubcheats_fixed = 0; for (int i = 0; i < n_cheats; i++) { uint16_t addr = (uint16_t)(0x0300 + i); fixed_add(addr, (uint8_t)(i & 0xFF), -1); } } int main() { const int N = MAX_CHEATS; // 256 active cheats const int REPS = 10000000; // ---- Correctness: both implementations must return identical values ---- build_defect(N); build_fixed(N); for (int i = 0; i < N; i++) { uint16_t addr = (uint16_t)(0x0300 + i); uint8_t expected = (uint8_t)(i & 0xFF); uint8_t got_defect = defect_SubCheatsRead(addr); uint8_t got_fixed = fixed_SubCheatsRead(addr); assert(got_defect == expected && "defect implementation returned wrong value"); assert(got_fixed == expected && "fixed implementation returned wrong value"); } printf("CORRECTNESS: PASS (both return identical values for %d cheats)\n", N); // ---- Performance: O(1) must be substantially faster than O(C) ---- // Simulate reading from all cheat addresses REPS times (worst-case: last address each read) uint16_t worst_addr = (uint16_t)(0x0300 + N - 1); // last cheat = max scan in defect volatile uint8_t sink = 0; long t0 = clock_ns(); for (int r = 0; r < REPS; r++) { sink ^= defect_SubCheatsRead(worst_addr); } long defect_ns = clock_ns() - t0; long t1 = clock_ns(); for (int r = 0; r < REPS; r++) { sink ^= fixed_SubCheatsRead(worst_addr); } long fixed_ns = clock_ns() - t1; (void)sink; double ratio = (double)defect_ns / (double)fixed_ns; printf("BENCHMARK: defect=%ldns fixed=%ldns ratio=%.1fx (C=%d cheats)\n", defect_ns, fixed_ns, ratio, N); // Expect at least 5x improvement with 256 cheats assert(ratio >= 5.0 && "expected at least 5x speedup with O(1) lookup vs O(256) scan"); printf("PERFORMANCE: PASS (%.1fx >= 5.0x required)\n", ratio); printf("ALL TESTS PASSED\n"); return 0; }