1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
[Note: this is a work in progress, and it's not finished. Neither is
the coverage code, meaning what you see here is subject to change as
the code changes!]
Starting with Atari800 3.2.0, the monitor has a new COV (coverage)
command. This is meant to be a short explanation & tutorial that should
help everyone understand what COV is & what it's good for.
The general idea is that COV can tell you:
- What sections of code were executed, and what sections weren't.
For development, this is useful for testing. Ideally, you want to
"exercise" all your code, to verify that it works properly. Code that
never gets run can't be tested. For reverse engineering, this will
help you identify sections of memory as code or data, and it's handy
for finding dead code areas.
- How often each instruction was executed, and...
- How much CPU time (6502 cycles) each instruction or section used.
For development, these are useful for finding performance
bottlenecks. You can concentrate only on optimizing the code that's
run most frequently. For reverse engineering, this helps you identify
'interesting' sections of code.
A word of caution: Currently, the COV command doesn't know anything
about bankswitching (neither XL/XE PORTB switching nor cartridges).
If the range of code you're examining with COV gets bankswitched out
and different code is run at the same address, COV's results will be
confusing and probably useless. To avoid this, limit yourself to working
with one small(ish) section of code at a time, or else set breakpoints
on the instructions that do the bankswitching, and manually clear the
coverage stats (COV C) when the breakpoints are triggered.
COV has 5 subcommands:
COV C - Clears the coverage stat counters. Every address in the emulated
Atari (0 to FFFF) has two counters: number of times executed, and cycles
used. These are updated whenever the emulator runs the CPU (including
exiting the monitor via CONT, or using the G/R/O commands). The counters
start out at zero when Atari800 starts, and are NEVER automatically zeroed
(not even when using the COLDSTART command). The only way to clear them
is to use COV C. You should definitely do this any time you alter the
code with the A (assembler) command.
The other commands are for viewing the coverage stats. They each take
an optional start and end address, which sets the coverage range (the
range of code we're "looking at"). If no start/end addresses are given,
the commands use the current range (last start/end addresses given,
or 0000 to FFFF if no range was given).
COV S - Show a summary of the coverage stats. As an example, you'll get
something similar to this [*] if you start Atari800 with BASIC enabled,
wait a second or so at the READY prompt, press F8 to enter the monitor,
then use COV S with the start & end addresses of the cartridge:
> cov s a000 bfff
Range a000-bfff: 883(0.14%) insns, 2889(0.17%) cycles executed
Coverage: 378(4.61%) of 8192
Total: 616725 instructions, 1706224 cycles executed
[*] But probably not identical, unless you hit F8 at exactly the
same time since startup as I did.
What's this telling us? Let's look at the first line first:
883(0.14%) insns - 883 instructions in the range a000-bfff were executed,
which amounts to 0.14% of all instructions executed so far. If the same
instruction was executed more than once (e.g. a loop), it's counted
each time. 883 works out to 0.14% of the total instructions executed
(see the 3rd line of output). Notice that 0.14% isn't really very much:
most of the code the Atari has executed so far is outside of the range
a000-bfff (it's actually in the c000-ffff range, aka the OS ROM).
2889(0.17%) cycles - Those 883 instructions took 2889 cycles to execute,
or 0.17% of the cycles the CPU has executed so far.
The second line is: Coverage: 378(4.61%) of 8192
It's telling us that there are 8192 (decimal) memory locations in the
range we're looking at (a000-bfff), and that 378 of them have been
executed as instructions [*], which works out to 4.61%. Note that any
real program (such as BASIC) will contain data as well as code, so
it's unlikely that you'll ever see 100% coverage if you're looking at
the whole program. You will, if you "drill down" to look at individual
subroutines or loops.
[*] ...or, being perfectly pedantic, as operands to instructions. An
immediate LDA #0 counts as 2 instructions, here.
The last line gives the total CPU instruction and cycle counts since
startup (or since the last COV C command). These are what was used to
calculate the percentages on the first line.
So if BASIC only used 0.17% of the CPU cycles, what used the other 98.83%?
A good guess would be the OS. Let's check:
> cov s c000 ffff
Range c000-ffff: 615842(99.86%) insns, 1703335(99.83%) cycles executed
Coverage: 2089(12.75%) of 16384
Total: 616725 instructions, 1706224 cycles executed
Yep, that's it, 99.83%. Was any other code run?
> cov s 0000 9fff
Range 0000-9fff: 0(0.00%) insns, 0(0.00%) cycles executed
Coverage: 0(0.00%) of 40960
Total: 616725 instructions, 1706224 cycles executed
Nope.
OK, let's go back to looking at BASIC. Enter "cov s a000 bfff" again,
you should get the same display as the first example. Now, let's play
around with BASIC a bit, and see what we get. Use "cont" to get back
into BASIC, and type:
PRINT "HELLO"
...which will give you HELLO followed by another READY prompt. Now
press F8 to get back to the monitor and run "cov s". Notice there are no
start/end addresses in the command? COV will re-use the last start/end
addresses we gave it (in this case, a000 and bfff). You should see
something like:
Range a000-bfff: 15339(0.33%) insns, 47727(0.39%) cycles executed
Coverage: 1438(17.55%) of 8192
Total: 4642110 instructions, 12216322 cycles executed
The coverage was 4.61% before, so running that PRINT command caused about
12% of the cartridge to run. You can try various other BASIC commands
and watch the coverage increase, but it won't ever reach 100% because
not everything in the BASIC ROM is code (some of it's data tables).
COV H - Show CPU hogs
TODO: write the rest of this!
|