class ZXUtils::Benchmark
ZXUtils::Benchmark
¶ ↑
Benchmarking utilities.
- NOTE
-
Currently the code must be located at 0x8000.
Example:
require 'zxutils/benchmark' require 'zxlib/basic' include ZXLib class BenchNeg16 include Z80 include Z80::TAP export test_neg16 label_import ZXLib::Sys import ZXUtils::Benchmark, :bm, macros: true get_bench_result calculate_benchmark_tstates(bm.counter, bm.tsframe, bm.frames, bm.idle, bm.adjustment) estimate_tsframes estimate_tstates_per_interrupt(vars.udg, bm.interrup_vec, bm.forward, bm.tsframe, bm.idle) ns :test_neg16 do xor a sub l ld l, a sbc a, a sub h ld h, a ret end end benchmark = BenchNeg16.new 0x8000 # Note: this must be the 0x8000 address at the moment. tsframe = benchmark['bm.tsframe'] program = Basic.parse_source <<-EOC 1 DEF FN n(x)=x-(65536 AND x>=32768) DEF FN b(a,c)=USR #{benchmark['bm.bench']}: REM benchmark DEF FN t()=USR #{benchmark['bm.getset_tsframe']}+65536*PEEK #{tsframe+2}: REM get ts/frame DEF FN s(t)=USR #{benchmark['bm.getset_tsframe']}+65536*PEEK #{tsframe+2}: REM set ts/frame DEF FN i()=USR #{benchmark['bm.get_idle']}: REM idle DEF FN r()=USR #{benchmark[:get_bench_result]}: REM result 10 LET counter=65535: LET frames=FN b(#{benchmark[:test_neg16]},counter) PRINT "Interrupts: ";frames PRINT "T-States: ";FN r() STOP 100 REM Estimate T-States/interrupt LET adj=FN n(USR #{benchmark[:estimate_tsframes]}): LET idl=FN i(): PRINT "Est. T-States/int.:";idl*512+adj;" (+-4)" INPUT "Is this ok? Y/n", a$: IF a$<>"n" AND a$<>"N" THEN RETURN INPUT "Enter value: ",tf: PRINT "T-States/int.:";FN s(tf) RETURN 9998 STOP 9999 CLEAR #{benchmark.org-1}: LOAD "benchmark"CODE: GO SUB 100: RUN EOC puts benchmark.debug puts program.to_source escape_keywords: true program.save_tap "testneg16", line: 9999 benchmark.save_tap "testneg16", name: "benchmark", append: true puts "TAP: testneg16.tap:" Z80::TAP.parse_file('testneg16.tap') do |hb| puts hb.to_s end
See also: ZXUtils::Benchmark::Macros
Public Instance Methods
bench()
click to toggle source
Benchmarks the tested routine. Provide a routine
address and a counter
. Returns a number of seconds (multiplied by the interrupt frequency - 50Hz) that have passed. This callback is to be used from the ZX Basic.
1 DEF FN b(a,c)=USR #{program['benchmark.bench']}
# File lib/zxutils/benchmark.rb, line 258 ns :bench do call fn_argn jr C, start error_q report_error_unless Z, 'Q Parameter error' call get_arg_bc ld [routine], bc call fn_argn.seek_next jr NZ, error_q.err call get_arg_bc ld [counter], bc end
get_adjustment()
click to toggle source
Returns a signed integer. Convert with: LET x=x-(65536 AND x>=32768)
# File lib/zxutils/benchmark.rb, line 377 ns :get_adjustment do ld bc, [adjustment] ret end
get_frames()
click to toggle source
Returns an unsigned integer
# File lib/zxutils/benchmark.rb, line 365 ns :get_frames do ld bc, [frames] ret end
get_idle()
click to toggle source
Returns an unsigned integer
# File lib/zxutils/benchmark.rb, line 371 ns :get_idle do ld bc, [idle] ret end
getset_tsframe()
click to toggle source
Returns a less significant 16-bit unsigned integer. Add 65536 to get the actual value.
# File lib/zxutils/benchmark.rb, line 348 ns :getset_tsframe do call fn_argn jr C, only_get jr NZ, only_get call get_arg_debc ld a, d ora a jp NZ, overflow_err ld [tsframe.bytes[0]], bc ld a, e ld [tsframe.bytes[2]], a ret only_get ld bc, [tsframe] ret end
start()
click to toggle source
A benchmark start entry for the machine-language.
Provide a routine
and a counter
address in the memory addressed by the appropriate labels.
# File lib/zxutils/benchmark.rb, line 273 with_saved :start, iy, :exx, hl, :exx, ret: true, use: vars do ld hl, [routine] ld [routine_a + 1], hl ld hl, -1 ld [frames], hl inc hl ld [idle], hl ld bc, [counter] di ld [restore_sp+1], sp ld sp, [vars.udg] ld hl, inthandler ld [forward+1], hl ld a, interrup_vec>>8 ld i, a im2 ei halt # 19 (accepting interrupt) + 10 (forward) + 73 (inthandler) #=102 iterate push bc # 11 routine_a call nop_test # 17+10+tested pop bc # 10 dec bc # 6 ld a, c # 4 ora b # 4 ld hl, finale # 10 jp NZ, iterate # 10 #=82+tested # Each full frame t-states: frames*(69888-102) # BC: 0 ld [forward+1], hl # 16 ld hl, forever # 10 #=26 forever inc c # 4 126.times { nop } # 126*4 jp (hl) # 4 #=512 # Last frame: tsframe-(idle*512 + (pc==forever ? 0 : (pc - finale)*4) + 102 + 26) finale ld [idle], bc # idle*512 + (pc==forever ? 0 : (pc - finale)*4) + 79 pop de # de: pc xor a ld hl, forever sbc hl, de # hl: forever - pc jr Z, no_adjust # hl: 0 (pc == forever) jr C, calc_idle # (pc > forever) ld hl, -10 # (pc < forever) jr no_adjust calc_idle ex de, hl # hl: pc ld de, finale xor a sbc hl, de # pc - finale add hl, hl # (pc - finale)*4 add hl, hl # hl: adjust = (pc - finale)*4 no_adjust add 102 + 26 adda_to h,l # hl: adjust + 102 + 26 ld [adjustment], hl restore_sp ld sp, 0 restore_rom_interrupt_handler ld bc, [frames] # return the number of frames that have passed end