Stop using "Int" for microsecond delays in "base"

The "base" library has the "threadDelay" primitive, which takes an Int argument in microseconds. Unfortunately this means that the longest delay you can get on a 32 bit machine with GHC is just under 36 minutes (2^31 uSec), and a hypothetical compiler that only used 30 bit integers (as per the standard) would get under 10 minutes. It is a bit tricky to write general-purpose libraries with this. I think that there should be a type Delay = Int64 declaration, and that threadDelay and related functions should take that as an argument type. Paul.

Paul Johnson schrieb:
The "base" library has the "threadDelay" primitive, which takes an Int argument in microseconds. Unfortunately this means that the longest delay you can get on a 32 bit machine with GHC is just under 36 minutes (2^31 uSec), and a hypothetical compiler that only used 30 bit integers (as per the standard) would get under 10 minutes. It is a bit tricky to write general-purpose libraries with this.
Isn't it just a waitLong :: Integer -> IO () waitLong n = let stdDelay = 10^7 (q,r) = divMod n stdDelay in replicateM_ (fromInteger q) (threadDelay (fromInteger stdDelay)) >> threadDelay (fromInteger r)

On 26 March 2011 20:16, Henning Thielemann
Paul Johnson schrieb:
The "base" library has the "threadDelay" primitive, which takes an Int argument in microseconds. Unfortunately this means that the longest delay you can get on a 32 bit machine with GHC is just under 36 minutes (2^31 uSec), and a hypothetical compiler that only used 30 bit integers (as per the standard) would get under 10 minutes. It is a bit tricky to write general-purpose libraries with this.
Isn't it just a
waitLong :: Integer -> IO () waitLong n = let stdDelay = 10^7 (q,r) = divMod n stdDelay in replicateM_ (fromInteger q) (threadDelay (fromInteger stdDelay)) >> threadDelay (fromInteger r)
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
Or take the one from concurrent-extra: http://hackage.haskell.org/packages/archive/concurrent-extra/0.6.0.1/doc/htm... However, I agree that it would be nice to reduce the need for these functions by having a larger sized Delay type. I don't think it's that hard to change. When using the threaded rts the threadDelay function is defined by the GHC event manager which stores time in seconds since the epoch (1970) in a Double. It gets the current time from the gettimeofday function[1]. When not using the threaded rts the threadDelay function is defined inside the rts. I'm not sure how hard it is to change that one. Bas [1] http://linux.die.net/man/2/gettimeofday

On Sat, Mar 26, 2011 at 3:44 PM, Bas van Dijk
Or take the one from concurrent-extra:
http://hackage.haskell.org/packages/archive/concurrent-extra/0.6.0.1/doc/htm...
I'll admit the main problem that I have with the threadDelay in concurrent-extra is the gratuitously unicode source file. I wound up having to reimplement it inside a library of mine to avoid adding a dependency on that extension and the unrelated dependency on stm. =( (Technically, I implemented it directly first, then found concurrent-extra and wasn't willing to refactor to use yours as a result of those.) You are of course free to implement things as you see fit, but little things like that do impact adoption. -Edward

On 27 March 2011 07:59, Edward Kmett
On Sat, Mar 26, 2011 at 3:44 PM, Bas van Dijk
wrote: Or take the one from concurrent-extra:
http://hackage.haskell.org/packages/archive/concurrent-extra/0.6.0.1/doc/htm...
I'll admit the main problem that I have with the threadDelay in concurrent-extra is the gratuitously unicode source file. I wound up having to reimplement it inside a library of mine to avoid adding a dependency on that extension and the unrelated dependency on stm. =( (Technically, I implemented it directly first, then found concurrent-extra and wasn't willing to refactor to use yours as a result of those.) You are of course free to implement things as you see fit, but little things like that do impact adoption. -Edward
Note that 'delay' uses the 'threadDelay' function internally. AFAIK, this function is only supported in GHC. So to build the module you need GHC anyway which already supports the UnicodeSyntax language extension (since 6.12.1). I do agree that the dependency on stm is unfortunate. I will see if I can put the modules Control.Concurrent.Thread.Delay and Control.Concurrent.Timeout into a separate package. Any naming suggestions? unbounded-delays or something? Bas

Am 27.03.2011 11:17, schrieb Bas van Dijk:
On 27 March 2011 07:59, Edward Kmett
wrote: On Sat, Mar 26, 2011 at 3:44 PM, Bas van Dijk
wrote: Or take the one from concurrent-extra:
http://hackage.haskell.org/packages/archive/concurrent-extra/0.6.0.1/doc/htm...
I'll admit the main problem that I have with the threadDelay in concurrent-extra is the gratuitously unicode source file. I wound up having to reimplement it inside a library of mine to avoid adding a dependency on that extension and the unrelated dependency on stm. =( (Technically, I implemented it directly first, then found concurrent-extra and wasn't willing to refactor to use yours as a result of those.) You are of course free to implement things as you see fit, but little things like that do impact adoption. -Edward
Note that 'delay' uses the 'threadDelay' function internally. AFAIK, this function is only supported in GHC. So to build the module you need GHC anyway which already supports the UnicodeSyntax language extension (since 6.12.1).
With this argument you should use many more ghc extensions. The dependency on base-unicode-symbols is unfortunate, too! If this dependency was supposed to advertise your base-unicode-symbols package I consider this dependency as spam. Basic coding style should ASCII only. Cheers Christian
I do agree that the dependency on stm is unfortunate. I will see if I can put the modules Control.Concurrent.Thread.Delay and Control.Concurrent.Timeout into a separate package. Any naming suggestions? unbounded-delays or something?
Bas

On 26/03/11 19:16, Henning Thielemann wrote:
Paul Johnson schrieb:
The "base" library has the "threadDelay" primitive, which takes an Int argument in microseconds. Unfortunately this means that the longest delay you can get on a 32 bit machine with GHC is just under 36 minutes (2^31 uSec), and a hypothetical compiler that only used 30 bit integers (as per the standard) would get under 10 minutes. It is a bit tricky to write general-purpose libraries with this. Isn't it just a
waitLong :: Integer -> IO () waitLong n = let stdDelay = 10^7 (q,r) = divMod n stdDelay in replicateM_ (fromInteger q) (threadDelay (fromInteger stdDelay)) >> threadDelay (fromInteger r)
True, but: 1: Low level stuff like this belongs in the library, not the application. I'm writing Haskell, not C! 2: I actually want to use timeout, which inherits the same limitation. Right now it looks like the simplest thing to do would be to copy the existing timeout code but use "waitLong" instead of "wait". But I shouldn't have to do that. Paul.

On 27 March 2011 11:15, Paul Johnson
2: I actually want to use timeout, which inherits the same limitation. Right now it looks like the simplest thing to do would be to copy the existing timeout code but use "waitLong" instead of "wait". But I shouldn't have to do that.
concurrent-extra to the rescue again: http://hackage.haskell.org/packages/archive/concurrent-extra/0.6.0.1/doc/htm... But note that I may move this to its own package soon (as in later today). Bas

On 27 March 2011 11:21, Bas van Dijk
But note that I may move this to its own package soon (as in later today).
Done: http://code.haskell.org/~basvandijk/code/unbounded-delays/ I plan to release it this evening or tomorrow. Bas

Thanks!
On Sun, Mar 27, 2011 at 8:06 AM, Bas van Dijk
On 27 March 2011 11:21, Bas van Dijk
wrote: But note that I may move this to its own package soon (as in later today).
Done: http://code.haskell.org/~basvandijk/code/unbounded-delays/
I plan to release it this evening or tomorrow.
Bas
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

I just released the package:
http://hackage.haskell.org/package/unbounded-delays
I kept UnicodeSyntax but dropped the dependency on
base-unicode-symbols. I hope this is a satisfying compromise.
I also made a new major release of concurrent-extra that removes the
respected modules:
http://hackage.haskell.org/package/concurrent-extra-0.7
This release also supports (but doesn't require) the new cabal
test-suite feature. To test the package simply:
$ cabal configure --enable-tests
$ cabal build
now run the test suite either manually (and get nice colourful output) using:
$ dist/build/test-concurrent-extra/test-concurrent-extra
or using cabal (and get only a summary of the test output):
$ cabal test
Regards,
Bas
On 28 March 2011 20:01, Edward Kmett
Thanks!
On Sun, Mar 27, 2011 at 8:06 AM, Bas van Dijk
wrote: On 27 March 2011 11:21, Bas van Dijk
wrote: But note that I may move this to its own package soon (as in later today).
Done: http://code.haskell.org/~basvandijk/code/unbounded-delays/
I plan to release it this evening or tomorrow.
Bas
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

I kept UnicodeSyntax but dropped the dependency on base-unicode-symbols. I hope this is a satisfying compromise.
I don't mind, myself, but lots of people are rather picky about being haskell<year>-compliant. Do you intend to submit this for general adoption or is it just a stopgap until the base threadDelay is improved? Thanks, Dan

On 29 March 2011 00:56, Daniel Peebles
I kept UnicodeSyntax but dropped the dependency on base-unicode-symbols. I hope this is a satisfying compromise.
I don't mind, myself, but lots of people are rather picky about being haskell<year>-compliant. Do you intend to submit this for general adoption or is it just a stopgap until the base threadDelay is improved?
When the base threadDelay and timeout switch to Integer based periods I will of course deprecate this package. Until that time people can use this package. Bas

Am Samstag, den 26.03.2011, 17:20 +0000 schrieb Paul Johnson:
The "base" library has the "threadDelay" primitive, which takes an Int argument in microseconds. Unfortunately this means that the longest delay you can get on a 32 bit machine with GHC is just under 36 minutes (2^31 uSec), and a hypothetical compiler that only used 30 bit integers (as per the standard) would get under 10 minutes. It is a bit tricky to write general-purpose libraries with this. I think that there should be a
type Delay = Int64
declaration, and that threadDelay and related functions should take that as an argument type.
Paul.
Maybe, we should stop using Int altogether. Why not use Integer if we want integers, and try to implement Integer and its operations more efficiently? Int8, Int16, Int32, and Int64 are good when doing system programming, CInt is good when interfacing with C, but what is Int good for? Best wishes, Wolfgang

On Wednesday 30 March 2011 14:31:33, Wolfgang Jeltsch wrote:
Maybe, we should stop using Int altogether. Why not use Integer if we want integers, and try to implement Integer and its operations more efficiently?
Even getting near the performance of GMP with its probably hundreds of man- years of optimisation gone in is hard, beating it is a formidable task. Or were you thinking of making the calls to GMP faster? If that could be done, that would be very nice.
Int8, Int16, Int32, and Int64 are good when doing system programming, CInt is good when interfacing with C, but what is Int good for?
Speed. If you have computations you know won't overflow, it's good to have the native-sized Int and need not throttle things on 64-bit systems by using Int32 or on 32-bit systems by using Int64. But in general, I agree that it would be good to use Integer instead of Int more often. Cheers, Daniel

Maybe we could use something like stdint.h [1]. You could use a type
like int_fast16_t to ensure a minimum width of 16 while still getting
the benefits of native ints (if possible).
1 - http://en.wikipedia.org/wiki/Stdint.h
On 30 March 2011 15:20, Daniel Fischer
On Wednesday 30 March 2011 14:31:33, Wolfgang Jeltsch wrote:
Maybe, we should stop using Int altogether. Why not use Integer if we want integers, and try to implement Integer and its operations more efficiently?
Even getting near the performance of GMP with its probably hundreds of man- years of optimisation gone in is hard, beating it is a formidable task. Or were you thinking of making the calls to GMP faster? If that could be done, that would be very nice.
Int8, Int16, Int32, and Int64 are good when doing system programming, CInt is good when interfacing with C, but what is Int good for?
Speed. If you have computations you know won't overflow, it's good to have the native-sized Int and need not throttle things on 64-bit systems by using Int32 or on 32-bit systems by using Int64.
But in general, I agree that it would be good to use Integer instead of Int more often.
Cheers, Daniel

Maybe, we should stop using Int altogether. Why not use Integer if we want integers, and try to implement Integer and its operations more efficiently? Int8, Int16, Int32, and Int64 are good when doing system programming, CInt is good when interfacing with C, but what is Int good for?
It's good for big data structures since it can be unpacked into the constructor. I've seen space usage go down by 1/3 after an Integer -> Int switch. Integer is a sum type so there's an extra two words of overhead (if not mistaken, one for the tag, and one for the indirection since it can't unpack).

On Wed, Mar 30, 2011 at 7:56 PM, Evan Laforge
It's good for big data structures since it can be unpacked into the constructor. I've seen space usage go down by 1/3 after an Integer -> Int switch. Integer is a sum type so there's an extra two words of overhead (if not mistaken, one for the tag, and one for the indirection since it can't unpack).
Yes. Integer is terrible for performance.

On Wed, Mar 30, 2011 at 8:28 PM, Max Bolingbroke
On 30 March 2011 19:00, Johan Tibell
wrote: Yes. Integer is terrible for performance.
But in this case it's unlikely to make a difference because the whole point of threadDelay is to slow the program down, so who cares if we deref one more pointer :-)
Sure. In this particular case. What do we do if the user passes some humongous number to threadDelay? The underlying syscall doesn't support it, so I guess we would have to call that syscall repeatedly.

Am Mittwoch, den 30.03.2011, 20:00 +0200 schrieb Johan Tibell:
On Wed, Mar 30, 2011 at 7:56 PM, Evan Laforge
wrote: It's good for big data structures since it can be unpacked into the constructor. I've seen space usage go down by 1/3 after an Integer -> Int switch. Integer is a sum type so there's an extra two words of overhead (if not mistaken, one for the tag, and one for the indirection since it can't unpack).
Yes. Integer is terrible for performance.
Can’t Integer be implemented in a more efficient way that it’s done currently? Best wishes, Wolfgang

On Wednesday 30 March 2011 20:47:37, Wolfgang Jeltsch wrote:
Can’t Integer be implemented in a more efficient way that it’s done currently?
Theoretically, sure. Practically, everything above a minor speedup would be very hard, I think. And, as Johan mentioned, Integers can't be unpacked, I don't see how that could be achieved, so for IntMap and the like, performance would be drastically worse even if Integer manipulation itself got significantly faster.

Of course, in this particular case, worrying about the overhead of manipulating an Integer when you are in the process of jumping through the hoops to put your thread to *sleep* is somewhat silly. ;) In general though, using Ints by default is a reasonable performance compromise. -Edward On Wed, Mar 30, 2011 at 2:59 PM, Daniel Fischer < daniel.is.fischer@googlemail.com> wrote:
On Wednesday 30 March 2011 20:47:37, Wolfgang Jeltsch wrote:
Can’t Integer be implemented in a more efficient way that it’s done currently?
Theoretically, sure. Practically, everything above a minor speedup would be very hard, I think. And, as Johan mentioned, Integers can't be unpacked, I don't see how that could be achieved, so for IntMap and the like, performance would be drastically worse even if Integer manipulation itself got significantly faster.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Wed, Mar 30, 2011 at 12:15 PM, Edward Kmett
Of course, in this particular case, worrying about the overhead of manipulating an Integer when you are in the process of jumping through the hoops to put your thread to sleep is somewhat silly. ;)
Yes, but that's only because the conversation has gotten off track. I was answering the question "are Ints good for anything beyond the FFI?" which was raised as a result of the thread delay thing. Sorry about that. Integer sounds reasonable enough for threadDelay.

2011/3/30 Daniel Fischer
On Wednesday 30 March 2011 20:47:37, Wolfgang Jeltsch wrote:
Can’t Integer be implemented in a more efficient way that it’s done currently?
Theoretically, sure. Practically, everything above a minor speedup would be very hard, I think. And, as Johan mentioned, Integers can't be unpacked, I don't see how that could be achieved, so for IntMap and the like, performance would be drastically worse even if Integer manipulation itself got significantly faster.
I'm not sure, if an IntegerMap would be that much slower for Int-sized Integers. An optimized variant of the following trie-like data structure data IntegerMap v = IntegerMap (IntMap v) (M.Map Integer v) -- better: also use a trie-based impl. for M.Map Integer v should do the trick with a small constant overhead for Int-sized Integers. -Simon

On 3/30/11 2:00 PM, Johan Tibell wrote:
On Wed, Mar 30, 2011 at 7:56 PM, Evan Laforge
wrote: It's good for big data structures since it can be unpacked into the constructor. I've seen space usage go down by 1/3 after an Integer -> Int switch. Integer is a sum type so there's an extra two words of overhead (if not mistaken, one for the tag, and one for the indirection since it can't unpack).
Yes. Integer is terrible for performance.
This makes me wonder, though, whether it'd be worthwhile to: (A) make a special case allowing unpacking of Integers (e.g., by storing the constructor tag adjacent to the payload, ala PiSigma), or (B) to simplify the implementation to data Integer = J# Int# ByteArray# where the current (S# (x::Int#)) is implemented by (J# x nullPtr) or whatever the equivalent is for ByteArray#s ---Hackage doesn't want to show me the source for what a ByteArray# actually is implemented as... I could see the PiSigma implementation of A causing a lot of ruckus throughout the runtime, which would be a good reason to rule that out. But I can't see why B hasn't been done ---even if just as an implementation of A! It increases the memory footprint for Int-sized Integers, which is unfortunate, but the check for null should be no more expensive than the case match, and it opens the way for unpacking and related optimizations (which would offset or reverse the memory footprint differences). -- Live well, ~wren

On 31 March 2011 10:55, wren ng thornton
On 3/30/11 2:00 PM, Johan Tibell wrote:
On Wed, Mar 30, 2011 at 7:56 PM, Evan Laforge
wrote: It's good for big data structures since it can be unpacked into the constructor. I've seen space usage go down by 1/3 after an Integer -> Int switch. Integer is a sum type so there's an extra two words of overhead (if not mistaken, one for the tag, and one for the indirection since it can't unpack).
Yes. Integer is terrible for performance.
This makes me wonder, though, whether it'd be worthwhile to:
(A) make a special case allowing unpacking of Integers (e.g., by storing the constructor tag adjacent to the payload, ala PiSigma), or
(B) to simplify the implementation to
data Integer = J# Int# ByteArray#
where the current (S# (x::Int#)) is implemented by (J# x nullPtr) or whatever the equivalent is for ByteArray#s ---Hackage doesn't want to show me the source for what a ByteArray# actually is implemented as...
I could see the PiSigma implementation of A causing a lot of ruckus throughout the runtime, which would be a good reason to rule that out.
But I can't see why B hasn't been done ---even if just as an implementation of A! It increases the memory footprint for Int-sized Integers, which is unfortunate, but the check for null should be no more expensive than the case match, and it opens the way for unpacking and related optimizations (which would offset or reverse the memory footprint differences).
-- Live well, ~wren
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
You may also want to read section 3.3 of: http://hackage.haskell.org/trac/ghc/wiki/ReplacingGMPNotes (note though that this document is more than 2 years old) Bas

ByteArray# is a GHC primitive. There is no Haskell code for it unless you
want to look at the compiler implementation. It also doesn't have a
null-like value, but I guess you could use an empty one?
Dan
On Thu, Mar 31, 2011 at 4:55 AM, wren ng thornton
On 3/30/11 2:00 PM, Johan Tibell wrote:
On Wed, Mar 30, 2011 at 7:56 PM, Evan Laforge
wrote: It's good for big data structures since it can be unpacked into the constructor. I've seen space usage go down by 1/3 after an Integer -> Int switch. Integer is a sum type so there's an extra two words of overhead (if not mistaken, one for the tag, and one for the indirection since it can't unpack).
Yes. Integer is terrible for performance.
This makes me wonder, though, whether it'd be worthwhile to:
(A) make a special case allowing unpacking of Integers (e.g., by storing the constructor tag adjacent to the payload, ala PiSigma), or
(B) to simplify the implementation to
data Integer = J# Int# ByteArray#
where the current (S# (x::Int#)) is implemented by (J# x nullPtr) or whatever the equivalent is for ByteArray#s ---Hackage doesn't want to show me the source for what a ByteArray# actually is implemented as...
I could see the PiSigma implementation of A causing a lot of ruckus throughout the runtime, which would be a good reason to rule that out.
But I can't see why B hasn't been done ---even if just as an implementation of A! It increases the memory footprint for Int-sized Integers, which is unfortunate, but the check for null should be no more expensive than the case match, and it opens the way for unpacking and related optimizations (which would offset or reverse the memory footprint differences).
-- Live well, ~wren
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Paul Johnson
The "base" library has the "threadDelay" primitive, which takes an Int argument in microseconds.
I always end up with a wrapper around it, taking a NominalDiffTime; I could never be sure whether threadDelay interpreted its argument as milli-/micro-/nano-seconds without looking it up. For lack of Data.Time in base, how about Data.Fixed.Pico? Cheers, /Liyang

I always end up with a wrapper around it, taking a NominalDiffTime; I could never be sure whether threadDelay interpreted its argument as milli-/micro-/nano-seconds without looking it up.
I too always end up with a wrapper, but my wrapper takes a Double, which is in seconds. Seconds are easy, and a Double means that you can specify ridiculously long intervals, and for short intervals you have high precision. I find it much easier to write sleep 5, when I want to sleep for 5 seconds, than putting in some multiplication factor. Thanks, Neil

On Wed, Apr 20, 2011 at 22:31, Neil Mitchell
I always end up with a wrapper around it, taking a NominalDiffTime; I could never be sure whether threadDelay interpreted its argument as milli-/micro-/nano-seconds without looking it up.
I too always end up with a wrapper, but my wrapper takes a Double, which is in seconds. Seconds are easy, and a Double means that you can specify ridiculously long intervals, and for short intervals you have high precision. I find it much easier to write sleep 5, when I want to sleep for 5 seconds, than putting in some multiplication factor.
Note that NominalDiffTime has all the necessary instances to able to do the same. I.e. (5 :: NominalDiffTime), (5.123 :: NominalDiffTime), or (10^100 :: NominalDiffTime). These numbers are also interpreted as seconds, with a precision up to 10^-12. Erik

The problem that I have with NominalDiffTime in general is that it is
impossible to work with efficiently. There is no mechanism for extracting
the integral number of picoseconds represented without round tripping
unnecessarily through Rational. This isn't a problem for something like
Delay, but I hesitate to push for increasing its adoption.
For general purpose time manipulation where I need to manipulate a lot of
these kinds of deltas such as in FRP, I've had to abandon the time API
entirely because of the overhead. =( I appreciate Ashley's desire to retain
an opaque API so that he can freely change the internal implementation, but
such opacity comes at a cost of suitability in many cases.
More importantly, there is also a layering problem. NominalDiffTime is in
'time', which depends on 'base' and threadDelay is in 'base'.
-Edward
On Thu, Apr 21, 2011 at 4:01 AM, Erik Hesselink
On Wed, Apr 20, 2011 at 22:31, Neil Mitchell
wrote: I always end up with a wrapper around it, taking a NominalDiffTime; I could never be sure whether threadDelay interpreted its argument as milli-/micro-/nano-seconds without looking it up.
I too always end up with a wrapper, but my wrapper takes a Double, which is in seconds. Seconds are easy, and a Double means that you can specify ridiculously long intervals, and for short intervals you have high precision. I find it much easier to write sleep 5, when I want to sleep for 5 seconds, than putting in some multiplication factor.
Note that NominalDiffTime has all the necessary instances to able to do the same. I.e. (5 :: NominalDiffTime), (5.123 :: NominalDiffTime), or (10^100 :: NominalDiffTime). These numbers are also interpreted as seconds, with a precision up to 10^-12.
Erik
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
participants (17)
-
Bas van Dijk
-
Christian Maeder
-
Daniel Fischer
-
Daniel Peebles
-
Edward Kmett
-
Erik Hesselink
-
Evan Laforge
-
Henning Thielemann
-
Johan Tibell
-
Liyang HU
-
Max Bolingbroke
-
Neil Mitchell
-
Paul Johnson
-
Roel van Dijk
-
Simon Meier
-
Wolfgang Jeltsch
-
wren ng thornton