![]() |
|
High-performance timers |
Goalie Ca
Member #2,579
July 2002
![]() |
I've attached a simple windows/nix header file which uses native OS periodic timers. The windows timer is set to 1ms accuracy and the *nix one uses posix real-time extensions. Lower accuracy = lower cpu usage on windows. They both use the semaphore mechanism to wake other threads up and go to sleep. No rest() needed. this provides example usage. It is ugly and slow and will use a lot of cpu (3% on nix, 5% on windows) because of the software drawing to screen. Hardware accelerated / opengl will fare a lot better. Without the drawing code both use virtually no CPU. timer_init(milliseconds); *nix version linked to librt, windows version linked to winmm.lib Comments/feedback etc????/
------------- |
bamccaig
Member #7,536
July 2006
![]() |
Sounds great. I'm too exhausted to really look at it. I will say that it looks like the Windows code is tied to Allegro which seems unnecessary since AFAIK it doesn't actually use Allegro for anything... -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Goalie Ca
Member #2,579
July 2002
![]() |
Right now the allegro.h include is used to determine if it is windows or not. Also I include winalleg.h. True that nothing else specific to allegro resides in there. It was a quick hack but i'll come up with a better solution soon. ------------- |
GullRaDriel
Member #3,861
September 2003
![]() |
Depending of the type of program who use your timer code, CPU can be wasted as it never was, because: msdn said: This function affects a global Windows setting. Windows uses the lowest value (that is, highest resolution) requested by any process. Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. High resolutions can also prevent the CPU power management system from entering power-saving modes. Setting a higher resolution does not improve the accuracy of the high-resolution performance counter. This was discussed some times ago. I linked a website in this topic who was about various high precision timer. But heh, until your program manage a ton of thread, this should have a little impact. All that shit to say: imho, it seems that you have done the best for the Windows part. "Code is like shit - it only smells if it is not yours" |
bamccaig
Member #7,536
July 2006
![]() |
/offtopic Goalie Ca said: if(timer_init(100)) This way of coding seems odd to me. I'm used to using booleans to indicate success or failure and that statement seems to be saying if timer_init() is successful... Whenever I use C-like routines that work like this I explicitly compare against 0 to indicate that success should return 0 and that the routine doesn't return a boolean value. if(timer_init(100) != 0) { set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); allegro_message("Failed to initialize timer"); //todo: fetch errno on linux, error on windows. make a macro/function return -1; } I guess I'm too new school. Returning zero on success seems unorthodox. It makes sense that only one value is needed for success and multiple values can give a better description of an error, but the logic of saying if routine() then an error occurred doesn't really make sense in the same realm as boolean logic. Hehe, /evilthought: /sorry-for-hijacking :-X -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
gnolam
Member #2,030
March 2002
![]() |
Quote: I guess I'm too new school. Returning zero on success seems unorthodox.
Quote:
int main(int argc, char* argv[]) { ... return(0); }
-- |
bamccaig
Member #7,536
July 2006
![]() |
I said: if(timer_init(100) != 0)
if [ "$?" -ne "0" ]; then -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Goalie Ca
Member #2,579
July 2002
![]() |
Quote: Depending of the type of program who use your timer code, CPU can be wasted as it never was, because: ... All that shit to say: imho, it seems that you have done the best for the Windows part. Well.. I was thinking about setting the default to 5ms. It is all put in a #define so anyone can change it. 1ms shouldn't tax a modern machine too much. This seemed to be the cleanest way to get high-resolution and multi-core support. AFAIK, it never clearly explains the details, context switches occur more often. I suppose that it shrinks the timeslices, does more pre-empting, etc. Quote: This way of coding seems odd to me. That style is used everywhere. It is comfortable and natural in systems level programming. I suppose that it makes more sense if you read the c-code as a portable assembly. psh 100 jsr timer_init bne error ; next line of code....
Or maybe in plain english: ------------- |
Evert
Member #794
November 2000
![]() |
On a tangent, have you looked into Allegro 5's timers (the 4.9 SVN branch), just to see if there's anything in there that needs improvement? |
BAF
Member #2,981
December 2002
![]() |
Quote: I guess I'm too new school. Returning zero on success seems unorthodox. It makes sense that only one value is needed for success and multiple values can give a better description of an error, but the logic of saying if routine() then an error occurred doesn't really make sense in the same realm as boolean logic.
Returning a value to state success/nonsuccess on something required like that is unorthodox. If you really did OOP, you would use exceptions. |
Goalie Ca
Member #2,579
July 2002
![]() |
Quote: On a tangent, have you looked into Allegro 5's timers (the 4.9 SVN branch), just to see if there's anything in there that needs improvement? I'll look into it in detail when i get time. Allegro5 appears to use a new timer API (not like i ever looked at the old one anyways). Actually i'm quite interested in getting a public threading/concurrency interface in there. On quick inspection i see a lot of internal stuff already there. ------------- |
Thomas Fjellstrom
Member #476
June 2000
![]() |
Quote: On quick inspection i see a lot of internal stuff already there. One or two of the main devs have something (I'm not sure what it is) against including a public thread api. Though allegro has an internal api that it itself uses. -- |
Peter Wang
Member #23
April 2000
|
The new API timer implementations were based pretty closely on the old timer implementations, so if you have a problem with the old ones.... But, the new API should accomodate different implementations much better than the old one, so definitely submit patches if you can. I'm particularly interested in implementations that make use of the various high precision timer facilities in Linux.
|
Goalie Ca
Member #2,579
July 2002
![]() |
If i understand the code correctly (quick review). 1) Timer thread is spawned So the user will supply a function to increment a ticker. Then they will spinlock() or rest() in the main loop. This whole process is really just redundant. Both windows and unix will spawn their own threads and handle all of the above automatically. The code I posted above uses these. My code supplies the callback and the delay function for the main loop. The "hack" is that i use a semaphore to put the main loop to sleep and unlock it in the timer callback. Another possibility is to eliminate those separate thread timers and create a wrapped rest function that keeps track of overflow and underflow. But.. getting the current "time" value is broken on some multiprocessor configurations. Processor affinity is key. This is described in both the windows and unix docs. Quote: One or two of the main devs have something (I'm not sure what it is) against including a public thread api. Though allegro has an internal api that it itself uses. Well.. in this day and age it would be really handy.. and it would provide excellent user testing on thread-safety in the library :-) ------------- |
|