(in-place) mutable unboxable Ints (was: [GHC] #8158: Replace IO manager's IntMap with a mutable hash table)

Hello Simon, On 2013-08-24 at 08:54:20 +0200, GHC wrote: [...]
Comment (by simonmar):
@bos: GHC has a `FastMutInt` type for this purpose, which is a 1-element mutable unboxed array. I'd be interested to know whether performance differs between this and `ForeignPtr`.
source:ghc/compiler/utils/FastMutInt.lhs
One thing I have been wondering about: ...even with FastMutInt, which is defined as data FastMutInt = FastMutInt (MutableByteArray# RealWorld) If I have a hypothetical data structure, data IoStats = IoStats { sBytesRecv :: {-# UNPACK -#} !FastMutInt , sBytesSent :: {-# UNPACK -#} !FastMutInt , sPacketsRecv :: {-# UNPACK -#} !FastMutInt , sPacketsSent :: {-# UNPACK -#} !FastMutInt } Then (if have the numbers right) each instance of IoStats takes 1 word for the IoStats info-ptr, plus 1 word for each unpacked FastMutInt (which is basically reduces to pointer to a MutableByteArray#), and 3 words for each MutableByteArray# as those result in separate heap objects; that is, a total of 17 words needs to be allocated to keep track of 4 counters. The overhead could be improved somewhat, if I used a 4-word-long MutableByteArray (which would still be a separate heap object and thus result in a single 3-word overhead), but the data declaration would be less expressive IMHO. Would it be possible (w/ reasonable effort) to have an unpackable version of FastMutInt which only has a total storage cost of 1 word (when unpacked), so that IoStats would have a total storage cost of 5 words (and no indirections)? Or even just a new unboxed primitive MutInt# type in the style of Int#, so that FastMutInt would be defined similiar to 'Int' as data FastMutInt = FMI# MutInt# ? PS: The FastMutInt API doesn't seem to provide atomic decrements/increments, what would be needed to provide that? Cheers, hvr

On 24/08/13 08:47, Herbert Valerio Riedel wrote:
Hello Simon,
On 2013-08-24 at 08:54:20 +0200, GHC wrote: [...]
Comment (by simonmar):
@bos: GHC has a `FastMutInt` type for this purpose, which is a 1-element mutable unboxed array. I'd be interested to know whether performance differs between this and `ForeignPtr`.
source:ghc/compiler/utils/FastMutInt.lhs
One thing I have been wondering about:
...even with FastMutInt, which is defined as
data FastMutInt = FastMutInt (MutableByteArray# RealWorld)
If I have a hypothetical data structure,
data IoStats = IoStats { sBytesRecv :: {-# UNPACK -#} !FastMutInt , sBytesSent :: {-# UNPACK -#} !FastMutInt , sPacketsRecv :: {-# UNPACK -#} !FastMutInt , sPacketsSent :: {-# UNPACK -#} !FastMutInt }
Then (if have the numbers right) each instance of IoStats takes 1 word for the IoStats info-ptr, plus 1 word for each unpacked FastMutInt (which is basically reduces to pointer to a MutableByteArray#), and 3 words for each MutableByteArray# as those result in separate heap objects; that is, a total of 17 words needs to be allocated to keep track of 4 counters. The overhead could be improved somewhat, if I used a 4-word-long MutableByteArray (which would still be a separate heap object and thus result in a single 3-word overhead), but the data declaration would be less expressive IMHO.
Would it be possible (w/ reasonable effort) to have an unpackable version of FastMutInt which only has a total storage cost of 1 word (when unpacked), so that IoStats would have a total storage cost of 5 words (and no indirections)?
Or even just a new unboxed primitive MutInt# type in the style of Int#, so that FastMutInt would be defined similiar to 'Int' as
data FastMutInt = FMI# MutInt#
?
This is not like anything else we have: it's neither a primitive value that can be passed around, like Int#, nor is it an object on the heap with identity, like MutVar#. What does it mean to pass a MutInt# value around? Presumably the intention is for it to be passed by reference somehow, but a reference to what? Mutable objects have identity - you have to explicitly create them with a State#, so that we don't accidentally create zero or two or some other number of them. So if a mutable object were to be unpacked in a constructor field, its parent object would need to somehow assume the responsibility of being the object with identity. I just don't know a good way to fit something like this into GHC (but that doesn't mean it's impossible!).
PS: The FastMutInt API doesn't seem to provide atomic decrements/increments, what would be needed to provide that?
Just some new primops. Cheers, Simon
participants (2)
-
Herbert Valerio Riedel
-
Simon Marlow