Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Author
Message
TheComet
18
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 13th Mar 2012 09:41 Edited at: 13th Mar 2012 09:42
Hey all


This is just a heads up to all of you people wanting to run an online DBP server or something. Here's a typical usage of the timer() command:



The command returns a 32 bit value, and starts at 2147483648. It will take a total of 25 days to reach a value of 4294967296. What happens when that occurs? Well, the subroutine DoStuff won't be called again. Ever.

I've expirienced this before when I was rendering a rather large fractal (20 Gigapixels to be exact). There are two solutions to this, the one with abs() is probably slower than the other:





TheComet

Fallout
23
Years of Service
User Offline
Joined: 1st Sep 2002
Location: Basingstoke, England
Posted: 13th Mar 2012 10:01
Interesting! My experience of timer() commands is they return the number of milliseconds since the epoch, and are always incrementing and won't stop for the life of the computer.

So taking your cue, I looked at the help file for timer and noticed this:

st as DWORD
st=TIMER()


I looked at the help file and DWORDs are indeed 32bit, although that makes no sense to me, since I thought the definition of a WORD was the width of the architecture. i.e. 32bit or 64bit on modern machines, making a DWORD 64bit or 128bit.

Have you proven this with a test Mr Comet, or are you assuming based on the help files? It wouldn't surprise me if the help files were wrong as usual, and timer() is returning a 64bit number.

TheComet
18
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 13th Mar 2012 10:37
I have no conclusive evidence that my program stopped working correctly due to the timer() command. As I said, I've been rendering a 20 gigapixel fractal, and after two weeks the program stopped it's calculations.

I am assuming it was the fault of timer().

Even if the command timer() were able to return a 64 bit integer, how would you hold that number in a variable? The highest we can go is dword, which is an unsigned 32-bit integer.

I suppose a float or a double could hold the number, but it has some floating point inaccuracies.

TheComet

Fallout
23
Years of Service
User Offline
Joined: 1st Sep 2002
Location: Basingstoke, England
Posted: 13th Mar 2012 15:52
There are "double integers" in DBP which appear to be 64bit, so I think that'd do the job.

Very interestingly (to me anyway ), I just started getting a new bug in Carnage. When I went to the settings menu, and left it on that screen for several minutes, the game would return from the screen but hang. So my first thought was to remember what you said about adding the "or newTime < startTime" condition to the timer check, and that solved the problem. I'm using PERFTIMER(), so no doubt the timer goes out of range sooner than timer() and then resets to 0, which is probably why I saw the bug quite frequently.

Anyway, turns out I'd moved some timer variables which I'd declared as "double integers" out of the scope of my timer function, so it was creating new variables and defaulting them to normal integers. Since putting the variable definitions back in scope, I haven't been able to recreate the bug. So I think double integer is the way to go. Whether timer() returns a double integer, I have no idea.

BatVink
Moderator
23
Years of Service
User Offline
Joined: 4th Apr 2003
Location: Gods own County, UK
Posted: 13th Mar 2012 17:06
IanM once posted the correct way to make this check, so that when it cycles through zero, it keeps working. It was simple and just a matter of reversing the logic that most people use. Although it's simple, I can't remember or explain it

Calling IanM, calling IanM....

GIDustin
18
Years of Service
User Offline
Joined: 30th May 2008
Location:
Posted: 13th Mar 2012 17:34
http://forum.thegamecreators.com/?m=forum_view&t=125657&b=1&msg=1451486#m1451486

Diggsey
20
Years of Service
User Offline
Joined: 24th Apr 2006
Location: On this web page.
Posted: 13th Mar 2012 17:39
@TheComet
Your code should work correctly, since when you subtract two numbers it doesn't matter if one of them has wrapped around, you will still get a small positive value as the result. The only way it can fail is if the difference itself overflows, so if for some reason DoStuff was not called for 25 days it would stop being called for the next 25 days.

If instead of subtracting the timer() values, you compare them, it will fail as you described though.

[b]
TheComet
18
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 13th Mar 2012 18:49
@ GIDustin, Diggsey - You two are missing the point. If I have this line of code:

if timer() - LastTime > 1000

And timer() wraps, it will never become true again, because timer() will always be smaller than LastTime. The only way to fix this is to either check it for negitivity, or use abs().

TheComet

GIDustin
18
Years of Service
User Offline
Joined: 30th May 2008
Location:
Posted: 13th Mar 2012 18:55 Edited at: 13th Mar 2012 18:57
I am not so sure of that. Lets say it does wrap:

LastTime = 2,147,483,647
timer() = –2,147,483,648

timer() - LastTime
–2,147,483,648 - (2,147,483,647)
= -4,294,967,295

since the result, -4,294,967,295, is outside the scope of an integer, it wraps as well, becoming 0.

At least that is how I took it when IanM explained it...

Edit: Here is an example 1500 MS later:


LastTime = 2,147,483,647
timer() = -2,147,482,148

timer() - LastTime
–2,147,482,148 - (2,147,483,647)
= -4,294,965,795
Which wraps to: 1500
TheComet
18
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 13th Mar 2012 19:16 Edited at: 13th Mar 2012 19:20
Oh I see now... I didn't think of the result also wrapping. Thanks for clarifying

If that's the case though, why did my fractal generator stop working after a while? Are DBP applications able to run for that long?

TheComet

Diggsey
20
Years of Service
User Offline
Joined: 24th Apr 2006
Location: On this web page.
Posted: 13th Mar 2012 21:19
Does your graphics card support 20 gigapixel images?

[b]
Doomster
18
Years of Service
User Offline
Joined: 8th Nov 2007
Location: Germany
Posted: 13th Mar 2012 21:24
Perhaps DBP simply ran out of memory? I mean, it's limited to 2 GB afterall, since it's a 32-Bit application and 20 Gigapixel would quite probably exceed that, I would suppose...

-Doomster

TheComet
18
Years of Service
User Offline
Joined: 18th Oct 2007
Location: I`m under ur bridge eating ur goatz.
Posted: 14th Mar 2012 01:28
In my program I streamed the data directly to disk, so the only limit to how big my fractal can be is my hard drive and the accuracy of the type double (I checked and yes, I had 300 GB free disk space, and the fractal required 60 GB). To view the image you need a special program which picks out the data it needs rather than loading the entire image into memory.

TheComet

Diggsey
20
Years of Service
User Offline
Joined: 24th Apr 2006
Location: On this web page.
Posted: 14th Mar 2012 01:47
Perhaps there is a memory leak in DBPro or a plugin which caused you to run out of memory after leaving it running for a long time.

[b]
Latch
19
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 14th Mar 2012 11:27 Edited at: 14th Mar 2012 11:33
I think the timer() function is based on the winapi function GetTickCount() which does indeed return a DWORD (32 bit unsigned long integer) of milliseconds passed since the system was started up. It lasts for 49.7 days then resets to 0 . It shouldn't start at 2147483648 unless the computer had already been on for 25 days.

Anyway, timer() should loop back to zero after passing 4294967296 unless it's behaving like a signed integer in which case it would start counting backwards (or up if you prefer) from -2147483648 until it reached zero.

So the wrapping might not behave quite as one might expect:

if timer() was 1000
and the last time was -2147483648
the result of timer() - (-2147483648)
would be
1000 + 2147483648 = 2147484648
now if we look at the binary of that:

10000000000000000000001111101000

You can see that bit 31 is set which, if timer()-lasttime is being returned as a signed integer, means that the value is negative. In fact the value is:

-2147482648

So there has to be a conditional that checks for the possibility of timer() being reset or wrapped back to zero:



Just be sure to cast your types to integers or DWORDS.

Enjoy your day.
GIDustin
18
Years of Service
User Offline
Joined: 30th May 2008
Location:
Posted: 14th Mar 2012 15:27 Edited at: 14th Mar 2012 15:39
Latch,

I believe DBPro does all the converting of types for you:





As you can see, it looped, and nothing "huge" happened.

Edit: Also, your example:
Quote: "if timer() was 1000
and the last time was -2147483648"

You are saying that that several weeks have passed since you compared the two values together.... I guess it's possible that you will get odd results if the values aren't compared often. If 80 days have passed since you compared the values, it might say that only a few days have passed, or that none have passed at all...
Benjamin
23
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 14th Mar 2012 15:42
When adding or subtracting the CPU doesn't differentiate between positive and negative numbers (thanks to two's complement) so you don't have to worry about using the right datatype when doing the operation, you only have to worry about how you want the output displayed.



Support a charitable indie game project!
Van B
Moderator
23
Years of Service
User Offline
Joined: 8th Oct 2002
Location: Sunnyvale
Posted: 14th Mar 2012 15:48
The thing that annoys me is that I leave my computer on most of the time, my laptop get's put in sleep mode - so the timer() is way into the choppy numbers all the time, giving pauses between updates.

It actually becomes noticable after only a couple of days - code that relies on timer() starts to jerk... I mean if you had a rotating plain, that rotates like this:

ROTATE OBJECT 1,0,wrapvalue(timer()/3.0),0

This would be smooth and perfect when the PC is first switched on, but after a couple of days it'll be jerky as hell. Ideally, someone one gift me a command to reset the timer. Double-ideal would be an expansion of perftimer - firstly to document the damn commands, secondly to allow the interval to be changed, and of course thirdly, to allow that timer to be reset.

Health, Ammo, and bacon and eggs!
Benjamin
23
Years of Service
User Offline
Joined: 24th Nov 2002
Location: France
Posted: 14th Mar 2012 15:54
Van, that's not typically how a clock/timer is used. Usually you perform your operation on the offset between the current and last values, and in that same way you could just make your own timer:





Support a charitable indie game project!
Van B
Moderator
23
Years of Service
User Offline
Joined: 8th Oct 2002
Location: Sunnyvale
Posted: 14th Mar 2012 16:27
Yes, but when timer starts getting irregular updates, your elapsed time will go from nothing, to chunk values, which will really screw up your code. The code I posted is really just to show how messed up timer() can be, even after just a few days. I tend to use an elapsed variable like yourself, but with irregular timer() updates that elapsed time updates in chunks...

like:
Loop1 : 1ms
Loop2 : 1ms
Loop3 : 1ms

Forward a week...

Loop100503052 : 1ms
Loop100503053 : 0ms
Loop100503054 : 0ms
Loop100503055 : 0ms
Loop100503056 : 5ms
Loop100503057 : 0ms
Loop100503058 : 0ms
Loop100503059 : 3ms
Loop100503060 : 0ms
Loop100503061 : 0ms

So timer based movement means it can end up updating like that - things moving smoothly, then eventually things stop, or move in big chunks. It's not something that can be solved with internal handling, unless you lock the frame rate and forgoe timer based movement. Ideally.... we need to be able to reset timer() on program launch, and even during the program, if the timer() get's too unruly.

Or!!!

If it's possible to set the interval for perftimer, then it might be pretty useful for this stuff - sometimes we don't need 1000th second accuracy, sometimes just 100th is enough, depending on the project. Would probably be better suited to non-movement timer systems though - like virtually locking the frame rate to 50, then passing back any remaining resources to Windows, or internal jobs like path finding and AI. Like, we could set the perftimer to increment according to a specific frame rate, then just wait on the timer changing value. But that way, it would reduce the accuracy of the DWORD, it wouldn't need to be so 'infinite' - and that means it's less likely to hit the jerky numbers.

Oh, if it could have 2 parameters, like a straight second counter DWORD, so 1 seconds = 1 instead of 1000... then have a second timer for just the miliseconds, that resets to 0...
Anything really that helps avoid the inaccuracies would be a benefit.

Health, Ammo, and bacon and eggs!
Diggsey
20
Years of Service
User Offline
Joined: 24th Apr 2006
Location: On this web page.
Posted: 14th Mar 2012 16:31 Edited at: 14th Mar 2012 16:32
@Van B
The reason you are getting jerky results is because you are converting timer() to a float, and a float can't store values that high with good precision. The timer itself doesn't get less accurate with time like you are suggesting. If you convert it to a delta value first and then convert to a float, the value will be much smaller and so you can represent it with very high precision as a float and you won't get any jerkiness.

[b]
Van B
Moderator
23
Years of Service
User Offline
Joined: 8th Oct 2002
Location: Sunnyvale
Posted: 14th Mar 2012 16:41
Ahh! - I'm an idiot

Health, Ammo, and bacon and eggs!
Green Gandalf
VIP Member
21
Years of Service
User Offline
Joined: 3rd Jan 2005
Playing: Malevolence:Sword of Ahkranox, Skyrim, Civ6.
Posted: 14th Mar 2012 18:08
Well spotted Diggsey.

I was puzzling over that one too.
Latch
19
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 15th Mar 2012 02:14 Edited at: 15th Mar 2012 02:16
@GIDustin

Maybe I'm not looking at it right but bear with me a sec...

If timer() returns a DWORD, then it's max value is 4294967295. The next value after that is 0. So, if timer() loops to zero, and we are checking

if timer()-lastvalue > 1000

If lastvalue was 4294967295 and timer() counted up to 999
what would the value of timer()-lastvalue be?

As a dword wouldn't it be undefined because it would be negative, therefore it might have to be cast back to a signed integer where the high bit would be set making it negative and the conditional test failing or remain undefined and cause the conditional to fail?

I'm just trying to address TheComets original post and why his timer check code may have failed.

In your code example, perhaps NewTimer = timer() + Add is automatically casting NewTimer as a signed integer and therefore it is always greater than the new value - or + . But perhaps, in TheComets code the behaviour is as I suggest.

The failure would only occur when timer() is less than lastvalue.

Enjoy your day.
mr Handy
18
Years of Service
User Offline
Joined: 7th Sep 2007
Location: out of TGC
Posted: 15th Mar 2012 14:56 Edited at: 15th Mar 2012 14:56
Quote: "My experience of timer() commands is they return the number of milliseconds since the epoch"


THIS IS TRULY EPIC!!! never thought of that!!!
GIDustin
18
Years of Service
User Offline
Joined: 30th May 2008
Location:
Posted: 15th Mar 2012 15:20
Quote: "If lastvalue was 4294967295 and timer() counted up to 999
what would the value of timer()-lastvalue be?"


It would be a negative number, and if the result was cast as a dword it would be fine, but I believe it would cast to an integer containing the value 999:

(999-4294967295) = -4294966296
wraps to 999 (add 4294967295)

That still works as well... Perhaps there is some way to cast your variables that could cause the problem, but I cannot think of one at the moment.
Fallout
23
Years of Service
User Offline
Joined: 1st Sep 2002
Location: Basingstoke, England
Posted: 15th Mar 2012 15:56
Quote: "THIS IS TRULY EPIC!!! never thought of that!!!"


lol. Why is that so epic MrHandy?

tiresius
23
Years of Service
User Offline
Joined: 13th Nov 2002
Location: MA USA
Posted: 15th Mar 2012 15:57
Quote: "@Van B
The reason you are getting jerky results is because you are converting timer() to a float, and a float can't store values that high with good precision. The timer itself doesn't get less accurate with time like you are suggesting. If you convert it to a delta value first and then convert to a float, the value will be much smaller and so you can represent it with very high precision as a float and you won't get any jerkiness."

Diggsey what is the code for "convert it to a delta value"? I always thought the 8 0 0 0 0 15 0 0 8 0 0 16 type measurements was due to the low resolution of the timer (with it not being updated by the OS as often as it should be)? I've been using IanM's Matrix1Util hitimer() which seems to be much better with this sort of thing.


A 3D marble platformer using Newton physics.
Diggsey
20
Years of Service
User Offline
Joined: 24th Apr 2006
Location: On this web page.
Posted: 15th Mar 2012 19:18
Quote: "I always thought the 8 0 0 0 0 15 0 0 8 0 0 16 type measurements was due to the low resolution of the timer (with it not being updated by the OS as often as it should be)?"


That's quite true, but it's still accurate enough to be able to move objects around smoothly as long as it's used correctly, and the accuracy doesn't degrade with time. Hitimer will certainly give better results though.

[b]
IanM
Retired Moderator
23
Years of Service
User Offline
Joined: 11th Sep 2002
Location: In my moon base
Posted: 15th Mar 2012 20:57 Edited at: 15th Mar 2012 20:57
For those of you that want to understand why differences work when using times directly don't, then read on. Everyone else just ignore me

Rather than use those awful 32 bit signed integer numbers to try and see what happens, I'll just use an 8 bit unsigned number in an example instead - it works in exactly the same way but is easier to understand.

So assuming an 8 bit timer, suppose LastTime=254, and CurrentTime=3 (ie, it got to 255, then wrapped to 0 and continued counting).

ElapsedTime = CurrentTime - LastTime
ElapsedTime = 3 - 254
ElapsedTime = -251

But as the number has underflowed (it's gone below the valid range), you need add 256 (the size of the range) to bring it back into the correct range, so -251 becomes 5.

To confirm that, simply enumerate the values after the start point until you reach the end point and then count them: 255, 0, 1, 2, 3
Those are the 5 values we're looking for.

The 'magic' of 2s-complement binary maths does all of this underflow/overflow/wrapping for you without you needing to worry about it. It works for signed and unsigned numbers no matter their capacity. As long as you are adding, subtracting or carrying out bit-level operations, there's no difference at the processor level between signed and unsigned values.

Latch
19
Years of Service
User Offline
Joined: 23rd Jul 2006
Location:
Posted: 15th Mar 2012 22:40
Oh my goodness! I've been making a huge mistake in my tests. I knew in my heart that values wrapped around but when I was testing it, it wasn't happening; because I was using the wrong values! I was never counting up or changing the value so I ended up confusing myself:

Quote: "Quote: "if timer() was 1000
and the last time was -2147483648"
You are saying that that several weeks have passed since you compared the two values together.... I guess it's possible that you will get odd results if the values aren't compared often. If 80 days have passed since you compared the values, it might say that only a few days have passed, or that none have passed at all..."


I had no idea what GIDustin was talking about because I was thinking to myself "i'm only waiting 1000 ms" but in reality, I was never changing the value I was comparing so I was always getting a negative number!

This is what I was ultimately doing:

1000 - ((2^31)-1)

I was never changing lastvalue! So I was baffled why the values weren't changing and always being negative! I guess bug checking is important after all!

Sorry if my error ended up confusing anybody else!

Enjoy your day.
GIDustin
18
Years of Service
User Offline
Joined: 30th May 2008
Location:
Posted: 15th Mar 2012 23:44
Quote: "Sorry if my error ended up confusing anybody else! "


Think of the positives though. The next guy that searches the forums for "timer()" is going to learn more than he ever wanted to know.

Login to post a reply

Server time is: 2026-07-11 04:30:48
Your offset time is: 2026-07-11 04:30:48