Day 19 Sleep imprecision

Hi there.

I am working on day 19 and trying to improve the accuracy of sleep to reach 30 FPS. Casey seems to be able to hit 33.3 ms consistently.
I setup a minimal repro program, but my results are still much more imprecise:

 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
[5/15/2020 7:51:29 AM] 
Debugging new process...[OK]
Process ID: 10592
Milliseconds per Frame: 33.884300ms/f, work seconds: 0.000000s, sleep 0.033333s, sum 0.033333s
Milliseconds per Frame: 34.062199ms/f, work seconds: 0.000228s, sleep 0.033105s, sum 0.033333s
Milliseconds per Frame: 33.339798ms/f, work seconds: 0.000114s, sleep 0.033219s, sum 0.033333s
Milliseconds per Frame: 34.079201ms/f, work seconds: 0.000146s, sleep 0.033187s, sum 0.033333s
Milliseconds per Frame: 34.028900ms/f, work seconds: 0.000311s, sleep 0.033022s, sum 0.033333s
Milliseconds per Frame: 33.819199ms/f, work seconds: 0.000255s, sleep 0.033078s, sum 0.033333s
Milliseconds per Frame: 34.026203ms/f, work seconds: 0.000257s, sleep 0.033076s, sum 0.033333s
Milliseconds per Frame: 33.703201ms/f, work seconds: 0.000215s, sleep 0.033118s, sum 0.033333s
Milliseconds per Frame: 33.581997ms/f, work seconds: 0.000229s, sleep 0.033104s, sum 0.033333s
Milliseconds per Frame: 33.659000ms/f, work seconds: 0.000214s, sleep 0.033120s, sum 0.033333s
Milliseconds per Frame: 33.435600ms/f, work seconds: 0.000237s, sleep 0.033096s, sum 0.033333s
Milliseconds per Frame: 33.768799ms/f, work seconds: 0.000220s, sleep 0.033114s, sum 0.033333s
Milliseconds per Frame: 33.410198ms/f, work seconds: 0.000095s, sleep 0.033238s, sum 0.033333s
Milliseconds per Frame: 33.333397ms/f, work seconds: 0.000071s, sleep 0.033262s, sum 0.033333s
Milliseconds per Frame: 33.650002ms/f, work seconds: 0.000155s, sleep 0.033179s, sum 0.033333s
Milliseconds per Frame: 33.786400ms/f, work seconds: 0.000078s, sleep 0.033255s, sum 0.033333s
Milliseconds per Frame: 33.975998ms/f, work seconds: 0.000143s, sleep 0.033190s, sum 0.033333s
Milliseconds per Frame: 33.333397ms/f, work seconds: 0.000057s, sleep 0.033276s, sum 0.033333s
Milliseconds per Frame: 33.571800ms/f, work seconds: 0.000110s, sleep 0.033224s, sum 0.033333s
Milliseconds per Frame: 34.081802ms/f, work seconds: 0.000114s, sleep 0.033219s, sum 0.033333s
Milliseconds per Frame: 33.333397ms/f, work seconds: 0.000185s, sleep 0.033148s, sum 0.033333s
Milliseconds per Frame: 33.910301ms/f, work seconds: 0.000294s, sleep 0.033039s, sum 0.033333s
Milliseconds per Frame: 33.775898ms/f, work seconds: 0.000171s, sleep 0.033162s, sum 0.033333s
Milliseconds per Frame: 33.340000ms/f, work seconds: 0.000388s, sleep 0.032946s, sum 0.033333s
Milliseconds per Frame: 33.353100ms/f, work seconds: 0.000242s, sleep 0.033092s, sum 0.033333s
Milliseconds per Frame: 33.387798ms/f, work seconds: 0.000225s, sleep 0.033108s, sum 0.033333s
Milliseconds per Frame: 33.971600ms/f, work seconds: 0.000137s, sleep 0.033196s, sum 0.033333s
Milliseconds per Frame: 34.082600ms/f, work seconds: 0.000138s, sleep 0.033196s, sum 0.033333s
Milliseconds per Frame: 33.896500ms/f, work seconds: 0.000139s, sleep 0.033194s, sum 0.033333s
Milliseconds per Frame: 34.114902ms/f, work seconds: 0.000132s, sleep 0.033201s, sum 0.033333s
Milliseconds per Frame: 33.951202ms/f, work seconds: 0.000186s, sleep 0.033147s, sum 0.033333s
Milliseconds per Frame: 33.333397ms/f, work seconds: 0.000362s, sleep 0.032971s, sum 0.033333s
Milliseconds per Frame: 33.848999ms/f, work seconds: 0.000261s, sleep 0.033072s, sum 0.033333s
Milliseconds per Frame: 33.383999ms/f, work seconds: 0.000091s, sleep 0.033242s, sum 0.033333s
Milliseconds per Frame: 33.477200ms/f, work seconds: 0.000244s, sleep 0.033089s, sum 0.033333s
Milliseconds per Frame: 33.819798ms/f, work seconds: 0.000188s, sleep 0.033146s, sum 0.033333s
Milliseconds per Frame: 34.158901ms/f, work seconds: 0.000158s, sleep 0.033175s, sum 0.033333s
Milliseconds per Frame: 33.386902ms/f, work seconds: 0.000183s, sleep 0.033150s, sum 0.033333s
Milliseconds per Frame: 33.463398ms/f, work seconds: 0.000180s, sleep 0.033154s, sum 0.033333s
Milliseconds per Frame: 33.333397ms/f, work seconds: 0.000198s, sleep 0.033135s, sum 0.033333s
Milliseconds per Frame: 33.338497ms/f, work seconds: 0.000185s, sleep 0.033148s, sum 0.033333s
Milliseconds per Frame: 33.333397ms/f, work seconds: 0.000370s, sleep 0.032963s, sum 0.033333s
[5/15/2020 7:51:31 AM] Process exited with exit code 3221225786



Do you see any obvious issue?

 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
#include <stdint.h>
#include <windows.h>
#include <stdio.h>

typedef uint32_t bool32;
typedef float real32;

static int64_t GlobalPerfCountFrequency;

inline real32
Win32GetSecondsElapsed(LARGE_INTEGER Start, LARGE_INTEGER End)
{
    return ((real32)(End.QuadPart - Start.QuadPart) /
            (real32)GlobalPerfCountFrequency);
}

inline LARGE_INTEGER
Win32GetWallClock(void)
{
    LARGE_INTEGER EndCounter;
    QueryPerformanceCounter(&EndCounter);
    return EndCounter;
}

int main()
{
    LARGE_INTEGER PerfCountFrequencyResult;
    QueryPerformanceFrequency(&PerfCountFrequencyResult);
    GlobalPerfCountFrequency = PerfCountFrequencyResult.QuadPart;

    UINT DesiredSchedulerMS = 1;
    bool32 SleepIsGranular = (timeBeginPeriod(DesiredSchedulerMS) == TIMERR_NOERROR);

#define MonitorRefreshHz 60
#define GameUpdateHz (MonitorRefreshHz/2)
    real32 TargetSecondsPerFrame = 1.0f / (real32)GameUpdateHz;

    LARGE_INTEGER LastCounter = Win32GetWallClock();

    while (1)
    {
        LARGE_INTEGER WorkCounter = Win32GetWallClock();
        real32 WorkSecondsElapsed = Win32GetSecondsElapsed(LastCounter, WorkCounter);

        real32 SecondsElapsedForFrame = WorkSecondsElapsed;
        real32 SleepSeconds = 0;
        if(SecondsElapsedForFrame < TargetSecondsPerFrame)
        {
            if(SleepIsGranular)
            {
                SleepSeconds = (TargetSecondsPerFrame - SecondsElapsedForFrame);
                if(SleepSeconds > 0)
                {
                    Sleep((DWORD)(1000.0f * SleepSeconds));
                }
            }
            else {
                *(int*)0 = 0;
            }
            while(SecondsElapsedForFrame < TargetSecondsPerFrame)
            {
                SecondsElapsedForFrame = Win32GetSecondsElapsed(LastCounter, Win32GetWallClock());
            }
        }
        else
        {
            // Missed framerate
        }

        LARGE_INTEGER EndCounter = Win32GetWallClock();
        real32 MSPerFrame = 1000.0f * Win32GetSecondsElapsed(LastCounter, EndCounter);
        LastCounter = EndCounter;

        char DebugBuffer[256];
        _snprintf_s(DebugBuffer, sizeof(DebugBuffer),
                    "Milliseconds per Frame: %fms/f, work seconds: %fs, sleep %fs, sum %fs\n",
                    MSPerFrame, WorkSecondsElapsed, SleepSeconds, WorkSecondsElapsed + SleepSeconds);
        OutputDebugString(DebugBuffer);
    }
    return(0);
}


Here is the build command:

1
2
3
4
set CommonCompilerFlags=-MT -nologo -Gm- -GR- -EHa- -Oi -WX -W4 -wd4201 -wd4100 -wd4189 -FC -Z7 /INCREMENTAL:NO /DEBUG:FULL
set CommonLinkerFlags=-opt:ref user32.lib Winmm.lib

cl %CommonCompilerFlags% main.cpp /link %CommonLinkerFlags%

Edited by ppbitb on Reason: Initial post
I've had issues with sleep not being quite accurate as well on my system. I think Casey offered some explanation on this in a few streams. I wouldn't put too much effort or thoughts into it.
Ah, thanks a lot for the pointer, it probably saved me a lot of time.