SFML community forums

General => General discussions => Topic started by: Laurent on May 19, 2011, 08:23:03 am

Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on May 19, 2011, 08:23:03 am
Hi

A major API break today: I changed all times to be Uint32 number of milliseconds instead of float number of seconds.

It may potentially break a lot of code, so... good luck for updating :mrgreen:

Here is a list of what is modified by this update:
- sf::Clock::GetElapsedTime
- sf::Window/RenderWindow::GetFrameTime
- sf::SoundBuffer/Music::GetDuration
- sf::SoundStream/Sound/Music::Set/GetPlayingOffset
- sf::SoundStream::OnSeek
- timeouts in sf::Http/Ftp/TcpSocket/IpAddress/SocketSelector

As a bonus, I also added the sf::Int64 and sf::Uint64 types.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: xazax on May 19, 2011, 01:00:45 pm
Yay!

Good news for me, most of us (at least I think) is more comfortable with the milliseconds, since most of the libraries use that approach.

Thanks!
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Tank on May 19, 2011, 01:46:22 pm
Very good. :)
Title: Re: Switched times to Uint32 milliseconds in SFML 2
Post by: Nexus on May 19, 2011, 10:50:58 pm
Oh, so I already know what to do next in Thor ;)

I think the client code of RenderWindow::GetFrameTime() becomes more complicated when game logic functions work with a float dt (part of a second). However it would be inconsistent not to change it as the single function in SFML. Another option would is also to modify the logic ticks where possible and only work with milliseconds.

It's a good thing that you get rid of float's inaccuracy for long times. But aren't the floats theoretically more precise than a millisecond? As far as I know, QueryPerformanceCounter on Windows may have a higher resolution than 1 ms.

The addition of the 64 bit types is very nice!
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on May 19, 2011, 10:54:05 pm
Quote
Just out of interest: Weren't the floats theoretically more precise than a millisecond? On the counterpart, they are less accurate for long times.

Yes, the problem is that they become less accurate too quickly (apparently it becomes a problem after 2.33 hours).
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Nexus on May 19, 2011, 10:56:18 pm
So you sacrifice the high-performance timers for the sake of long measurements, which are of course more realistic. You could have had both advantages with double, couldn't you?
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on May 19, 2011, 11:13:00 pm
Quote
So you sacrifice the high-performance timers

Nop, SFML never claimed to support less than 1 ms precision. The reason why floats were initially used is not the extra precision they can store.

Quote
You could have had both advantages with double, couldn't you?

In fact I decided to stop using floating point numbers in general, and switch to types that allow exact representations -- integers.
And it makes little sense to go below millisecond precision, it's hard to achieve and rarely needed. So Uint32 is enough.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Disch on May 19, 2011, 11:25:28 pm
This is great news!
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Nexus on May 20, 2011, 01:28:02 am
Okay, that makes sense, thanks for the explanation! I'll have to work a little with the new units until I fully see their advantages and limits.

By the way, I don't think an additional #ifdef _MSC_VER is necessary for the 64 bit types, because MSVC++ supports signed/unsigned long long since 2005. See here (http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx) :)
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on May 20, 2011, 07:35:28 am
Quote
By the way, I don't think an additional #ifdef _MSC_VER is necessary for the 64 bit types, because MSVC++ supports signed/unsigned long long since 2005

Oh ok, but I think it's safer to leave it -- although I officially don't care about VC6, VC2002/2003 are still supposed to work ;)
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Svenstaro on May 23, 2011, 01:34:22 am
So with uint32 we will get problems only after almost 50 days. Good enough for me and about any purpose I can think of where sfml would be utilized.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: OniLinkPlus on May 23, 2011, 02:11:02 am
50 days of insignificantly less accurate instead of approx 2 hours of insignificantly more accurate? Sounds good to me!
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Tank on May 24, 2011, 02:41:02 am
Not less accurate, but overflowing. There's the time when all 32 bits are 1. ;)
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Mars_999 on June 02, 2011, 05:12:32 am
Quote from: "OniLink10"
50 days of insignificantly less accurate instead of approx 2 hours of insignificantly more accurate? Sounds good to me!


Ha, you never played WOW, EVERCRACK, or BC2 :) Sleep what's that?
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: OniLinkPlus on June 02, 2011, 06:21:32 am
Quote from: "Mars_999"
Quote from: "OniLink10"
50 days of insignificantly less accurate instead of approx 2 hours of insignificantly more accurate? Sounds good to me!


Ha, you never played WOW, EVERCRACK, or BC2 :) Sleep what's that?
I used to play WoW. Never got addicted. Never saw what was addicting about it. In fact, it bored me.
Your point is?
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Groogy on June 02, 2011, 11:22:55 am
Quote from: "OniLink10"
Quote from: "Mars_999"
Quote from: "OniLink10"
50 days of insignificantly less accurate instead of approx 2 hours of insignificantly more accurate? Sounds good to me!


Ha, you never played WOW, EVERCRACK, or BC2 :) Sleep what's that?
I used to play WoW. Never got addicted. Never saw what was addicting about it. In fact, it bored me.
Your point is?


^--- What he said
EVE though on the other hand.. If I could inject it, I would...
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Mars_999 on June 02, 2011, 10:41:41 pm
Quote from: "OniLink10"
Quote from: "Mars_999"
Quote from: "OniLink10"
50 days of insignificantly less accurate instead of approx 2 hours of insignificantly more accurate? Sounds good to me!


Ha, you never played WOW, EVERCRACK, or BC2 :) Sleep what's that?
I used to play WoW. Never got addicted. Never saw what was addicting about it. In fact, it bored me.
Your point is?


My point is you are apparently not one of 11+million users who are. So you aren't the norm.

Either way the main point is some games run more than a day I seen some friends who let their computers sit there and run as there was no save function vs. going through the game again, and it sat there for days....

OH BTW I have not played WOW, EVERCRACK, but BC2 ahhhh yes good times!

Couldn't we just overload the function? And keep the float version also? Not sure what harm that would do....
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Nexus on June 02, 2011, 11:51:24 pm
Quote from: "Mars_999"
Couldn't we just overload the function? And keep the float version also?
You cannot overload functions if their signature (name and parameters) is the same. At sf::Clock::GetElapsedTime(), only the return value was changed, not the signature.

The only option would be a function with another name, for example GetElapsedSeconds() and GetElapsedMilliseconds().
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Mars_999 on June 03, 2011, 01:03:29 am
Quote from: "Nexus"
Quote from: "Mars_999"
Couldn't we just overload the function? And keep the float version also?
You cannot overload functions if their signature (name and parameters) is the same. At sf::Clock::GetElapsedTime(), only the return value was changed, not the signature.

The only option would be a function with another name, for example GetElapsedSeconds() and GetElapsedMilliseconds().


My bad for not looking at the function ahead of time. I assumed we sent in a parameter... How about a template class then....
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on June 03, 2011, 08:32:55 am
Quote
My bad for not looking at the function ahead of time. I assumed we sent in a parameter... How about a template class then....

No way. sf::Clock is a very simple class, its interface must remain simple.
But I don't understand your point: float allows even less precision (2.33 hours vs 50 days for uint32). The only way to allow more would be to use uint64.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Kian on June 09, 2011, 09:46:26 pm
The beauty of ints is you just concatenate them together, and get a bigger int.

It's only fifty days if you don't check for an overflow. If you expect the timer to have to go longer than 50 days, you can make a quick check to see if the new time is greater than the old time. If it isn't, add one to another int. This new int holds the number of times you overflowed. Multiply by fifty, and you got the whole length of days. For a regular 32 bit int, this method gives you millisecond precision out to... 18,446,744,073,709,551,615ms, which works out to 584,542,046 years.

Half a billion years should be enough for most purposes. Add another counter in case you overflow this one, and it should provide room for longer than the age of the universe.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Svenstaro on June 09, 2011, 10:24:10 pm
Or just use uint64_t to begin with.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Disch on June 09, 2011, 10:30:02 pm
I'm not sure what the issue is here... maybe I didn't read the thread correctly.

I 100% agree with the change to Uint32.  In fact before it existed I had to have a wrapper class around sf::Clock to convert the times to Uint32.

The big problem with floats is that the higher they get, the less precise they are.  As was mentioned, after about 2 hours, a float timer will begin to lose precision.  2 hours is nothing for a game -- many people play games for several hours at a time.

Other non-game programs are sometimes run 24/7.  In that instance a float clock would be near worthless.

With Uint32 you don't ever have to worry about loss of precision.  You have millisecond precision (give or take depending on the platform) and it's consistent.

If you want a float clock, it's easy to wrap the Uint32 version to produce a float  (return Time() / 1000f;).  The opposite is not true because the loss of precision can skew the timing and give you false results.  The only way I could accomplish it in my attempts was to reset the clock every now and then to ensure there was no loss of precision.  However this has side effects of adding possible gaps in the time, and the clock requiring occasional CPU attention.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on June 09, 2011, 10:52:05 pm
Quote
Or just use uint64_t to begin with.

That wouldn't prevent the returned Uint32 from overflowing.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: pdinklag on June 10, 2011, 10:02:43 am
Quote from: "Mars_999"
Couldn't we just overload the function? And keep the float version also? Not sure what harm that would do....

The float version is obsolete really. The simple conversion from Uint32 milliseconds to float seconds comes for free basically and allows for the highest possible precision.

Using a 32-bit field for a time stamp is becoming really uncommon these days, though. There shouldn't be too much of a problem since the counting begins with the initialization of the clock, but I'd still suggest going with the flow and using a 64-bit value here.

Since overloading isn't possible with the same signature, I'd suggest to simply change the return time of GetElapsedTime to Uint64. That will require people to change their code again, but SFML2 isn't yet official and this hassle wouldn't have to be bothered with anymore in the future (at least not the foreseeable future).

Another possibility would be adding a function like "GetElapsedTimeLong" that returns a Uint64. The clock's internal counter would be a Uint64 value and the old Uint32 version would simply return the lower 32 bits. It would keep people from having to alter their sources again, but IMO going to Uint64 entirely is the best way.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Nexus on June 10, 2011, 01:55:36 pm
Quote from: "pdinklag"
The float version is obsolete really. The simple conversion from Uint32 milliseconds to float seconds comes for free basically
The conversion is still explicitly necessary; forgetting it may lead to warnings, while the code still compiles. But it is of course possible. My point is, the same code is now more complicated on user side, either because
Quote from: "pdinklag"
There shouldn't be too much of a problem since the counting begins with the initialization of the clock, but I'd still suggest going with the flow and using a 64-bit value here.
I don't think a 64 bit type brings relevant advantages. To "go with the flow", Laurent should take std::time_t and not an arbitrary integer type. But in my opinion, sf::Uint32 is fine for milliseconds.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on June 10, 2011, 02:14:30 pm
I don't think that time_t is a good candidate:
Quote from: "Wikipedia"
ISO C defines time_t as an arithmetic type, but does not specify any particular type, range, resolution, or encoding for it. Also unspecified are the meanings of arithmetic operations applied to time values.

Quote from: "Wikipedia"
Unix and POSIX-compliant systems implement time_t as an integer or real-floating type [1] (typically a 32- or 64-bit integer) which represents the number of seconds since the start of the Unix epoch: midnight UTC of January 1, 1970 (not counting leap seconds).


And I don't think it's worth using Uint64, people often end up storing time in Uint32, therefore they would need explicit static_cast so that the compiler doesn't complain about potential loss of precision.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: pdinklag on June 10, 2011, 04:50:15 pm
Quote from: "Nexus"
There is the omnipresent /1000.f to get seconds or

Isn't that what macros were invented for? :) (which I don't have in Java :( )
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Disch on June 10, 2011, 04:56:22 pm
Quote
Isn't that what macros were invented for?


Ugh, no.  Macros violate scope rules and pollute the namespace.

an inline function or a wrapper class would be better:

Code: [Select]

// to keep this simple, it does not handle wrapping gracefully
//   do not run for more than 49 days
//   (although because it gives you a float, it will become useless earlier
//    than that anyway)
class ClockFloat
{
  sf::Clock clk;
public:
  inline void Reset()
  {
    clk.Reset();
  }

  inline float GetElapsedTime()
  {
    return clk.GetElapsedTime() / 1000.0f;
  }
};
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Haikarainen on July 03, 2011, 11:41:29 am
Umm, just a sidenote: Couldn't the 50-dayslimit of uint32 be a lot larger if you we're to use a multiplier int on the side?
Like when the uint32 has reached its limit, the multiplier +=1, and the uint resets. And then just get the time using `(maxvalue of a uint32 * multiplier int) + current uint32 value ? Or would that cause trouble to precision?

Edit; was that really stupid or is there some sort of precise type that can store such high values as a returntype?
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on July 03, 2011, 02:46:23 pm
There's Uint64 but I don't want to use it. I'm fine with Uint32 and its 49.7 days limit.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Tronic on July 06, 2011, 11:33:33 pm
This change is a clear and useless regression.

Use double, keep the API compatibility and keep it precise down to microsecond level for 300 years. Time precision greater than 1 ms is important for various things including audio clock sync, profiling and such. 1 ms jitter is apparent on smooth 60 FPS animation even if not particularly disturbing.

There are highly precise timers available on all major platforms, so there is also no reason to only offer 1 ms precision. Double precision floating-point is lightning fast to calculate with and the extra four bytes for a clock memory footprint cannot be significant either (especially since floats are promoted to double anyway when put into registers or passed to functions).
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: kolofsson on November 04, 2011, 06:13:16 pm
Sorry to resurrect this thread but I've got a question.

Let's assume that each one frame of some game lasts a constant 1.6 ms. By one frame I mean one loop cycle. The question is: what will be the elapsed time value? Will it be equal to 2 ms each frame?

I'm asking because the elapsed time is used to calculate movement of an object by multiplying its velocity by the elapsed time. When the interval is big, there is no problem, but if it is as small as I've suggested, will there be problems?

I must say I'm not convinced to using integer for storing time. It's like limiting sprite position to full pixels.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on November 04, 2011, 06:32:37 pm
There will be a problem indeed, since 1.6 can't be returned (it will be 1 by the way, C++ truncates when it converts float to int).
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: gsaurus on November 05, 2011, 02:19:04 am
I'm experiencing a problem that may be related to this. I'm using a clock in the game loop to monitor the time taken by logics updates and by draws, so if updates take too long, the display is skipped, if everything is done quickly I make it sleep the rest of the frame duration, and things like that, so every frame has exactly the same duration. But the clock introduces errors, specially if updates or draws are fast, and I need precision because of netplay synchronization.

When I drag/resize the window it desynchronizes a little bit more (game goes a little bit faster than expected), I'm not sure how the integer timer is affecting it or not, maybe I have something wrong anyway.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: OniLinkPlus on November 05, 2011, 03:57:00 am
Quote from: "Tronic"
This change is a clear and useless regression.

Use double, keep the API compatibility and keep it precise down to microsecond level for 300 years. Time precision greater than 1 ms is important for various things including audio clock sync, profiling and such. 1 ms jitter is apparent on smooth 60 FPS animation even if not particularly disturbing.

There are highly precise timers available on all major platforms, so there is also no reason to only offer 1 ms precision. Double precision floating-point is lightning fast to calculate with and the extra four bytes for a clock memory footprint cannot be significant either (especially since floats are promoted to double anyway when put into registers or passed to functions).
If you read the arguments FOR using integers in the thread, you would see that that "extra precision" you need wouldn't exist even if floats were used. OSes only guarantee precision to the millisecond level.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Felheart on November 05, 2011, 06:55:20 am
It's a bit unclear to me but if I set the fps limit to 100:
window.SetFramerateLimit(100);
then, i accumulate the the value of GetFrameTime(); each frame.
After exactly one day, will my "accumulated-time" variable differ significantly from the value "86400000" (milliseconds in a day) ??

In other words, will GetFrameTime try to make up for previous errors / inaccurate measures?

I am currently using my own timing system (I use the .NET bindings and the Stopwatch class) in order to minimize such errors.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: kolofsson on November 05, 2011, 09:34:41 am
Quote from: "Laurent"
There will be a problem indeed, since 1.6 can't be returned (it will be 1 by the way, C++ truncates when it converts float to int).


What if my loop lasted shorter than 1 ms (0.9 ms), would it be truncated to 0 ms?

Also, if I ran a loop that would accumulate the elapsed time, the loop lasting 1,9 ms (displayed as 1 ms), after 1000 frames 1,9 second would have elapsed in reality, but the accumulated timer value would show 1 second! That's seriously crappy. In that case I would totally drop the frame timer and go for a global timer. Then the differences would be corrected, right?

What do you mean that OS guarantees 1ms as the smallest measurement? If so, then why was the float displaying non-round FPS values, like 1700 FPS?
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on November 05, 2011, 10:27:59 am
Quote
will GetFrameTime try to make up for previous errors / inaccurate measures?

No.

Quote
What if my loop lasted shorter than 1 ms (0.9 ms), would it be truncated to 0 ms?

Yes.

Quote
In that case I would totally drop the frame timer and go for a global timer. Then the differences would be corrected, right?

Yes.

Quote
What do you mean that OS guarantees 1ms as the smallest measurement? If so, then why was the float displaying non-round FPS values, like 1700 FPS?

Indeed it's not true, all OSes can provide sub-millisecond resolution.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: gsaurus on November 05, 2011, 12:30:37 pm
Quote from: "kolofsson"
What if my loop lasted shorter than 1 ms (0.9 ms), would it be truncated to 0 ms?

This is most likely what is happening with my game, specially during window drag/resize when display is ignored, truncations make my game run a little bit faster :(. Any suggestion?
I see two different uses of clocks: longterm and precision measurements, sometimes I wish there were one clock for each.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: kolofsson on November 05, 2011, 01:42:12 pm
Quote from: "gsaurus"
This is most likely what is happening with my game, specially during window drag/resize when display is ignored, truncations make my game run a little bit faster :(. Any suggestion?
I see two different uses of clocks: longterm and precision measurements, sometimes I wish there were one clock for each.


Yes we could have a float precision clock, what's the problem, what's the harm?

Gsaurus, I guess a global timer would help you. Then, each frame you could store the timestamp in an array:

Code: [Select]
timestamp[frame_number] = gettime()

And then, to get the time elapsed:

Code: [Select]
time_elapsed = timestamp[current_frame] - timestamp[current_frame - 1]

if time_elapsed equals 0, skip this iteration of the loop.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Nexus on November 05, 2011, 03:17:19 pm
In the long term, a high precision clock might indeed be useful. Actually, I personally find milliseconds quite annoying -- they are too unprecise for some measurements, and very cumbersome for everyday work (seconds are usually easier to imagine and to work with) ;)

I also thought about writing high precision clocks on top of SFML, but given its current interface, I have to duplicate the whole code (i.e. sf::Clock and the implementation for all platforms), if I'm not mistaken. If at least sf::priv::GetSystemTime() returned nanoseconds, I could use it as a workaround for the time being :P
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: kolofsson on November 05, 2011, 03:44:10 pm
Quote from: "Nexus"
milliseconds  are too unprecise for some measurements, and very cumbersome for everyday work (seconds are usually easier to imagine and to work with) ;)


Exactly! If I'm using the standard SI physical units and want to calculate car/ball movement in a single frame, I have to multiply velocity (meters/second) * delta time (milliseconds) and divide it by 1000. This is really neither fast nor elegant.

EDIT: Since I'm using Python (and still learning it), I found a neat function in Python called time.clock(). The description from the docs: a floating point number, based on the Win32 function QueryPerformanceCounter(). The resolution is typically better than one microsecond.


I guess, bye bye sf::timer :P
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Spidyy on November 06, 2011, 03:37:02 pm
I kept the old version of sf::clock (in millisecond) because it is really more easy to use. No need for additionnal conversion or reflexion. I don't use the network so I don't need precisely timed clock, and having to do some tricks to have a decent FPS counter or whatever don't have its place in the S of SFML.

BTW, the clock mechanism are easy to change or use. And the wiki exist.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Nexus on November 06, 2011, 04:00:00 pm
Quote from: "Spidyy"
BTW, the clock mechanism are easy to change or use. And the wiki exist.
Yes, but changing SFML itself is not a good idea, I prefer non-intrusive approaches. And as mentioned, you currently need to duplicate the whole SFML code if you want to measure microseconds in a platform-independent way.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Tronic on December 14, 2011, 03:31:08 am
Quote from: "OniLink10"
Quote from: "Tronic"
This change is a clear and useless regression.

Use double, keep the API compatibility and keep it precise down to microsecond level for 300 years. Time precision greater than 1 ms is important for various things including audio clock sync, profiling and such. 1 ms jitter is apparent on smooth 60 FPS animation even if not particularly disturbing.

There are highly precise timers available on all major platforms, so there is also no reason to only offer 1 ms precision. Double precision floating-point is lightning fast to calculate with and the extra four bytes for a clock memory footprint cannot be significant either (especially since floats are promoted to double anyway when put into registers or passed to functions).
If you read the arguments FOR using integers in the thread, you would see that that "extra precision" you need wouldn't exist even if floats were used. OSes only guarantee precision to the millisecond level.


As others have pointed out, that belief is bogus. All OSes worth a mention provide nanosecond or similar precision in their time interfaces, and the actual timers on pretty much any platform are of very high precision too. I highly doubt SFML ever getting ported to a system where time precision wouldn't be better than 1 ms.

Also, it needs to be emphasized that double precision float (i.e. double) is needed. Single precision (i.e. float) is not enough as was demonstrated by the original issue that started this thread. Double precision floating-point calculations are extremely fast even on modern mobile platforms (not to mention x86), so the performance won't be an issue. Neither should the 8 byte memory footprint for a time value matter anywhere.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on December 14, 2011, 08:57:02 am
It seems that everybody wants different things:
- nanoseconds, microseconds, milliseconds, seconds
- float, double, Uint32, Uint64

The most flexible approach would be to implement sf::Clock using a Uint64 number of nanoseconds. This is indeed possible on supported OSes; I can even improve the implementation to use only monotonic and non-overflowing functions.

But then I still have to decide what to provide in the public API. I have several solutions, but none of them would satisfy everyone:
- provide Uint64 nanoseconds, but then many people will complain that we're losing the S of SFML
- provide Uint32 milliseconds, but then some people will complain that the resolution is too high
- provide double seconds, but then some people will complain about the lack of exact timestamps, as well as the need to cast to float every calculation involving time (everything gets promoted to double when one of the operands is a double, but SFML uses float everywhere else)
- provide everything, but then I will complain about the bloated API

If someone can find a clean solution to this problem I'm ready to rewrite sf::Clock again if necessary.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: luiscubal on December 14, 2011, 03:12:53 pm
How about some simple-to-use flexible TimeSpan class?

Code: [Select]

class TimeSpan {
   //Whatever;
public:
  //constructors come here

  Uint64 GetNanoseconds() const;
  Uint32 GetMilliseconds() const;
  double GetSeconds() const;
};
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on December 14, 2011, 03:25:19 pm
Quote
How about some simple-to-use flexible TimeSpan class?

It doesn't solve points 3 and 4
Quote
- provide double seconds, but then some people will complain about the lack of exact timestamps, as well as the need to cast to float every calculation involving time (everything gets promoted to double when one of the operands is a double, but SFML uses float everywhere else)
- provide everything, but then I will complain about the bloated API

And I don't know if it's clear enough that every function returns the same thing with a different type/resolution, it could be a decomposition of a time value instead, like the "tm" struct in time.h.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: luiscubal on December 14, 2011, 04:14:20 pm
To be honest, I'm perfectly fine with the current SFML 2 time API.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laugilus on December 15, 2011, 01:21:38 pm
What about :

Code: [Select]
template <class T = Uint32>
class Clock;

template <>
class Clock<Uint32> {/* milisec implementation */};

template <>
class Clock<Uint64> {/* nanosec implementation */};

template <>
class Clock<double> {/* double implementation */};

// A float implementation ???
template <>
class Clock<float> {/* float implementation */};


If every implementation shares the same API, you won't "complain about the bloated API".
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Nexus on December 16, 2011, 10:59:50 pm
The sf::Clock class is only one side of the medal. All the interfaces that work with times have to be adapted, too -- for example, sf::Sleep(), sf::RenderWindow::GetFrameTime() or sf::TcpSocket::Connect().

And if Laurent is against a TimeSpan class with its conversions, the candidates are float seconds (like in early SFML 2) or unsigned int milliseconds (like now). Are there interfaces for which float is too unprecise in real life situations? Or did the change to milliseconds mainly happen to allow long time measuring with sf::Clock?

In this case, an option might entail offering two sf::Clock methods. One for daily wark with the practical seconds, and one for rare high-resolution measuring.
Code: [Select]
float      GetElapsedSeconds();      // or just GetElapsedTime()
sf::Uint64 GetElapsedNanoSeconds();
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: luiscubal on December 16, 2011, 11:49:34 pm
Quote
Are there interfaces for which float is too unprecise in real life situations?


That question has already been answered.

Quote
Yes, the problem is that they become less accurate too quickly (apparently it becomes a problem after 2.33 hours).
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Nexus on December 16, 2011, 11:55:12 pm
No, it has not. I explicitely asked for real life situations, because no one will call sf::Sleep() with 2.33 hours. So, at which places in the SFML API apart from sf::Clock itself is the inaccurateness an issue?
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: kolofsson on December 17, 2011, 09:08:15 am
Yes, I think that if we care about the "Simple" in SFML, then the time unit should be 1 second, thus forcing to use a floating point variable. With a millisecond as a unit, if you want to keep all your variables true to the SI units, each time you have to divide the time by 1000.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: TomCatFort on December 18, 2011, 05:44:56 pm
Quote from: "Laurent"

- provide double seconds, but then some people will complain about the lack of exact timestamps, as well as the need to cast to float every calculation involving time (everything gets promoted to double when one of the operands is a double, but SFML uses float everywhere else)

Casting a floating point type to an another one works by loading the data into one of the FPU registers then unloading it into the target type, this takes a little time yes. But if you do calculations they are loaded in those registers anyway and they are stored in the internal format of the FPU (As I know in Intel processor these registers use 80 bit extended precision) so the most drawback of doubles comes from the double memory usage.

I would personally use unsigned 64 bit integer with nanoseconds so SFML can use the best available timer on the platform. It can be simply converted to milliseconds or the desired floating point value if the programmer want something else.

A TimeSpan class could be made that internally use nanoseconds and provides methods to retrieve it in various other formats. The programmer doesn't even need to carry this class around, they just extract the needed value and propagate that in they code.
Code: [Select]

TimeSpan ts = foo.EllapsedTime();
double deltaTime = ts.AsDoubleSecunds();
update(deltaTime);
render(deltaTime);
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on December 18, 2011, 06:00:44 pm
Quote
the most drawback of doubles comes from the double memory usage

I was talking about the required static_cast, which makes the code verbose and ugly. I don't really care about memory or CPU usage ;)

Quote
I would personally use unsigned 64 bit integer with nanoseconds so SFML can use the best available timer on the platform. It can be simply converted to milliseconds or the desired floating point value if the programmer want something else.

I was thinking about something similar, yes. Except that I'd use microseconds, nobody needs nanoseconds.

Quote
A TimeSpan class could be made that internally use nanoseconds and provides methods to retrieve it in various other formats. The programmer doesn't even need to carry this class around, they just extract the needed value and propagate that in they code.

That's more or less what I'm investigating.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: TomCatFort on December 18, 2011, 06:03:22 pm
Quickly wrote a test in java to see how good is the time precision using nanoseconds:
Code: [Select]

final int C = 10;
long[] res = new long[C];
int i = 0;
long tp = System.nanoTime();
while (i < C)
{
    long tn = System.nanoTime();
    if (tn != tp)
    {
        long d = tn - tp;
        tp = tn;
        res[i] = tn;
        i++;
    }
}

for (i = 0; i < C; i++)
    System.out.println(Integer.toString(i) + " = " + res[i]);


This is the result:
Code: [Select]

0 = 181327039326786
1 = 181327039328598
2 = 181327039329503
3 = 181327039330409
4 = 181327039331315
5 = 181327039332221
6 = 181327039332674
7 = 181327039333580
8 = 181327039334485
9 = 181327039335391


It seems that my ordinary laptop can produce far better (although not true nanotime) precision than milliseconds. It is hard to say no to this (personally).
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on December 18, 2011, 06:08:25 pm
Yeah yeah, I already said that I agree for sub-millisecond precision (but microsecond is enough) ;)
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: TomCatFort on December 19, 2011, 05:40:58 pm
Well micro is still a thousand times better then milis! :D
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: The DarK' on December 25, 2011, 09:35:21 pm
Quote from: "TomCatFort"
Well micro is still a thousand times better then milis! :D


Indeed !

However, the last git version doesn't provide the micro.


A possible solution, in order to keep the S of SFML, and deliver the exact nanosecond time : provide 2 functions.

GetElapsedTime() / GetFrameTime(); // In float (second), easy to manipulate. (Sprite.Move(ElapedTime * 20, 0) for example).

GetPreciseElapsedTime()  / GetPreciseFrameTime(); // In nanosecond.


So, everybody is happy  :)
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on December 25, 2011, 10:05:08 pm
I'm currently working on a new API for timing, don't worry ;)
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Mario on January 02, 2012, 09:52:13 pm
Any news/ETA on this? Right now I simply wait for at least 10 ms to pass, before adding up frame times, as a workaround. However I'd prefer going back to a simple "time += timer.GetElapsedTime()" to determine the timeframe I have to update.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on January 02, 2012, 10:54:54 pm
The time API will be updated soon, with a big surprise :lol:
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: OniLinkPlus on January 03, 2012, 12:22:06 am
Quote from: "Laurent"
The time API will be updated soon, with a big surprise :lol:
We can measure time down to the planck scale?!
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on January 03, 2012, 08:01:33 am
Quote
We can measure time down to the planck scale?!

No, you'll have to wait for SFML 172.0 to get this feature.

The big surprise is not about the time API.
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Klaim on January 04, 2012, 01:05:16 am
Use of std::chrono-like code maybe? :D
Title: Switched times to Uint32 milliseconds in SFML 2
Post by: Laurent on January 04, 2012, 07:49:05 am
Quote
Use of std::chrono-like code maybe?

A little bit. But it will remain very simple.
Title: Re: Switched times to Uint32 milliseconds in SFML 2
Post by: Tronic on June 25, 2012, 01:38:39 am
The Time/seconds API should be changed so that it uses double rather than float. As shown previously, float is not precise enough for timing.
Title: Re: Switched times to Uint32 milliseconds in SFML 2
Post by: minirop on June 25, 2012, 02:49:10 am
float is not precise enough for timing.
did you look at the source code ? internally it's a Uint64 (so microseconds) and it's cast to float when asked.
float Time::asSeconds() const
{
    return m_microseconds / 1000000.f;
}
if you really need floating and accuracy, take asMicroseconds and cast it yourself to double.