From 349ebc0baddd097aa4a8b3a05d5f10da4571d24a Mon Sep 17 00:00:00 2001 From: Stefan Arentz Date: Sun, 15 Jan 2017 16:28:32 -0500 Subject: [PATCH] Fixes #137 Benchmark CPU Module (#138) --- src/Makefile | 12 +++++-- src/cpu.c | 6 ---- src/cpu.h | 4 +++ src/cpu_bench.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 src/cpu_bench.c diff --git a/src/Makefile b/src/Makefile index d9fb437..6d386a2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -39,10 +39,15 @@ SCR_TEST_SOURCES=cpu.c ins.c mem.c fmt.c two.c scr.c dsk.c chr.c alc.c utl.c scr SCR_TEST_OBJECTS=$(SCR_TEST_SOURCES:.c=.o) SCR_TEST_LIBS=-lSDL2 -all: $(EWM_SOURCES) $(EWM_EXECUTABLE) $(CPU_TEST_SOURCES) $(CPU_TEST_EXECUTABLE) $(SCR_TEST_EXECUTABLE) +CPU_BENCH=cpu_bench +CPU_BENCH_SOURCES=cpu.c ins.c mem.c fmt.c cpu_bench.c +CPU_BENCH_OBJECTS=$(CPU_BENCH_SOURCES:.c=.o) +CPU_BENCH_LIBS= + +all: $(EWM_SOURCES) $(EWM_EXECUTABLE) $(CPU_TEST_SOURCES) $(CPU_TEST_EXECUTABLE) $(SCR_TEST_EXECUTABLE) $(CPU_BENCH) clean: - rm -f $(EWM_OBJECTS) $(EWM_EXECUTABLE) $(CPU_TEST_OBJECTS) $(CPU_TEST_EXECUTABLE) $(SCR_TEST_OBJECTS) $(SCR_TEST_EXECUTABLE) + rm -f $(EWM_OBJECTS) $(EWM_EXECUTABLE) $(CPU_TEST_OBJECTS) $(CPU_TEST_EXECUTABLE) $(SCR_TEST_OBJECTS) $(SCR_TEST_EXECUTABLE) $(CPU_BENCH) $(EWM_EXECUTABLE): $(EWM_OBJECTS) $(CC) $(LDFLAGS) $(EWM_OBJECTS) $(EWM_LIBS) -o $@ @@ -53,5 +58,8 @@ $(CPU_TEST_EXECUTABLE): $(CPU_TEST_OBJECTS) $(SCR_TEST_EXECUTABLE): $(SCR_TEST_OBJECTS) $(CC) $(LDFLAGS) $(SCR_TEST_OBJECTS) $(SCR_TEST_LIBS) -o $@ +$(CPU_BENCH): $(CPU_BENCH_OBJECTS) + $(CC) $(LDFLAGS) $(CPU_BENCH_OBJECTS) $(CPU_BENCH_LIBS) -o $@ + .c.o: $(CC) $(CFLAGS) $< -c -o $@ diff --git a/src/cpu.c b/src/cpu.c index 73fb70d..9d4d3bb 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -37,12 +37,6 @@ #include "mem.h" #include "fmt.h" -/* Private API */ - -typedef void (*cpu_instruction_handler_t)(struct cpu_t *cpu); -typedef void (*cpu_instruction_handler_byte_t)(struct cpu_t *cpu, uint8_t oper); -typedef void (*cpu_instruction_handler_word_t)(struct cpu_t *cpu, uint16_t oper); - // Stack management. void _cpu_push_byte(struct cpu_t *cpu, uint8_t b) { diff --git a/src/cpu.h b/src/cpu.h index ada06a3..4189451 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -56,6 +56,10 @@ struct cpu_t { uint64_t counter; }; +typedef void (*cpu_instruction_handler_t)(struct cpu_t *cpu); +typedef void (*cpu_instruction_handler_byte_t)(struct cpu_t *cpu, uint8_t oper); +typedef void (*cpu_instruction_handler_word_t)(struct cpu_t *cpu, uint16_t oper); + #define MEM_FLAGS_READ 0x01 #define MEM_FLAGS_WRITE 0x02 diff --git a/src/cpu_bench.c b/src/cpu_bench.c new file mode 100644 index 0000000..81c5813 --- /dev/null +++ b/src/cpu_bench.c @@ -0,0 +1,88 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Stefan Arentz - http://github.com/st3fan/ewm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include +#include +#include + +#include "cpu.h" +#include "ins.h" +#include "mem.h" + +#define CPU_BENCH_ITERATIONS (100 * 1000 * 1000) + +void test(struct cpu_t *cpu, uint8_t opcode) { + uint64_t runs[3]; + + struct cpu_instruction_t *ins = &cpu->instructions[opcode]; + + for (int run = 0; run < 3; run++) { + struct timespec start; + if (clock_gettime(CLOCK_REALTIME, &start) != 0) { + perror("Cannot get time"); + exit(1); + } + + switch (ins->bytes) { + case 1: + for (uint64_t i = 0; i < CPU_BENCH_ITERATIONS; i++) { + ((cpu_instruction_handler_t) ins->handler)(cpu); + } + break; + case 2: + for (uint64_t i = 0; i < CPU_BENCH_ITERATIONS; i++) { + ((cpu_instruction_handler_byte_t) ins->handler)(cpu, 0x12); + } + break; + case 3: + for (uint64_t i = 0; i < CPU_BENCH_ITERATIONS; i++) { + ((cpu_instruction_handler_word_t) ins->handler)(cpu, 0x1234); + } + break; + } + + struct timespec now; + if (clock_gettime(CLOCK_REALTIME, &now) != 0) { + perror("Cannot get time"); + exit(1); + } + + uint64_t duration_ms = (now.tv_sec * 1000 + (now.tv_nsec / 1000000)) + - (start.tv_sec * 1000 + (start.tv_nsec / 1000000)); + + runs[run] = duration_ms; + } + + printf("$%.2X %s %8llu %8llu %8llu -> %8llu\n", + opcode, ins->name, runs[0], runs[1], runs[2], + (runs[0] + runs[1] + runs[2]) / 3); +} + +int main(int argc, char **argv) { + struct cpu_t *cpu = cpu_create(EWM_CPU_MODEL_65C02); + cpu_add_ram_data(cpu, 0, 0xffff, malloc(0xffff)); + cpu_reset(cpu); + + for (int opcode = 0; opcode <= 255; opcode++) { + test(cpu, opcode); + } +}