ElapsedMilliseconds() gets negative

Windows specific forum
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

ElapsedMilliseconds() gets negative

Post by c4s »

Introduced in Windows 8, turning your computer off will actually put it into some kind of hibernation mode. That's great because it'll help to shut down and boot much faster!

Anyway, if you've read the title you know that this is not why I started this thread. Instead I wanted to let you know what I just found out: ElapsedMilliseconds() isn't very reliable anymore, because it will not be reset when turning you computer off - instead only when restarting it.
Technically this might even be correct behavior. However on the user side it's kind of strange to see statistics (e.g. the Task Manager) telling me that my computer is on for 20 days although I just turned it on a couple of hours ago.

The problem: Since PureBasic is only returning a signed long variable for ElapsedMilliseconds() things can get weird if the computer is "on" for about 24 days. Here and there I'm using a little code to check if a certain delay has passed:

Code: Select all

If ElapsedMilliseconds() > LastTime + 1000  ; At least 1 sec passed?
    LastTime = ElapsedMilliseconds()
    ; [...]
Starting with Windows 8 chances are way higher that this code will fail because after 24 days ElapsedMilliseconds() will return a negative value...

Obviously it would be great if ElapsedMilliseconds() could just return a quad value (which will be safe for the next 290 million years ;)). But apart from that are there any quick fixes for my problem?
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
freak
PureBasic Team
PureBasic Team
Posts: 5941
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Re: ElapsedMilliseconds() gets negative

Post by freak »

If you use the x64 version then the result is 64bit and there is no problem.

Also, it is only problematic on the exact rollover time. As soon as both your start and end measurement are negative, there is no problem anymore because the difference between the two will again be a positive value.
quidquid Latine dictum sit altum videtur
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: ElapsedMilliseconds() gets negative

Post by Demivec »

c4s wrote:But apart from that are there any quick fixes for my problem?

Code: Select all

If ElapsedMilliseconds() > LastTime + 1000   Or ElapsedMilliseconds() < LastTime; At least 1 sec passed or clock rollover?
    LastTime = ElapsedMilliseconds()
    ; [...]
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: ElapsedMilliseconds() gets negative

Post by Tenaja »

freak wrote:Also, it is only problematic on the exact rollover time. As soon as both your start and end measurement are negative, there is no problem anymore because the difference between the two will again be a positive value.
If your start time is anywhere in the first 21 days, and the check-time is anywhere after that, then you have hit that exact rollover time. Obviously there is a workaround to deal with it.

Probably a relatively simple, and very safe solution would be to convert the 32-bit value to 64-bit, then do the math (convert back if necessary). Is there a bitwise copy that does not sign-extend? I'm sure I have seen some macros on here somewhere.
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: ElapsedMilliseconds() gets negative

Post by Danilo »

Long Overflow:

Code: Select all

ms.l = 2147483640

For i = 0 To 20
    Debug ms    
    ms + 1
Next
Convert to quad as unsigned number:

Code: Select all

ms.l = 2147483640

For i = 0 To 20
    ; convert to quad
    quad.q = ms & $FFFFFFFF
    Debug quad
    
    ms + 1
Next
The value returns to 0 after 4294967295 (because we are reading a long), which is 49 days.
You still need to check for new ElapsedMilliseconds() values not being smaller than the last value.
If the new value is smaller, do the math for the overflow.


64bit ElapsedMilliseconds for 32bit systems:

Code: Select all

CompilerIf #PB_Compiler_Processor = #PB_Processor_x86

    Procedure.q ElapsedMilliseconds_64()
        Static ElapsedMilliseconds_64_oldValue.q = 0                ; value of last call
        Static ElapsedMilliseconds_64_overflow.q = 0                ; how many overflows occured
        Protected current_ms.q = ElapsedMilliseconds() & $FFFFFFFF  ; get new value as unsigned number
        If ElapsedMilliseconds_64_oldValue > current_ms             ; If old value is greater than new value
            ElapsedMilliseconds_64_overflow + 1                     ;     increment overflow by 1
        EndIf
        ElapsedMilliseconds_64_oldValue = current_ms
        ProcedureReturn current_ms + ElapsedMilliseconds_64_overflow * $FFFFFFFF ; return current value + overflows
    EndProcedure

    Macro ElapsedMilliseconds()
        ElapsedMilliseconds_64()
    EndMacro
    
CompilerEndIf

For i = 0 To 20
    ms.q = ElapsedMilliseconds()
    Debug ms
    Delay(20)
Next
- Must be used with quad variables (.q).
- Because of signed Quads in PB, this overflows after 106751991167 days (round about 292471208 years).
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: ElapsedMilliseconds() gets negative

Post by c4s »

Thanks to all of you for the great suggestions!
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Post Reply