my game uses 90% CPU how to prevent it?
| 1 | int main(){ |
| 2 | |
| 3 | FInitializeGame(); //game initialization |
| 4 | |
| 5 | TPanama_Joe * joe; |
| 6 | joe = new TPanama_Joe(224,248,0,typejoe); |
| 7 | TBoard gameboard(joe->get_board_id()); |
| 8 | bool game_start=true; |
| 9 | unsigned int intro_counter=0; |
| 10 | |
| 11 | gameboard.Load_intro(); |
| 12 | |
| 13 | while (!key[KEY_ESC]) |
| 14 | { |
| 15 | clear(buffer); |
| 16 | while (main_counter>0){ |
| 17 | |
| 18 | if(game_start==true){ |
| 19 | |
| 20 | gameboard.gamelevel=0; |
| 21 | if(key[KEY_1]) gameboard.gamelevel=1; |
| 22 | else |
| 23 | if(key[KEY_2]) gameboard.gamelevel=2; |
| 24 | else |
| 25 | if(key[KEY_3]) gameboard.gamelevel=3; |
| 26 | else |
| 27 | if(key[KEY_4]) gameboard.gamelevel=4; |
| 28 | |
| 29 | if (gameboard.gamelevel!=0) { |
| 30 | game_start=false; |
| 31 | joe->joeloadpos_disc(gameboard.gamelevel); |
| 32 | joe->joesavepos(); |
| 33 | gameboard.Load_(joe); |
| 34 | |
| 35 | } |
| 36 | |
| 37 | intro_counter++; |
| 38 | if(intro_counter>60) intro_counter=0; |
| 39 | |
| 40 | }else |
| 41 | if(joe->joemove(gameboard.CLlist)==true){ |
| 42 | gameboard.Load_(joe); |
| 43 | joe->joesavepos(); |
| 44 | } |
| 45 | |
| 46 | gameboard.CLlist.moveobject(typeskull); |
| 47 | gameboard.CLlist.moveobject(typeskull_x2); |
| 48 | gameboard.CLlist.moveobject(typejumpinskull); |
| 49 | gameboard.CLlist.moveobject(typejumpinskull_x2); |
| 50 | gameboard.CLlist.moveobject(typespider); |
| 51 | gameboard.CLlist.moveobject(typespider_x2); |
| 52 | gameboard.CLlist.moveobject(typesnakeR); |
| 53 | gameboard.CLlist.moveobject(typesnakeL); |
| 54 | |
| 55 | if (key[KEY_F5]){ |
| 56 | FCreateBoard(); |
| 57 | if((joe->itemsCTR.searchitem(typetorch))==true) |
| 58 | gameboard.objects_visible=true; |
| 59 | gameboard.display_objects(gameboard.objects_visible); |
| 60 | gameboard.change_board_color(); |
| 61 | } |
| 62 | |
| 63 | if (key[KEY_F12] || joe->joegameover==true){ |
| 64 | |
| 65 | delete joe; |
| 66 | joe = new TPanama_Joe(224,248,0,typejoe); |
| 67 | game_start=true; |
| 68 | gameboard.Load_intro(); |
| 69 | |
| 70 | } |
| 71 | |
| 72 | |
| 73 | TPanama_Joe::animupdate(); |
| 74 | TScroller::animupdate(); |
| 75 | TFlames::animupdate(); |
| 76 | TBridge::animupdate(); |
| 77 | TSpider::animupdate(); |
| 78 | TLaser::animupdate(); |
| 79 | TTorch::animupdate(); |
| 80 | main_counter--; |
| 81 | |
| 82 | } |
| 83 | |
| 84 | |
| 85 | joe->itemsCTR.draw(); |
| 86 | gameboard.draw(); |
| 87 | joe->draw(); |
| 88 | |
| 89 | if(game_start==true){ |
| 90 | |
| 91 | draw_sprite(buffer,(BITMAP*)data[logo].dat,165,85); |
| 92 | draw_sprite(buffer,(BITMAP*)data[logobottom].dat,0,400); |
| 93 | if(intro_counter>30){ |
| 94 | writetext("PRESS 1,2,3 or 4 TO",250,240); |
| 95 | writetext("START GAME",285,255); |
| 96 | } |
| 97 | |
| 98 | } |
| 99 | |
| 100 | |
| 101 | |
| 102 | acquire_screen(); |
| 103 | blit(buffer,screen,0,0,0,0,640,480); |
| 104 | release_screen(); |
| 105 | |
| 106 | } |
| 107 | |
| 108 | delete joe; |
| 109 | FQuitGame(); //Quit game |
| 110 | |
| 111 | } |
| 112 | END_OF_MAIN(); |
First of all, use the [CODE][/CODE] tags (only in non-caps)
Secondly, for your program to be able to take less than maximum CPU, it needs to use rest(1) or somesuch function.
Long answer:
You game will naturally try to take as much CPU time as possible. This isn't exactly a problem, because the more CPU usage, the faster your game runs, and the more you can do in a second. However, if you do want to reduce it, use the aforementioned rest() function. Use rest(0) to yield all the extra time back to the operating system.
Call it at the end of your game loop [after logic and drawing sequences.]
while(!game_over) { game_logic.update(); game_logic.draw_buffer(); rest(0); }
Something like...
| 1 | int main() |
| 2 | { |
| 3 | Init(); |
| 4 | |
| 5 | while( !quit ) |
| 6 | { |
| 7 | if (key[KEY_ESC]) { |
| 8 | quit=true; } |
| 9 | |
| 10 | while(speed_counter) |
| 11 | { // logic "step" |
| 12 | |
| 13 | |
| 14 | --speed_counter; |
| 15 | yield_timeslice(); |
| 16 | } |
| 17 | |
| 18 | // redraw |
| 19 | ScreenSystem->draw_flip(); |
| 20 | fps++; |
| 21 | yield_timeslice(); |
| 22 | rest(1); |
| 23 | } |
| 24 | |
| 25 | return 0; |
| 26 | } |
| 27 | END_OF_MAIN(); |
should work pretty well. Using the yield_timeslice() function will mean your program will yield it's processor usage if some other program needs it more, otherwise it will still use 100%. This means that your program might look like it's using 100% of the processor, but in reality most of it is going to waste unless it's actually needed. The rest(1) part will actually make the program appear to use less CPU.
Using the yield_timeslice() function will mean your program will yield it's processor usage if some other program needs it more, otherwise it will still use 100%.
Recently yield_timeslice was changed to rest(1), so it will cause 0% CPU usage.
Hmm, didn't know that. When did this happen? Is this in the stable 4.2.0?
Recently yield_timeslice was changed to rest(1), so it will cause 0% CPU usage.
rest(1) is not yielding, its sleeping. When did someone decide to redefine the meanings of words.
rest(0) does the same thing as yield_timeslice, which does not save the CPU (it'll come right back to your program when nothing else wants it). Using rest(1) is what you want, but you only want to call it when you're not falling behind.
while(playing) { while(counter <= 0) rest(1); while(counter > 0) { do_logic(); --counter; } draw(); }
I thought we had a big discussion and it was decided that: yes, yield_timeslice is by semantics rest(0), but everyone actually wants rest(1), so it was changed...
/* sys_directx_yield_timeslice: * Yields remaining timeslice portion to the system. */ static void sys_directx_yield_timeslice(void) { Sleep(0); }
I believe at one point during the WIPs, it was changed to Sleep(1). Yielding is not the same as resting for 1 msec and it's a good thing that it is still Sleep(0).
However, if you look back at news, you'll see "Deprecated yield_timeslice in favour of rest(0)." I don't remember why; maybe it had to do with differences in cross platform behaviour. But whatever, I think yield_timeslice makes a lot more sense then manually calling rest(0). If it was truly deprecated just because people wanted 0% CPU usage, that's stupid. Yield is yield. It's not rest.
Recently yield_timeslice was changed to rest(1), so it will cause 0% CPU usage.
Did not!
yield_timeslice was declared deprecated, and it's implemented the same as rest(0), i.e. it won't reduce CPU usage, but just relinquish the processor.
I don`t know pretty much about writing games, so whould someone explain to me what would rest(0) do? It would rest 0 miliseconds so... I guess, that since is rests even for 0 time, then the program would give back the processor to other processes. So it`s like forcing the game to give the prcessor time to other applications without acutally slowing down the game. Is that correct?
An in what context is 'yield' used here? I get a bit confused, it seems that I don`t know all the meanings of this word.
On Unixes, rest(0) is implemented as sched_yield. It will give back the processor to other processes, but it will also "slow down" your game because it will resume after more than 0 ms. It depends on the mood of other processes. However, yielding will be forced by OS every now and then. On linux 2.6.x it depends of kernel config CONFIG_HZ.
This isn't exactly a problem, because the more CPU usage, the faster your game runs, and the more you can do in a second.
This is a problem. If you don't put the CPU to sleep when it could be sleeping then you require that the processor be run constantly at it's highest frequency. All laptops and many well designed desktops cut power to the CPU when it is sleeping a lot, e.g. by reducing the clock speed. Once the power is cut heat output decreases and often fans can be slowed down or switched off, reducing noise output. If your program uses 100% CPU just because it can then it will probably not stay on those machines for long.
Here is how I achieve non-100% CPU usage with Allegro (in this example, limiting to 70 fps):
| 1 | volatile int scupdate=0; |
| 2 | void update280() |
| 3 | { |
| 4 | scupdate++; |
| 5 | } |
| 6 | END_OF_FUNCTION(update280); |
| 7 | |
| 8 | ... |
| 9 | { |
| 10 | /* at startup */ |
| 11 | LOCK_FUNCTION(update280); |
| 12 | LOCK_VARIABLE(scupdate); |
| 13 | install_int_ex(update280,BPS_TO_TIMER(280)); |
| 14 | |
| 15 | |
| 16 | /* in game loop */ |
| 17 | skipframe = false; |
| 18 | if(scupdate < 4) |
| 19 | { |
| 20 | rest(((4-scupdate)*1000)/280); |
| 21 | scupdate -= 4; |
| 22 | } |
| 23 | else |
| 24 | { |
| 25 | if(scupdate > 4) |
| 26 | { |
| 27 | framecount++; |
| 28 | if(framecount&7) skipframe = true; |
| 29 | } |
| 30 | if(scupdate > 7) scupdate = 0; else scupdate -= 4; |
| 31 | } |
| 32 | } |
EDIT: code fixed.
I don`t know pretty much about writing games, so whould someone explain to me what would rest(0) do? It would rest 0 miliseconds so... I guess, that since is rests even for 0 time, then the program would give back the processor to other processes. So it`s like forcing the game to give the prcessor time to other applications without acutally slowing down the game. Is that correct? An in what context is 'yield' used here? I get a bit confused, it seems that I don`t know all the meanings of this word.
Tomek -
rest() in allegro, which is also sleep() on unices and Sleep() on Windows, tells the operating system to put the process to sleep for the specified number of milliseconds.
The concept of "sleep" is threading/operating system speak that means, in plain English, "Hey, operating system - I'm done for now. Let other programs have the CPU, and don't bother me again for X milliseconds."
The concept of "yield" is threading/operating system speak that means, in plain English, "Hey, operating system - I can stop what I'm doing right now so you can let other programs do stuff they need to do. BUT, if noone else has any work to do, then please let me know so I can keep going"
That's what rest(0) or the windows Sleep(0) do. They tell the o/s to give the CPU to others, but if noone else wants/needs it, let your process have it back.
That's why rest(0) won't accomplish what you're going for. The CPU will still stay at 100% because your program is still working fulltime - it's just "playing nice" with everyone else.
If you actually rest(1), you are telling the operating system to not even let you have the CPU until at least 1ms has passed. Therefore, the CPU usage WILL actually drop. With today's CPU speeds, 1 millisecond is an eternity. If every millisecond you wake up, do a few hundred thousand instructions, then go back to sleep, you're barely using the CPU.
I hope that helps you understand the terminology better!
On a related note, as someone pointed out already, some desktops and many/most laptops the system crank up the fans when the CPU is at full usage for a long time. Other power-management side-effects can also occur. This is why going full throttle is bad form unless you actually have to. I have a P4 3.0ghz in a laptop that is very quiet when at rest, but when something is using 100% cpu the thing SCREAMS. I play hard core 3d games on my laptop and expect them to be using full resources all the time - I wear headphones. But other games that are poorly designed don't last long on my computer. I once ran across a KICK ASS solitaire suite that I loved, but it used 100% CPU. I'm sorry, there's no way you actually need 3 billion instruction cycles a second for me to play free cell.
The best way would be using thread wake-up events, based on a timer. In short, you set up a timer to wake your main thread at regular intervals (with each timer click). After you are done drawing a frame and updating logic, make the main thread sleep until signalled again. It will use 0% cpu until the timer ticks again, but will continue if it already has.
Unfortunately, allegro doesn't have a mechanism to support this, so you'll have to use platform-specific api to do this.
In windows, one would have 2 threads, a main thread and a timer thread. The timer thread increments the counter and activates an event (thereby waking up the main thread if necessary). The main thread updates logic, draws, sleeps until timer event, and repeats.
If you don't want to multi-thread, use the rest() approach.
What's the difference between your approach and this?
Because that doesn't rest at all
. But seriously..
while(timer <= 0) rest(1);
causes the thread to rest anywhere between 1ms and 10ms per call, which isn't very accurate, and it cuases the program to rest-check-rest-check-etc (which takes some, if negligible, CPU time) until its ready, instead of just staying down and letting the OS wake the thread up on time.
How do you implement this timer thread?
1. Write a thread function for the timer thread, which sleeps for the desired amount of time, then sets an event.
2. Spawn a thread from your main thread.
3. Use a waiting function in the main thread to suspend until the timer event is signalled.
For more details:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createevent.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/setevent.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/waitforsingleobject.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp
These should get you started.
Hello, Windows-only only land. Nice to see you.
Yay, hello there. Haven't done any multithread programming on other platform, so I guess someone else should do the appropriate googling.
Pthread is cross platfrom.
But it is also a pain in the ass to build and use on non-*n?x platforms, or at least so I've heard.
I never have problems building themon solaris, linux (debian) , windows xp ( pthread pack from source.redhat.org )
I've been using Boost::threads for months now. I THINK they use pthreads on Unix but native on Windows (correct me if I'm wrong, too lazy to go check)
but, regardless, it works great and easy, on either platform.
1. Write a thread function for the timer thread, which sleeps for the desired amount of time, then sets an event.
Something like this?
while (true) { Sleep(20); //0.02 sec, 50 fps SetEvent(handle); };
Is this more accurate than using allegro timer?
Is this more accurate than using allegro timer?
POSSIBLY/probably, but no guarantees. The allegro timers go for a 5ms resolution. Your snippet theoretically goes for 2ms resolution but, in reality, the documentation for all Sleep() style functions will say something like -
Sleep( int ms ) - Puts the process to sleep for AT LEAST ms milliseconds
Under a light load, you're likely to get pretty good results but there's no guarantee you will wake up right at 2ms everytime. Also, I wasn't following the ENTIRE event queue discussion, but asynchronous event delivery is also not usually guaranteed to work instantly.
Is this more accurate than using allegro timer?
No. In fact, that could lead to time drifting. It takes a variable amount of time to call those functions and do whatever they're gonna do. You'd have to find a way to make the OS put the thread to sleep and wake it up at specific intervals.
What you can try to do, is calculate the amount of time you need to sleep until the next tic should fire (using QPC/gettimeofday to track the current time vs. the next target time), sleep for that amount (via Sleep/usleep), wake up and do whatever, then repeat. This is basically what Allegro does for timers (though some jitter is introduced since all the timer functions run in the same thread/loop).
int ms_to_sleep_for = one_second / tics_per_second; unsigned int current_time = get_time(); while(running) { signed int diff = current_time - get_time(); if(diff > 0) Sleep(diff); do_something(); current_time += ms_to_sleep_for; }
pthreads works fine on windows... I use it myself.
What you can try to do, is calculate the amount of time you need to sleep until the next tic should fire (using QPC/gettimeofday to track the current time vs. the next target time)
Of course this is exactly the same solution as the code I gave (guess I found the thread sooner!), it just doesn't devolve time counting to an Allegro timer. So I guess follow on questions are whether your use of Sleep rather than rest is a non-platform neutral oversight and whether anybody has a useful table of which high precision time functions are available on which OSs?
So I guess follow on questions are whether your use of Sleep rather than rest is a non-platform neutral oversight and whether anybody has a useful table of which high precision time functions are available on which OSs?
Oversight, yes. I was going for psuedo-code and would've used sleep(), but that a real libc function.
As for high precision time functions, sane OSs have gettimeofday, Windows has QueryPerformanceFrequency/QueryPerformanceCounter. If neither of those exist/work, the system isn't worth worrying about.
I think it would be nice to have threads in Allegro. If I haven't misunderstood the universe, you need threads to fully enjoy the powers of dual core processors. And they are the future.
I've picked up a timing method that I like very much, using Allegro timers:
| 1 | #include <semaphore.h> |
| 2 | |
| 3 | sem_t ticks; |
| 4 | void inc_timer() |
| 5 | { |
| 6 | sem_post(&ticks); |
| 7 | } |
| 8 | |
| 9 | main() |
| 10 | { |
| 11 | sem_init(&ticks, 0, 0); |
| 12 | |
| 13 | install_int_ex(inc_timer, BPS_TO_TIMER(30)); |
| 14 | |
| 15 | while(1) |
| 16 | { |
| 17 | if(redraw) |
| 18 | { |
| 19 | // Drawing |
| 20 | blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); |
| 21 | redraw = false; |
| 22 | } |
| 23 | |
| 24 | sem_wait(&ticks); |
| 25 | |
| 26 | // Logic |
| 27 | redraw = true; |
| 28 | } |
| 29 | |
| 30 | remove_int(inc_timer); |
| 31 | sem_destroy(&ticks); |
| 32 | } |
The sem_wait causes the application to sleep for at least the right amount of time, but if it misses several ticks it simply won't sleep.