[GHC] #14900: Calling isByteArrayPinned# on compact ByteArray

GHC ghc-devs at haskell.org
Thu Mar 8 01:47:10 UTC 2018


#14900: Calling isByteArrayPinned# on compact ByteArray
-------------------------------------+-------------------------------------
           Reporter:  andrewthad     |             Owner:  (none)
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:  8.2.2
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 The documentation explaining the relationship between pinnedness and
 compact regions is incomplete. From `Data.Compact`:

 > Pinned ByteArray# objects cannot be compacted. This is for a good
 reason: the memory is pinned so that it can be referenced by address (the
 address might be stored in a C data structure, for example), so we can't
 make a copy of it to store in the Compact.

 This is half-way true since it only considers one a the ways in which the
 GHC runtime tracks the pinnedness of an object. From experimenting with
 compact regions, it seems like there are two different notions of
 pinnedness:

 1. Did the user explicitly ask for the `ByteArray` to be pinned?
 2. Is the `ByteArray` pinned?

 If (1) is true, then (2) must always be true, but if (1) is false, then
 could be true or false. `ByteArray`s over 3KB are pinned, and `ByteArray`s
 under 3KB are not (or somewhere around that number).

 With that background information in place, here's the scenario I've
 encountered:

 {{{
 {-# LANGUAGE MagicHash #-}

 import Data.Primitive
 import Data.Compact
 import GHC.Int
 import GHC.Prim

 main :: IO ()
 main = do
   ByteArray arr1# <- fmap getCompact $ newByteArray 65000 >>=
 unsafeFreezeByteArray >>= compact
   ByteArray arr2# <- newByteArray 65000 >>= unsafeFreezeByteArray
   print (I# (isByteArrayPinned# arr1#))
   print (I# (isByteArrayPinned# arr2#))
   putStrLn "Finished"
 }}}

 When compiled and run, this gives:

 {{{
 0
 1
 Finished
 }}}

 We can see that the 65KiB `ByteArray` that was not compacted let's the
 user know that it is pinned. The compacted `ByteArray` claims to not be
 pinned, but this is not true. The docs in `Data.Compact` claim:

 > Data in a compact doesn't ever move, so compacting data is also a way to
 pin arbitrary data structures in memory.

 I propose that the behavior of `compact` be modified to accurately convey
 the pinnedness of the `ByteArray`s that copies. This would mean that even
 small, previously unpinned, `ByteArray`s would also be designated as
 pinned. It's a small change, but it makes the information the runtime
 gives us more accurate. This is occasionally handy when dealing with the
 FFI.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14900>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list