I've been using timer_us_gettime64 for profiling for years, and I've noticed the occasional hiccup with results from it. This post also applies to timer_ms_gettime and timer_ms_gettime64.
I had a bar graph showing how long different processes were taking, and for a single frame, the bar graph would sometimes have some insane value and go off the charts. At first, I thought it was a problem on my end, but eventually I noticed that something was supposedly taking multiple frames, but I was still having a new frame rendered every vblank, which made me think it there was a problem with the time KOS was returning.
It looks like the problem comes from a race condition between reading the seconds value KOS keeps track of, and reading the SH4 TMU value for more precision. For example, in timer_us_gettime64...
scnt = timer_ms_counter;
cnt = timer_count(TMU2);
...the TMU can underflow and trigger and IRQ between when timer_ms_counter is read and when timer_count(TMU2) is read. The events end up like this:
- timer_us_gettime64 is called
- Read 5 from timer_ms_counter
- Read value from timer_count(TMU2)
- timer_us_gettime64 returns 5.5 seconds since boot
- Almost half a second time passes and timer_us_gettime64 is called again
- Read 5 from timer_ms_counter
- Timer underflows, IRQ handler increments timer_ms_counter to 6 and TMU resets
- Read value from timer_count(TMU2)
- timer_us_gettime64 returns 5.0 seconds since boot (Should be 5.999 or 6.0)
- The first time is subtracted unsigned from the second time (5.0 - 5.5), resulting in 2**64-0.5 seconds having elapsed between calls to gettime
I made a basic test to check for unusual timer behavior. It runs until a key is pressed on a keyboard. It rapidly polls the timer, and when there is a large difference between two calls to gettime it prints the difference. Using the original KOS timer, I would get about three timer errors detected each minute. With my fixes, I haven't found any errors after 10 minutes.
On a semi-related note, why is the seconds timer called a millisecond timer in the code? timer_ms_counter doesn't count milliseconds, it apparently actually counts seconds.