Jump to content
izb

CPU meter

Recommended Posts

Been tinkering away at my game, and thought I'd spend some time adding better debug tools, so I added a CPU meter. I was getting concerned that I had no idea if my plans were going to fit into my frame budget.

The screenshot shows I'm using 32% of the CPU resources available. Well worth adding because it started out at 53% and it helped to reveal that I was doing some very slow and unnecessary things in my code that had to be improved or removed.

Basically it's just counting the cycles that it spends waiting for the vertical blank, and remapping that to a value from 0..100% based on the max number of cycles available at 60fps.

Figured out the max cycles by looking at the changes in the emulator's in-built cycle counter when the interrupt comes in.

As it turns out, the frame budget is 133,462 cycles, which sounds a lot. But then it also turns out that it's easy to write code that burns through those cycles really quickly if you're not careful 🙂 

cpumeter.png

  • Like 5

Share this post


Link to post
Share on other sites

The code is a horrible, unpresentable mishmash of magic numbers and macros, but I'll do my best...

This is the main wait loop which just thrashes and waits for the vbl interrupt to set a flag

Quote

 

    stz cycle_counterL
    stz cycle_counterH
    stz vsync_trigger
 
    :
    inc cycle_counterL
    bne @carry
    inc cycle_counterH ; (assume branch is not taken because it's a small error and that's ok)
    @carry:

    lda vsync_trigger
    beq :- ; thrash until we're in a vblank

 

This just waits for vsync_trigger to be set (by the interrupt) and counts up a cycle_counter value while it does so. From the emulator's own cycle counter, I can see that this loop is worth 14 cycles, so each tick of cycle_counter here is actually 14 cycles.

Quote

    ; Max cycles per frame is 133,462, or 9533 thrashes around this loop
    Movw arith_param_a, cycle_counter ; Copies one 16-bit ZP value to another
    Stow arith_param_b, 37 ; Stores a 16-bit value into a ZP location. 37 is the high byte of 9533, scaling the CPU usage to 0..255 after division
    jsr div_u16 ; Perform the division. Result is stored back in arith_param_a

So from there we know that the most amount of time we can spend in this loop is 9533 loops. If we divide our cycle counter by 37 (You'll need to find your own divide routine somewhere) then we end up with a value between 0 and 255 in the low byte of the division result.

Next up, we need to remap that byte to a 0..100 percentage value, which is:
 

Quote

    ; 0 == max CPU usage, 255 == idle, We want this inverted.
 
    ; Due to rounding errors, if the high byte of the result is > 0, then we should consider that idle.
    lda arith_param_a_H
    beq :+
    lda #$ff
    sta arith_param_a_L
    :
    lda arith_param_a_L
    eor #$ff
    sta arith_param_a_H ; Put result in high byte, shifting it up 8-bits
    stz arith_param_a_L ; Put 0 in the low byte
    ; The cpu usage is now a value from 0..65280. If we divide by 652, we will have remapped
    ; the cpu usage value from 0..100, which can be displayed as a percentage
    Stow arith_param_b, 652
    jsr div_u16

    lda arith_param_a_L
    sta cpu_usage  ; Store the single-byte result somewhere

There's probably cleaner or quicker ways to do this without the two divisions, but it seems to work well enough for my purposes.

I should probably calculate the number of cycles burned by calculating the CPU usage and subtract that from the result 🙂
 

  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

Very interesting, a great routine to add to every game project. Much better and more elegant than toggling a background colour that I have done...

Share this post


Link to post
Share on other sites

The Apple II emulator, AppleWin, counts the cycles of a "step" and shows it on-screen along with the registers, etc.  You can step over a line, routine or run to a breakpoint and you can see exactly how many cycles that took.  It's really great for profiling code.  That's one area where x16emu could get a lot stronger - better debugging tools.  Even with final hardware, having the ability to debug and profile in the emulator will be awesome and will lead to better quality software.  Hopefully, over time, x16emu keeps getting features such as that.

  • Like 2

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

Please review our Terms of Use