cpu fps etc...
karistouf

hi again.
ok, this is surely once again THE CLASSICAL QUESTIOn about CPU weight and allegro and blablablabla.

I begin without the app:
{"name":"state0.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/0\/5076464c4a2ed765dbb2a2fdd59a9e3a.jpg","w":511,"h":500,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/0\/5076464c4a2ed765dbb2a2fdd59a9e3a"}state0.jpg

The old version, without any rest(1) nor timer function:
{"name":"schwz3_state.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/3\/83af845627c7ee305ada2bea96a85b09.jpg","w":992,"h":468,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/3\/83af845627c7ee305ada2bea96a85b09"}schwz3_state.jpg

I have put in my main loop a rest of 1 sec, and putted in volatile funct activated by the timer all my printing to screen.
Notice here that I have only a poor bmp of 32k and less for mouse cursor...

Modification to the program with a rest and timer function, FPS 100:
{"name":"fps100.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/5\/45dac6f09ba88ffcdcb54dd614e4603a.jpg","w":962,"h":435,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/5\/45dac6f09ba88ffcdcb54dd614e4603a"}fps100.jpg

FPS 50:
{"name":"fps50.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/d\/ad05f6a1c21056bbebca180a3c788b4b.jpg","w":955,"h":447,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/d\/ad05f6a1c21056bbebca180a3c788b4b"}fps50.jpg

Here is part of the code, I do not arrive to do less to not charge the CPU. Any idea ?

:-[

1////////////////////////////////////////////////////////////////////////////////
2 
3volatile long screen_unit=0;
4void screen_printing(void)
5{
6screen_unit++;
7
8//... mes functions d affichage
9 rectfill(buffer,0,0,440,400,makecol(255,255,255));
10 textprintf_ex(buffer,font, 105,20,makecol(255,0,0),-1,AppliName);//affichage nom appi
11 draw_sprite(buffer,fond1,(int)-5,0);
12
13 if (index_view_graph==1)
14 { rectfill(buffer, 320,350,330,360,makecol(255,0,0));
15 view_midi_visual();
16 }
17
18 if (index_view_midiapps==1)
19 { rectfill(buffer, 150,350,160,360,makecol(255,0,0));
20 listOfAppl();
21 }
22
23
24 if ( index_write_deb==1){
25 rectfill(buffer, 415, 370,425, 380,makecol(255,0,0));
26 }
27
28
29 show_connected_to_midishare();
30 textprintf_ex(buffer,font, 10,200,makecol(255,0,0),-1,"Midi INPUT: ");
31 textprintf_ex(buffer,font, 10,210,makecol(255,0,0),-1,"%s", my_midi_string);
32 
33 show_udp();
34 choices();
35 textprintf_ex(buffer,font, 10,180,makecol(255,0,0),-1,"FPS: %d ", FPS_defini);
36 draw_sprite(buffer,mouse,(int)mouse_x,mouse_y);
37 blit(buffer,screen,0,0,0,0,442,442);
38 
39}
40END_OF_FUNCTION(screen_printing)
41 
42 
43 
44////////////////////////////////////////////////////////////////////////////////
45int main()
46{
47 allegro_init();
48 install_keyboard();
49 install_mouse();
50 install_timer();
51 LOCK_FUNCTION(screen_printing);
52 LOCK_VARIABLE(screen_unit);
53
54 set_color_depth(16);
55 set_gfx_mode(GFX_AUTODETECT_WINDOWED,442,442,0,0);
56 if(set_gfx_mode(GFX_AUTODETECT_WINDOWED,440,400,0,0)!=0)
57 {
58 set_gfx_mode(GFX_TEXT,0,0,0,0);
59 allegro_message("%s\nSchwartz_Peter's Video Mode:\n 1024x768 and Higher\n16 or 32 bits better look\n\n", allegro_error);
60 quit_funct();return 1;
61 }
62 fond1=load_bitmap("chaton2.tga",NULL);
63 mouse=load_bitmap("curseur1.bmp",NULL);
64 
65 buffer=create_bitmap(SCREEN_W,SCREEN_H);
66 blit(buffer,screen,0,0,0,0,442,442);
67 
68 if(set_display_switch_mode(SWITCH_BACKGROUND))
69 {set_display_switch_mode(SWITCH_BACKAMNESIA);}
70
71
72 load_ip_conf();
73 SetUpMidi();
74 
75 initialisation_client();
76 
77 
78 while (index_quit==0)
79 {
80 rest(1);
81 
82 
83
84 install_int_ex(screen_printing,BPS_TO_TIMER(FPS_defini));
85 
86 
87 
88 }
89 
90
91quit_funct();
92 
93 
94
95return 0;
96}
97END_OF_MAIN();

GullRaDriel

umpf !!!

Chris, n'appelle install_int_ex qu'une seule fois ! et en dehors de la boucle while !

Apres quoi tu pourras boucler sur ton rest(1); tranquillement !

bamccaig

First of all you shouldn't be doing so much work in a timer function. Setting a flag or incrementing a counter and responding to it in the game loop is the preferred (and feasible) approach. I'm not sure why you repeatedly call install_int_ex, but that seems shifty as well...

gnolam

I'm surprised that doesn't outright crash, what with Allegro's notorious thread unsafety and all.

Audric

You can attempt to rest() for more than 1ms at once.
Try 5, 10, 15, 20.

edit
As for the drawing part, chances are the biggest job for the CPU is the

blit(buffer,screen,0,0,0,0,442,442);

Considering that less than 10% of the screen surface may have changed, you could just blit these parts individually, like a "dirty rectangles" system.

(Additionally, you can memorize if these screen parts HAVE changed at all. For example, the top text: No need to redraw the paragraph if it has the same content as when it was last redrawn.)

Goalie Ca
Vanneto

Are there any advantages of using semaphores over normal high-res timers?

karistouf

ooooups, i didn t know it was an error, I have an hudge programm wich is running with install_ex inside of the main loop since 4 years of dev... without any error i mean errors of timers (and its real time manipulation)...

but its still doing nothing o my troubles of CPU...
with:

     while (index_quit==0)
     {
     rest(1);
//nothing... but refreshment is done in the volatile as previous and first code

     }

CPU weight is still from 41 % and up to 70%

{"name":"outofloop.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/3\/032ede2c76a20c40b9e54221cb2392ea.jpg","w":983,"h":510,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/3\/032ede2c76a20c40b9e54221cb2392ea"}outofloop.jpg

so? I mean install_ex is there tomake use of timer in an easy manner, to avoid calculations of tclock ?

GullRaDriel

install_int* granularity can vary from 1 msec to 14-20 msec

Goalie Ca
Quote:

Are there any advantages of using semaphores over normal high-res timers?

Yay. Someone asked the RIGHT question.

Why did i use a locking semaphore? Because allegro timers spawn their own thread, wake it up, run user code (increment value), and then go back to sleep.

I used a semaphore because i wanted to put the mail loop to sleep and have the timer wake it up like it should happen. You only want your main loop to execute when the timer beeps! Allegro timer simplifies this possibility away but certain operating systems (not all) libraries can handle this without a problem.

Rest is basically a way to stop constant spin locking by taking shifts. It will tell the operating system to put the thread to sleep... but only for a really short time. It then checks again.. whenever the operating system feels like it. It may check almost right away (bad because more cpu wasted) but the general rule of thumb is that rest is only accurate to within 15ms.

To summarize: rest still wastes tons of cpu. It constantly wakes up and goes back to sleep.

With my locking mechanism i can get my own (graphically simple) allegrogl games to use < 1% cpu.

bamccaig

That's really cool Goalie Ca, but how portable is it...? :-/ Will your example work on Windows and Linux? :-/ Do you need to install third party libraries or anything?

Goalie Ca

If your OS is posix then you have it. All linux, mac, and older winnt. For new windows you need to download pthread. http://sourceware.org/pthreads-win32/
If you really wanted to you could use windows locking mechanism. It is in winapi and does the same thing.

bamccaig

I guess I will attempt to learn to use semaphores then. :D Until then, here is my revised raw timer template...

1/*
2 * Name: fps.h
3 * Author: bamccaig->members.allegro.cc
4 * Purpose: Example of using Allegro timer routines to limit frames-per-second
5 * in a game.
6 * Disclaimer: Use at own risk. :P
7 */
8#include <allegro.h>
9#include <stdio.h>
10#include <stdlib.h>
11 
12#define bool short int
13#define false 0
14#define true -1
15 
16#define SECS_PER_MIN 60
17#define MINS_PER_HOUR 60
18#define HOURS_PER_DAY 24
19#define TARGET_FPS 30
20#define WHITE makecol(255, 255, 255)
21 
22volatile bool gblnCloseButtonPressed = false; // Flag for window close (X) button status.
23volatile unsigned short int gushrFramesPerSecond = 0; // Count of frames last second (Set).
24volatile unsigned short int gushrFramesThisSecond = 0; // Count of frames this second (Increment).
25volatile unsigned int guintPendingFrames = 0; // Number of frames OK'd to be processed.
26volatile unsigned int guintTotalFrames = 0; // Total number of frames.
27 
28volatile unsigned short int gushrSeconds = 0;
29unsigned short int gushrMinutes = 0;
30unsigned short int gushrHours = 0;
31unsigned short int gushrDays = 0;
32 
33void add_frame(void); // Timer routine.
34void close_button_handler(void); // Window X button handler on supported platforms.
35void draw(BITMAP*); // Draws the scene.
36int initialize(void); // Initializes the application.
37void logic(void); // Processes gameplay.
38void tick(void); // Timer routine.
39void update_time(void); // Updates clock variables.

1/*
2 * Name: fps.c
3 * Author: bamccaig->members.allegro.cc
4 * Purpose: Example of using Allegro timer routines to limit frames-per-second
5 * in a game.
6 * Disclaimer: Use at own risk. :P
7 */
8#include "fps.h"
9 
10int main(int argc, char* argv[])
11{
12 BITMAP* bmpBuffer = NULL;
13 
14 // Try to initialize game.
15 if(initialize() != 0)
16 exit(-1);
17 
18 // Create and clear screen buffer.
19 bmpBuffer = create_bitmap(800, 600);
20 clear(bmpBuffer);
21 
22 // Main game loop.
23 while(!(key[KEY_ESC] || gblnCloseButtonPressed))
24 {
25 // Rest loop. Nothing to do until next frame so we "go to sleep" temporarily.
26 while(!guintPendingFrames)
27 rest(16);
28 
29 // Logic loop. Changes to the game happen here.
30 while(guintPendingFrames)
31 {
32 logic();
33 guintPendingFrames--;
34 }
35 
36 /*
37 * Draw. Here we draw the current frame first to a buffer in main memory and
38 * then to the video memory (screen).
39 */
40 draw(bmpBuffer);
41 }
42 
43 // Release buffer.
44 destroy_bitmap(bmpBuffer);
45 
46 return(0);
47}
48END_OF_MAIN()
49 
50 
51 
52void add_frame(void)
53/*
54 * This is a timer routine that signals the main game loop to execute the logic (and redraw).
55 * Every time it executes it increments a counter. When the counter is non-zero the main game
56 * loop will execute the logic and then decrement the counter. Logic only happens once
57 * for every execution of this timer routine. Drawing happens at most once, but perhaps less
58 * if the program starts to get behind and needs to catch up again by repeating logic.
59 */
60{
61 guintPendingFrames++;
62}
63END_OF_FUNCTION(add_frame)
64 
65 
66 
67void close_button_handler(void)
68/*
69 * Handles the X button of the window on supported platforms. Signals the main game loop
70 * to exit.
71 */
72{
73 gblnCloseButtonPressed = true;
74}
75END_OF_FUNCTION(close_button_callback)
76 
77 
78 
79void draw(BITMAP* bmpBuffer)
80/*
81 * Draws the current frame to a BITMAP buffer in main memory and then to the video memory (screen).
82 * In this example we're only drawing the total frame count and the frames-per-second count.
83 */
84{
85 // Draw to buffer.
86 textprintf_ex(bmpBuffer, font, 20, 20, WHITE, -1, "frame-count: %d", guintTotalFrames);
87 textprintf_ex(bmpBuffer, font, 20, 40, WHITE, -1, "time: %03d:%02d:%02d:%02d", gushrDays, gushrHours, gushrMinutes, gushrSeconds);
88 textprintf_ex(bmpBuffer, font, 20, 60, WHITE, -1, "fps: %d", gushrFramesPerSecond);
89 
90 // Draw to screen.
91 blit(bmpBuffer, screen, 0, 0, 0, 0, 800, 600);
92 clear(bmpBuffer);
93}
94END_OF_FUNCTION(draw)
95 
96 
97 
98int initialize(void)
99// Initializes the program.
100{
101 char* chrGLaDOS_msg = "If at first you don't succeed,...you fail";
102 
103 // Try to initialize allegro.
104 if(allegro_init() != 0)
105 {
106 printf("%s [to initialize Allegro].\n", chrGLaDOS_msg);
107 return(-1);
108 }
109 
110 // Try to install keyboard.
111 if(install_keyboard() != 0)
112 {
113 printf("%s [to install the keyboard routines].\n", chrGLaDOS_msg);
114 return(-1);
115 }
116 
117 // Try to install timer.
118 if(install_timer() != 0)
119 {
120 printf("%s [to install the timer routines].", chrGLaDOS_msg);
121 return(-1);
122 }
123 
124 // Set color depth.
125 set_color_depth(32);
126 
127 // Try to set graphic mode.
128 if(set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0) != 0)
129 {
130 printf("%s [to set the graphics mode]. %s.\n", chrGLaDOS_msg, allegro_error);
131 return(-1);
132 }
133 
134 /*
135 * Set display switch mode so the game will continue processing even if the
136 * user switches to another window.
137 */
138 if(set_display_switch_mode(SWITCH_BACKGROUND) != 0)
139 {
140 printf("%s [to set display switch mode].\n", chrGLaDOS_msg, allegro_error);
141 return(-1);
142 }
143 
144 // Lock timer variables.
145 LOCK_VARIABLE(gblnCloseButtonPressed);
146 LOCK_VARIABLE(guintPendingFrames);
147 LOCK_VARIABLE(gushrFramesPerSecond);
148 LOCK_VARIABLE(gushrFramesThisSecond);
149 LOCK_VARIABLE(gushrSeconds);
150 LOCK_VARIABLE(gushrMinutes);
151 LOCK_VARIABLE(gushrHours);
152 LOCK_VARIABLE(gushrDays);
153 
154 // Lock timer routines.
155 LOCK_FUNCTION(add_frame);
156 LOCK_FUNCTION(close_button_handler);
157 LOCK_FUNCTION(tick);
158 
159 // Install timer callbacks.
160 install_int_ex(add_frame, BPS_TO_TIMER(TARGET_FPS));
161 install_int_ex(tick, BPS_TO_TIMER(1));
162 
163 // Install close-button callback.
164 set_close_button_callback(close_button_handler);
165 
166 return(0);
167}
168END_OF_FUNCTION(initialize)
169 
170 
171 
172void logic(void)
173/*
174 * Logic. In this example we're only incrementing a total frame counter, a
175 * frames-per-second counter, and updating time variables.
176 */
177{
178 update_time();
179 
180 guintTotalFrames++;
181 gushrFramesThisSecond++;
182}
183END_OF_FUNCTION(logic)
184 
185 
186 
187void tick(void)
188/*
189 * This is another timer routine that executes [approximately] once per second.
190 * It's role is to set the frames-per-second count and reset the
191 * frames-this-second counter.
192 */
193{
194 // Update game time.
195 gushrSeconds++;
196 
197 // Update frames per second.
198 gushrFramesPerSecond = gushrFramesThisSecond;
199 gushrFramesThisSecond = 0;
200}
201END_OF_FUNCTION(tick)
202 
203 
204 
205void update_time(void)
206// Updates time variables.
207{
208 if(gushrSeconds == SECS_PER_MIN)
209 {
210 gushrMinutes++;
211 gushrSeconds = 0;
212 }
213 
214 if(gushrMinutes == MINS_PER_HOUR)
215 {
216 gushrHours++;
217 gushrMinutes = 0;
218 }
219 
220 if(gushrHours == HOURS_PER_DAY)
221 {
222 gushrDays++;
223 gushrHours = 0;
224 }
225}

To compile it the following commands should work (you must have Allegro installed).

Windows/MinGW: gcc -O2 fps.c -o fps.exe -lalleg

*nix/GCC: gcc -O2 fps.c -o fps $(allegro-config --libs)

Goalie Ca
Quote:

I guess I will attempt to learn to use semaphores then.

Simple. A semaphore is like a locking counter. I've pasted the code i wrote to the wiki and have added a few useful comments. Basically main goes to sleep, ticker wakes it up. No wasted cycles, no extra context switches, no spinlocks.

1#include <allegro.h>
2#include <semaphore.h>
3sem_t ticks; //our new "counter" variable.
4 
5 
6void ticker(){
7 sem_post(&ticks); //increases count. wakes up first waiting thread (sem_wait) if count > 0
8}END_OF_FUNCTION(ticker)
9 
10void main(){
11 setup_stuff();
12 
13 sem_init(&ticks, 0, 1); //sets a good default value to count. (count = 1)
14 LOCK_FUNCTION(ticker);
15 install_int_ex(ticker,BPS_TO_TIMER(60));
16 
17 while(game_on){
18 sem_wait(&ticks); //decreases count, goes to sleep if count < 0, wakes back up when count >= 0 (through sem_post)
19 update_stuff();
20 draw_stuff();
21 }
22}END_OF_MAIN()

karistouf

OK finally I founded why it was taking so many weight in memory:
im using

   if(set_display_switch_mode(SWITCH_BACKGROUND))
  {set_display_switch_mode(SWITCH_BACKAMNESIA);}

to enable the visual refreshing of information if I m not on its window.
... oups !

Kitty Cat
Quote:

while(game_on){
    sem_wait(&ticks); //decreases count, goes to sleep if count < 0, wakes back up when count >= 0 (through sem_post)
    update_stuff();
    draw_stuff();
}

If you want to do frameskipping, this should work:

while(game_on){
    sem_wait(&ticks);
    do {
        update_stuff();
    } while(sem_trywait(&ticks) == 0);
    draw_stuff();
}

karistouf

MAOUW its nice, but it need to run , while its not on nor selected.
So in fact putting in an install_ex routines enable not to freeze the tasks, just the screen refreshment is not done ( wich take a HUDGE place in mem)

Thomas Fjellstrom
Quote:

I'm surprised that doesn't outright crash, what with Allegro's notorious thread unsafety and all.

A lot of the crashieness was "fixed" in the last release or two. But it means theres a ton of locking and unlocking going on, slowing things down and potentially using lots of cpu. That doesn't mean you should use the same allegro resources from multiple thread (in fact you probably shouldn't), unless you're absolutely sure you know what you're doing.

bamccaig
1/*
2 * Name: fps2.h
3 * Author: bamccaig->members.allegro.cc
4 * Purpose: Example of using Allegro timer routines and semaphores to limit frames-per-second
5 * in a game and reduce wasted cycles.
6 * Disclaimer: Use at own risk. :P
7 */
8#include <allegro.h>
9#include <semaphore.h>
10#include <stdio.h>
11#include <stdlib.h>
12 
13#define bool short int
14#define false 0
15#define true -1
16 
17#define SECS_PER_MIN 60
18#define MINS_PER_HOUR 60
19#define HOURS_PER_DAY 24
20#define TARGET_FPS 30
21#define WHITE makecol(255, 255, 255)
22 
23sem_t gSemaphore;
24 
25volatile bool gblnCloseButtonPressed = false; // Flag for window close (X) button status.
26volatile unsigned short int gushrFramesPerSecond = 0; // Count of frames last second (Set).
27volatile unsigned short int gushrFramesThisSecond = 0; // Count of frames this second (Increment).
28volatile unsigned int guintTotalFrames = 0; // Total number of frames.
29 
30volatile unsigned short int gushrSeconds = 0;
31unsigned short int gushrMinutes = 0;
32unsigned short int gushrHours = 0;
33unsigned short int gushrDays = 0;
34 
35void add_frame(void); // Timer routine.
36void close_button_handler(void); // Window X button handler on supported platforms.
37void draw(BITMAP*); // Draws the scene.
38int initialize(void); // Initializes the application.
39void logic(void); // Processes gameplay.
40void tick(void); // Timer routine.
41void update_time(void); // Updates clock variables.

1/*
2 * Name: fps2.c
3 * Author: bamccaig->members.allegro.cc
4 * Purpose: Example of using Allegro timer routines and semaphores to limit frames-per-second
5 * in a game and reduce wasted cycles.
6 * Disclaimer: Use at own risk. :P
7 */
8#include "fps2.h"
9 
10int main(int argc, char* argv[])
11{
12 BITMAP* bmpBuffer = NULL;
13 
14 // Try to initialize game.
15 if(initialize() != 0)
16 exit(-1);
17 
18 // Initalize semaphore.
19 sem_init(&gSemaphore, 0, 1);
20 
21 // Create and clear screen buffer.
22 bmpBuffer = create_bitmap(800, 600);
23 clear(bmpBuffer);
24 
25 // Main game loop.
26 while(!(key[KEY_ESC] || gblnCloseButtonPressed))
27 {
28 // Sleep until next frame.
29 sem_wait(&gSemaphore);
30 
31 // Logic loop. Changes to the game happen here.
32 logic();
33 
34 /*
35 * Draw. Here we draw the current frame first to a buffer in main memory and
36 * then to the video memory (screen).
37 */
38 draw(bmpBuffer);
39 }
40 
41 // Release buffer.
42 destroy_bitmap(bmpBuffer);
43 
44 return(0);
45}
46END_OF_MAIN()
47 
48 
49 
50void add_frame(void)
51/*
52 * This is a timer routine that signals the main game loop to execute the logic (and redraw).
53 */
54{
55 // Wake up game.
56 sem_post(&gSemaphore);
57}
58END_OF_FUNCTION(add_frame)
59 
60 
61 
62void close_button_handler(void)
63/*
64 * Handles the X button of the window on supported platforms. Signals the main game loop
65 * to exit.
66 */
67{
68 gblnCloseButtonPressed = true;
69}
70END_OF_FUNCTION(close_button_callback)
71 
72 
73 
74void draw(BITMAP* bmpBuffer)
75/*
76 * Draws the current frame to a BITMAP buffer in main memory and then to the video memory (screen).
77 * In this example we're only drawing the total frame count and the frames-per-second count.
78 */
79{
80 // To buffer.
81 textprintf_ex(bmpBuffer, font, 20, 20, WHITE, -1, "frame-count: %d", guintTotalFrames);
82 textprintf_ex(bmpBuffer, font, 20, 40, WHITE, -1, "time: %03d:%02d:%02d:%02d", gushrDays, gushrHours, gushrMinutes, gushrSeconds);
83 textprintf_ex(bmpBuffer, font, 20, 60, WHITE, -1, "fps: %d", gushrFramesPerSecond);
84 
85 // To screen.
86 blit(bmpBuffer, screen, 0, 0, 0, 0, 800, 600);
87 clear(bmpBuffer);
88}
89END_OF_FUNCTION(draw)
90 
91 
92 
93int initialize(void)
94// Initializes the program.
95{
96 char* chrGLaDOS_msg = "If at first you don't succeed,...you fail";
97 
98 // Try to initialize allegro.
99 if(allegro_init() != 0)
100 {
101 printf("%s [to initialize Allegro]. %s.\n", chrGLaDOS_msg, allegro_error);
102 return(-1);
103 }
104 
105 // Try to install keyboard.
106 if(install_keyboard() != 0)
107 {
108 printf("%s [to install the keyboard routines].\n", chrGLaDOS_msg);
109 return(-1);
110 }
111 
112 // Try to install timer.
113 if(install_timer() != 0)
114 {
115 printf("%s [to install the timer routines].", chrGLaDOS_msg);
116 return(-1);
117 }
118 
119 // Set color depth.
120 set_color_depth(32);
121 
122 // Try to set graphic mode.
123 if(set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0) != 0)
124 {
125 printf("%s [to set the graphics mode]. %s.\n", chrGLaDOS_msg, allegro_error);
126 return(-1);
127 }
128 
129 /*
130 * Set display switch mode so the game will continue processing even if the
131 * user switches to another window.
132 */
133 if(set_display_switch_mode(SWITCH_BACKGROUND) != 0)
134 {
135 printf("%s [to set display switch mode].\n", chrGLaDOS_msg, allegro_error);
136 return(-1);
137 }
138 
139 // Lock timer variables.
140 LOCK_VARIABLE(gblnCloseButtonPressed);
141 LOCK_VARIABLE(guintPendingFrames);
142 LOCK_VARIABLE(gushrFramesPerSecond);
143 LOCK_VARIABLE(gushrFramesThisSecond);
144 LOCK_VARIABLE(gushrSeconds);
145 LOCK_VARIABLE(gushrMinutes);
146 LOCK_VARIABLE(gushrHours);
147 LOCK_VARIABLE(gushrDays);
148 
149 // Lock timer routines.
150 LOCK_FUNCTION(add_frame);
151 LOCK_FUNCTION(close_button_handler);
152 LOCK_FUNCTION(tick);
153 
154 // Install timer callbacks.
155 install_int_ex(add_frame, BPS_TO_TIMER(TARGET_FPS));
156 install_int_ex(tick, BPS_TO_TIMER(1));
157 
158 // Install close-button callback.
159 set_close_button_callback(close_button_handler);
160 
161 return(0);
162}
163END_OF_FUNCTION(initialize)
164 
165 
166 
167void logic(void)
168/*
169 * Logic. In this example we're only incrementing a total frame counter, a
170 * frames-per-second counter, and updating time variables.
171 */
172{
173 update_time();
174 
175 guintTotalFrames++;
176 gushrFramesThisSecond++;
177}
178END_OF_FUNCTION(logic)
179 
180 
181 
182void tick(void)
183/*
184 * This is another timer routine that executes [approximately] once per second.
185 * It's role is to set the frames-per-second count and reset the
186 * frames-this-second counter.
187 */
188{
189 // Update game time.
190 gushrSeconds++;
191 
192 // Update frames per second.
193 gushrFramesPerSecond = gushrFramesThisSecond;
194 gushrFramesThisSecond = 0;
195}
196END_OF_FUNCTION(tick)
197 
198 
199 
200void update_time(void)
201// Updates time variables.
202{
203 if(gushrSeconds == SECS_PER_MIN)
204 {
205 gushrMinutes++;
206 gushrSeconds = 0;
207 }
208 
209 if(gushrMinutes == MINS_PER_HOUR)
210 {
211 gushrHours++;
212 gushrMinutes = 0;
213 }
214 
215 if(gushrHours == HOURS_PER_DAY)
216 {
217 gushrDays++;
218 gushrHours = 0;
219 }
220}

To compile it the following commands should work (you must have Allegro [and pthreads installed - Windows users, this probably means you]).

Windows/MinGW: gcc -O2 fps2.c -o fps2.exe -lalleg -lpthreadGC2

*nix/GCC: gcc -O2 fps2.c -o fps2.exe $(allegro-config --libs) -lpthread

karistouf
Quote:

I'm surprised that doesn't outright crash, what with Allegro's notorious thread unsafety and all.

never crashed... 4 years this damn calling inside main loop... hundred of performances and theatre play without crash... ;D;D;D;D

Quote:

unless you're absolutely sure you know what you're doing.

well, or people have made studies, and better than say'until you know what you are doing' they can explain WHY and HOW ( more constructiv), or they didn t ... no ?

;D

Thomas Fjellstrom
Quote:

well, or people have made studies, and better than say'until you know what you are doing' they can explain WHY and HOW ( more constructiv), or they didn t ... no ?

I don't understand a thing you just said.

However, what i meant was, if you know the issues inherent with threading, and know what to work around them, do as you please.

bamccaig

On a side note, should a semaphore (sem_t) be volatile? :-/

Thomas Fjellstrom

No. Just ignore that keyword. It doesn't do what most people think it does.

Goalie Ca
Quote:

On a side note, should a semaphore (sem_t) be volatile?

Actually it relies on a special CPU instruction called (roughly) "test and set lock". It is an entirely atomic operation. sem_t itself is a struct.

bamccaig
Thomas Fjellstrom said:

No. Just ignore that keyword. It doesn't do what most people think it does.

Is this not what it does? :-/

Goalie Ca

He must be referring to the fact that people assume volatile is atomic. That is it reads, processes, and writes back.

I think of Volatile as the (sort of) opposite of "register". That is, this is not to be cached in a register. Write-through!!! Read too!

bamccaig

Thanks, Goalie Ca! My raw Allegro timer example uses approximately 20% CPU. The modified version implementing pthreads/semaphores is using 3-5% CPU. :D

** EDIT **

I may have spoken too soon. The 20% CPU usage was seen on another system. My home system is actually using a very similar amount of CPU with raw Allegro timers... :-/

Thomas Fjellstrom
Goalie Ca
Quote:

I may have spoken too soon. The 20% CPU usage was seen on another system. My home system is actually using a very similar amount of CPU with raw Allegro timers... :-/

rest() will vary from system to system. It is dependant on the operating system scheduler. It may even vary from session to session. Might vary if you run it in win2k instead of vista.

I also wonder about pthread performance on windows. Windows does not have native posix threading. Windows threads will have to be "Wrapped" in order to have the necessary behaviour.

I can take my code and run it on a junker linux system and it will use < 1%.

Kitty Cat

BTW, is there a way to do this without relying on an Allegro timer? It's just that if you're trying to move away from a while(waiting) rest(1); loop, that's basically what Allegro's timers do. Though the timer thread does attempt to use precise resting, and calculating the rest time 'til it needs to wake up next, it still won't get any more accurate than 75 to 100 fps (since once it goes to sleep, the thread won't wake up again for about 10ms, which maxes you out at 100 tics per second; and if you're trying for 100fps, then you're not getting any better than a rest(1) anyway.. or worse, rest past the intended wakeup time causing an additional 10ms delay; then add the overhead of the callback loop itself, plus other timers trying to run..).

Obviously there'd be no portable way to do it, but I think having the system interrupt and call into your process at specific intervals to do a simple sem_post wouldn't be too hard to wrap.

Goalie Ca

Hmm.. that's good food for thought. I would have thought the allegro timers would use the underlying operating system ones (eg: windows highperformance timer). Granted.. none are "real-time" but they are pretty accurate nonetheless.

Allegro is in desperate need of threading tools and primitives. Not to be the devil here but SDL has a built-in pthread-like interface. Allegro5 better hurry up. DNF depends on it! I think DOS support is the real problem here holding a lot of this stuff back. Please correct me if i'm wrong.

Thomas Fjellstrom

Allegro has an internal cross platform'ish api.

Kitty Cat
Quote:

I would have thought the allegro timers would use the underlying operating system ones (eg: windows highperformance timer). Granted.. none are "real-time" but they are pretty accurate nonetheless.

They do use the high-precision timing methods when possible, but the granularity of the sleep method is the problem. Whether it tries to sleep 1 nanosecond* or one millisecond, the thread will stay down until it gets a timeslice again, which would be in about 10ms. Having the system interrupt your process on time would be the only way to break that.

(*) Sometimes nanosleep will actually busy wait on really small rest values (a few nanoseconds) depending on the system configuration.

Goalie Ca

So i've gone ahead and wrote a windows/linux/mac timer file that doesn't use allegro. The *nix one uses real-time posix extensions and the windows one uses the multimedia timer set to 1ms accuracy. Both use a semaphore mechanism to wake/sleep.

I've posted it here.
http://www.allegro.cc/forums/thread/594745

edit: no need for windows pthread anymore. THe windows version uses windows own locking mechanism.

Evert
Quote:

I think DOS support is the real problem here holding a lot of this stuff back. Please correct me if i'm wrong.

At your service.
Allegro 5 doesn't have DOS support, unless someone comes along and wants to do the work to try to fit it in somehow.

Thread #594692. Printed from Allegro.cc