0
\$\begingroup\$

Recently I worked on a game on Spritekit Engine. My question is not about spritekit, but generaly about game engines. When I write a loop code and run it (eg while i< 100000) my CPU usage goes to 100%, but when I run the test game there is no changes specially on CPU usage ,why is this so? (We know game engines runs in a loop that includes logic and graphic commands )

\$\endgroup\$
  • \$\begingroup\$ Usually you want to have some kind of frame limit in the loop to prevent to program from consuming 100% cpu. Like a sleep or delay function with a duration somewhere between 50 and 10 milliseconds, i.e. (1000/FPS ms). \$\endgroup\$ – zenith Mar 23 '15 at 6:48
3
\$\begingroup\$

The game engines will Sleep() or do something similar like pend on an event to not consume 100% cpu. Here is a Windows specific example that runs at a fixed frequency. On Windows XP, a Sleep(1) can take up to 2ms, so the loop takes that into account. The variables uPrev, uWait, and uRem are based on an original reading of a high speed counter, to prevent drift over time. dwLateStep is a debugging aid that is incremented every time a step has taken too long.

typedef unsigned long long UI64;        /* unsigned 64 bit int */
#define FREQ    400                     /* frequency */
DWORD    dwLateStep;                    /* late step count */
LARGE_INTEGER liPerfFreq;               /* 64 bit frequency */
LARGE_INTEGER liPerfTemp;               /* used for query */
UI64 uFreq = FREQ;                      /* process frequency */
UI64 uOrig;                             /* original tick */
UI64 uWait;                             /* tick rate / freq */
UI64 uRem = 0;                          /* tick rate % freq */
UI64 uPrev;                             /* previous tick based on original tick */
UI64 uDelta;                            /* current tick - previous */
UI64 u2ms;                              /* 2ms of ticks */
UI64 i;

    /* ... */ /* wait for some event to start thread */
    QueryPerformanceFrequency(&liPerfFreq);
    u2ms = ((UI64)(liPerfFreq.QuadPart)+499) / ((UI64)500);

    timeBeginPeriod(1);                 /* set period to 1ms */
    Sleep(128);                         /* wait for it to stabilize */

    QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
    uOrig = uPrev = liPerfTemp.QuadPart;

    for(i = 0; i < (uFreq*30); i++){
        /* update uWait and uRem based on uRem */
        uWait = ((UI64)(liPerfFreq.QuadPart) + uRem) / uFreq;
        uRem  = ((UI64)(liPerfFreq.QuadPart) + uRem) % uFreq;
        /* wait for uWait ticks */
        while(1){
            QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
            uDelta = (UI64)(liPerfTemp.QuadPart - uPrev);
            if(uDelta >= uWait)
                break;
            if((uWait - uDelta) > u2ms)
                Sleep(1);
        }
        if(uDelta >= (uWait*2))
            dwLateStep += 1;
        uPrev += uWait;
        /* fixed frequency code goes here */
        /*  along with some type of break when done */
    }

    timeEndPeriod(1);                   /* restore period */
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Ok,but i think thread sleep is not accurate.for example before this, when i programming with c# i use this command as thread.sleep(10) ,it does not wait exactly for 10 ms(i test it with time stamp). \$\endgroup\$ – Mehdi Amrollahi Mar 23 '15 at 9:50
  • \$\begingroup\$ In the case of Windows, the timeBeginPeriod(1) is supposed to set the ticker to 1000hz or 1 ms per tick, which it does on Win 7. I'm not sure about Vista. On Windows XP, the ticker is set to 1024hz, with three double delays every 125 ms (128 ticks = 125 ms), on the 42nd, 84th, and 125th "pseudo tick", so a Sleep(1) could take almost 2ms if it occurs on a double delay boundary. In the example code above, the Sleep(1) doesn't need to be accurate, it just needs to take less than 2ms. The peformance counter runs at 3+ mhz (Win 7) or at cpu clock speed (3.4ghz on my 3.4ghz cpu). \$\endgroup\$ – rcgldr Mar 23 '15 at 11:10
  • \$\begingroup\$ Beware of trusting anything less than 10ms per tick. In my experience, most data structures allow you to have ridiculously small values, but that's a reflection of standard data structures, not platform capability. Also, most are fast best-effort platforms (in contrast to real-time). Any timing is not guaranteed though fast is often good enough, especially today. \$\endgroup\$ – Taylor Kidd Mar 23 '15 at 17:10
  • \$\begingroup\$ i also find this link helpful : gameprogrammingpatterns.com/game-loop.html \$\endgroup\$ – Mehdi Amrollahi Mar 23 '15 at 17:49
  • \$\begingroup\$ @TaylorKidd - In the case of WIndows, timeGetDevCaps() can be used to check if timeBeginPeriod(1) actually results in a 1ms ticker. \$\endgroup\$ – rcgldr Mar 23 '15 at 20:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.