timer problem under vista
I'm using WaitWindowEvent(), it seems to work better here (on XP)
Well now: I tried to strip the program down to just the event loop - getting the time and playing the sounds - and it sort of works under Vista...
so I took the full length program and commented out everything inside the event loop, and noticed two things - first: it performs very differently depending on whether I make an .exe out of it, or run it in the PB console. (makes no difference whatsoever under XP) second: it seemed to get increasingly sticky (but not as bad as the .exe) when i added more stuff inside the event loop.
so, I know I have very much stuff inside the event loop and it's probably very bad programming, but why am i not having these problems under XP? after all it's only Get/SetGadgetState and setting variables, so it shouldn't be too heavy on the hardware (?)
Well now: I tried to strip the program down to just the event loop - getting the time and playing the sounds - and it sort of works under Vista...
so I took the full length program and commented out everything inside the event loop, and noticed two things - first: it performs very differently depending on whether I make an .exe out of it, or run it in the PB console. (makes no difference whatsoever under XP) second: it seemed to get increasingly sticky (but not as bad as the .exe) when i added more stuff inside the event loop.
so, I know I have very much stuff inside the event loop and it's probably very bad programming, but why am i not having these problems under XP? after all it's only Get/SetGadgetState and setting variables, so it shouldn't be too heavy on the hardware (?)
You would think it's that way but I've found Vista itself to be pretty heavy on the hardware whereas XP is a little gentler so the problems of extra stuff in an event loop are partially magnified with Vista, might be time to start optimising any code you can and see if that helps at all.noot wrote:after all it's only Get/SetGadgetState and setting variables, so it shouldn't be too heavy on the hardware (?)
well i can describe briefly what's inside the loop:
- 4 x soundVolume, soundPan, soundFrequency
- 4 x if...and...and...PlaySound
- some ExamineKeyboard and Select for buttongadgets
- twelve (12) times the following kind of bit (checking trackbar and checkbox values) - this should probably be optimised :roll:
the reason for having so much of this if-get-then-set crap is that i have three trackbars and a bunch of checkboxes for each of the four sounds...
- 4 x soundVolume, soundPan, soundFrequency
- 4 x if...and...and...PlaySound
- some ExamineKeyboard and Select for buttongadgets
- twelve (12) times the following kind of bit (checking trackbar and checkbox values) - this should probably be optimised :roll:
Code: Select all
If GetGadgetState(111)=0 And GetGadgetState(112)=0 And GetGadgetState(113)=0 And GetGadgetState(114)=0 And GetGadgetState(115)=0
bdf=GetGadgetState(11)
EndIf
If GetGadgetState(111)=1
bdf=Random(100000)
EndIf
If GetGadgetState(112)=1
bdf=bdf-100
If GetGadgetState(114)=0 And bdf<=0
bdf=100000
EndIf
EndIf
If GetGadgetState(113)=1
bdf=bdf+100
If GetGadgetState(114)=0 And bdf>=100000
bdf=0
EndIf
EndIf
If GetGadgetState(114)=1 And bdf>=99999
SetGadgetState(113,0)
SetGadgetState(112,1)
EndIf
If GetGadgetState(114)=1 And bdf<=1
SetGadgetState(113,1)
SetGadgetState(112,0)
EndIf
Wow, looks like a busy bit of code.
Just as a quick test I changed your code to use variables instead of constantly checking gadget states and halved the time taken, might be all it takes for Vista to be able to run better.
Of course, if you have any delay() or waitwindowevent() commands in your loop then it won't make any difference! 
Just as a quick test I changed your code to use variables instead of constantly checking gadget states and halved the time taken, might be all it takes for Vista to be able to run better.
Code: Select all
OpenWindow(0,0,0,800,600,"",$ca0001)
CreateGadgetList(WindowID(0))
CheckBoxGadget(111,10,10,30,30,"")
CheckBoxGadget(112,10,10,30,30,"")
CheckBoxGadget(113,10,10,30,30,"")
CheckBoxGadget(114,10,10,30,30,"")
CheckBoxGadget(115,10,10,30,30,"")
t=ElapsedMilliseconds()
For n=1 To 100000
If GetGadgetState(111)=0 And GetGadgetState(112)=0 And GetGadgetState(113)=0 And GetGadgetState(114)=0 And GetGadgetState(115)=0
bdf=GetGadgetState(111)
EndIf
If GetGadgetState(111)=1
bdf=Random(100000)
EndIf
If GetGadgetState(112)=1
bdf=bdf-100
If GetGadgetState(114)=0 And bdf<=0
bdf=100000
EndIf
EndIf
If GetGadgetState(113)=1
bdf=bdf+100
If GetGadgetState(114)=0 And bdf>=100000
bdf=0
EndIf
EndIf
If GetGadgetState(114)=1 And bdf>=99999
SetGadgetState(113,0)
SetGadgetState(112,1)
EndIf
If GetGadgetState(114)=1 And bdf<=1
SetGadgetState(113,1)
SetGadgetState(112,0)
EndIf
Next
t=ElapsedMilliseconds()-t
Debug t
t=ElapsedMilliseconds()
For n=1 To 100000
g111=GetGadgetState(111)
g112=GetGadgetState(112)
g113=GetGadgetState(113)
g114=GetGadgetState(114)
g115=GetGadgetState(115)
If g111=0 And g112=0 And g113=0 And g114=0 And g115=0
bdf=g111
EndIf
If g111=1
bdf=Random(100000)
EndIf
If g112=1
bdf=bdf-100
If g114=0 And bdf<=0
bdf=100000
EndIf
EndIf
If g113=1
bdf=bdf+100
If g114=0 And bdf>=100000
bdf=0
EndIf
EndIf
If g114=1 And bdf>=99999
SetGadgetState(113,0)
SetGadgetState(112,1)
EndIf
If g114=1 And bdf<=1
SetGadgetState(113,1)
SetGadgetState(112,0)
EndIf
Next
t=ElapsedMilliseconds()-t
Debug t

Actually I was thinking of "QueryPerformanceCounter" but couldn't remember the name before.noot wrote:thanks for the tip paul, i'll try it with something else (GetTickCount is it?), and maybe also check the driver updates... i'll report back when i see what happens
Apparently it's a lot higher resolution than GetTickCount which is "limited to the resolution of the system timer" accoring to MS
QueryPerformanceCounter
http://msdn2.microsoft.com/en-us/library/ms644904.aspx
GetTickCount
http://msdn2.microsoft.com/en-us/library/ms724408.aspx
More info about timers in general from MS is here
http://msdn2.microsoft.com/en-us/library/ms644900.aspx
Paul Dwyer
“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
Derek,
that's very interesting - I haven't realized that there could be THAT big a difference, although I normally always do put the states into variables, just for convenience... however, I have to use WaitWindowEvent(1) keeping this whole thing together so I'm afraid it's no help this time
Another thing I just thought of - maybe I should put Else Gosub after the first check, because there's not much use checking if any of the flags are 1 when they've all just been checked to be 0, is there
Paul,
I replaced the milliseconds/ticks with QueryPerformanceCounter, but no change on either system as to the actual performance, BUT the PerformanceCounter resolution is really pretty insane - if I'm interpreting the results correctly it's something like 3500 to 1 compared to the ticks (!) Wow.
that's very interesting - I haven't realized that there could be THAT big a difference, although I normally always do put the states into variables, just for convenience... however, I have to use WaitWindowEvent(1) keeping this whole thing together so I'm afraid it's no help this time

Another thing I just thought of - maybe I should put Else Gosub after the first check, because there's not much use checking if any of the flags are 1 when they've all just been checked to be 0, is there

Paul,
I replaced the milliseconds/ticks with QueryPerformanceCounter, but no change on either system as to the actual performance, BUT the PerformanceCounter resolution is really pretty insane - if I'm interpreting the results correctly it's something like 3500 to 1 compared to the ticks (!) Wow.
Yeah, so you need to findout how many ticks per second your hardware does
My system is 3,579,545 ticks per second
No idea how much that changes for different CPUs and vendors, I don't suppose it's relevent provided you are dividing correctly, I guess that the function overhead etc means it's not perfect but the tick count ones and PBs seems to be in 16ms resolution on my PC so atleast this is a lot better.
Since this didn't improve your performance I'm guessing that perhaps your sound drivers or something are not 100% under vista and you are runing overtime on response then catching up again, this would explain what you are seeing with performance too, more than a problem with timers and ticks
Code: Select all
freq.q
If QueryPerformanceFrequency_(@freq)
Debug Str(freq) + " ticks per second"
EndIf
No idea how much that changes for different CPUs and vendors, I don't suppose it's relevent provided you are dividing correctly, I guess that the function overhead etc means it's not perfect but the tick count ones and PBs seems to be in 16ms resolution on my PC so atleast this is a lot better.
Since this didn't improve your performance I'm guessing that perhaps your sound drivers or something are not 100% under vista and you are runing overtime on response then catching up again, this would explain what you are seeing with performance too, more than a problem with timers and ticks
Paul Dwyer
“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
Same here, so apparently it counts 1/3579545's of seconds regardless of hardware - ie. does exactly what a timer should do, and seems to do it pretty very well too!
But yeah, it must be a compatibility issue - and probably an isolated case at that. I'll update the CPU & soundcard drivers to see if that does anything, and after that it's back to XP for me
But yeah, it must be a compatibility issue - and probably an isolated case at that. I'll update the CPU & soundcard drivers to see if that does anything, and after that it's back to XP for me

timeBeginPeriod_()
timeEndPeriod_()
timeGetTime_()
Look up timeBeginPeriod and timeEndPeriod and timeGetTime in the PSDK or MSDN, also search these forums, I and several others have posted many examples on these.
timeGetTime is like getTicks only it uses the multimedia code in Windows and you can use timeBegindPeriod to increase the accuracy from um 15ms (on XP I think) down to ~2ms.
You might also consider putting the time stuff in it's own thread with a high priority. Myself in a program I created a timer thread set it to realtime priority and which runs in a loop with a Sleep_(1) in it and it sets a global variable with the value from timeGetTime_() and then I use a macro GetTime() that basically is a macro wrapper for the global variable.
I think I posted a example in Tips and Tricks some time ago.
The benefit of this is that the variable is updated each 1ms (remember to set the period at program start and end) or as close to 1ms as possible but your programs can use the GetTime() macro as much as you want with no additional procedure of API call overhead, only the overhead of reading a variable.
If this is overkill for your program (sounds to me like you might benefit from that particular solution actually) then you might want to redo your loop instead.
In a internet radio player I made all stuff is in the mainloop,
but the gadget checking and gfx vumeter display etc is layed out in a very efficient way.
The loop uses WaitWindowEvent(time) the time is a var that changes depending on wether the program is minimzed or not etc. (the goal is to only use as much cpu/resources as you need when you actually need it).
The code is layed out like this.
*loop start
-Was there an event?
--Yes, was it the main window?
---Yes, which gadget?
----What was the event?
-----Do gui stuff.
--No event timeout was reached, or a 0 event occured.
-Is the GUI visible (not minimized)?
--Yes, is it time yet to updated the graphics? (timer check or var check)
---Yes, draw the gui stuff
*loop end
I'm my case the audio is already in it's own playback thread thanks to BASS library so I won't have to deal with that luckily.
The graphics however will not be updated as long as GUI stuff is being processed (this is intentional to minimize CPU use) but is updated once that is done or if no GUI handling was needed at all.
My advice is get the audio stuff into it's own playback thread if you need to.
Also pay close attention to the gui stuff in the example above,
there is no point reading a trackbar unless an event happen and for that window and for that gadget. So if you are checking the trackbar everytime the loop um loops (pardon the pun) that is horrible coding, and it kinda smells like OOP and Managed coding gone wrong.
I really hope you will not continue to use the trackbar itself to store the value, read it and put it in a variable instead, only read the trackbar if you know the value has changed. As pointed out in the posts above your eating up way more cpu/resources than you truly need due to this.
Only do stuff when you actually need to do it, cache values/data wherever possible thus reducing the overhead of calling functions and procedures all the time, the less code there is inside a loop the better, prepare as much as possible before entering a loop, code inside procedures and functions etc also count as part of the code inside the loop so the less code there are inside those the faster the loop is.
With PureBasic you have the power to do this easily, lean mean code
timeEndPeriod_()
timeGetTime_()
Look up timeBeginPeriod and timeEndPeriod and timeGetTime in the PSDK or MSDN, also search these forums, I and several others have posted many examples on these.
timeGetTime is like getTicks only it uses the multimedia code in Windows and you can use timeBegindPeriod to increase the accuracy from um 15ms (on XP I think) down to ~2ms.
You might also consider putting the time stuff in it's own thread with a high priority. Myself in a program I created a timer thread set it to realtime priority and which runs in a loop with a Sleep_(1) in it and it sets a global variable with the value from timeGetTime_() and then I use a macro GetTime() that basically is a macro wrapper for the global variable.
I think I posted a example in Tips and Tricks some time ago.
The benefit of this is that the variable is updated each 1ms (remember to set the period at program start and end) or as close to 1ms as possible but your programs can use the GetTime() macro as much as you want with no additional procedure of API call overhead, only the overhead of reading a variable.
If this is overkill for your program (sounds to me like you might benefit from that particular solution actually) then you might want to redo your loop instead.
In a internet radio player I made all stuff is in the mainloop,
but the gadget checking and gfx vumeter display etc is layed out in a very efficient way.
The loop uses WaitWindowEvent(time) the time is a var that changes depending on wether the program is minimzed or not etc. (the goal is to only use as much cpu/resources as you need when you actually need it).
The code is layed out like this.
*loop start
-Was there an event?
--Yes, was it the main window?
---Yes, which gadget?
----What was the event?
-----Do gui stuff.
--No event timeout was reached, or a 0 event occured.
-Is the GUI visible (not minimized)?
--Yes, is it time yet to updated the graphics? (timer check or var check)
---Yes, draw the gui stuff
*loop end
I'm my case the audio is already in it's own playback thread thanks to BASS library so I won't have to deal with that luckily.
The graphics however will not be updated as long as GUI stuff is being processed (this is intentional to minimize CPU use) but is updated once that is done or if no GUI handling was needed at all.
My advice is get the audio stuff into it's own playback thread if you need to.
Also pay close attention to the gui stuff in the example above,
there is no point reading a trackbar unless an event happen and for that window and for that gadget. So if you are checking the trackbar everytime the loop um loops (pardon the pun) that is horrible coding, and it kinda smells like OOP and Managed coding gone wrong.
I really hope you will not continue to use the trackbar itself to store the value, read it and put it in a variable instead, only read the trackbar if you know the value has changed. As pointed out in the posts above your eating up way more cpu/resources than you truly need due to this.
Only do stuff when you actually need to do it, cache values/data wherever possible thus reducing the overhead of calling functions and procedures all the time, the less code there is inside a loop the better, prepare as much as possible before entering a loop, code inside procedures and functions etc also count as part of the code inside the loop so the less code there are inside those the faster the loop is.
With PureBasic you have the power to do this easily, lean mean code

I see in your example snippet that you only set gadget 113 and 112
The others you only read so I assume those are moved/changed by the user?
In that case put all that stuff among the other gadget select stuff
and right after endselect put the SetGadgetState.
That should move all the gadget stuff into the select block and only triggered when the user actually interacts with the GUI.
If done properly you should only have the sound play triggering outside/after the gui stuff, getting all the cpu it needs.
The only issue that still remain is if the user happen to interact with the GUI at the same time as a sound event happen, which is why you should consider using a thread.
A nice way to test this would be to click on the window titlebar and keep grabbing it, most likely the sound will never be played until you let go of the window again. With a thread it will play the sound even if you do this.
The others you only read so I assume those are moved/changed by the user?
In that case put all that stuff among the other gadget select stuff
and right after endselect put the SetGadgetState.
That should move all the gadget stuff into the select block and only triggered when the user actually interacts with the GUI.
If done properly you should only have the sound play triggering outside/after the gui stuff, getting all the cpu it needs.
The only issue that still remain is if the user happen to interact with the GUI at the same time as a sound event happen, which is why you should consider using a thread.
A nice way to test this would be to click on the window titlebar and keep grabbing it, most likely the sound will never be played until you let go of the window again. With a thread it will play the sound even if you do this.
Thanks Rescator, I think this will be a huge help! I didn't even
know about threads previously, but if they work like I understand,
looks like a playback thread will solve one or two other problems
as well... I was just going to ask if there is any way to keep the
program from halting when moving the window etc. but I guess
this is it
I definitely have some rewriting to do now...
know about threads previously, but if they work like I understand,
looks like a playback thread will solve one or two other problems
as well... I was just going to ask if there is any way to keep the
program from halting when moving the window etc. but I guess
this is it
