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

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

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

Herbert Valerio Riedel
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



Reply | Threaded
Open this post in threaded view
|

(in-place) mutable unboxable Ints

Simon Marlow-7
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