@@ -18,7 +18,6 @@ module Streamly.Internal.Data.Array.Unboxed.Mut.Type
1818 -- $arrayNotes
1919 Array (..)
2020 , MutableByteArray
21− , nilArrayContents
2221 , touch
2322 , pin
2423 , unpin
@@ -28,11 +27,11 @@ module Streamly.Internal.Data.Array.Unboxed.Mut.Type
2827 , nil
2928
3029 -- *** Uninitialized Arrays
31− , newArray
32− , newPinnedArrayBytes
33− , newArrayAligned
30+ , newPinned
31+ , newPinnedBytes
32+ , newAlignedPinned
33+ , new
3434 , newArrayWith
35− , newAlignedArrayContents
3635
3736 -- *** Initialized Arrays
3837 , withNewArrayUnsafe
@@ -234,9 +233,11 @@ import Streamly.Internal.Data.Unboxed
234233 , touch
235234 )
236235import GHC.Base
237− ( IO(..), byteArrayContents#
238− , Int(..), newAlignedPinnedByteArray#
239− , copyMutableByteArray#, compareByteArrays#
236+ ( IO(..)
237+ , Int(..)
238+ , byteArrayContents#
239+ , compareByteArrays#
240+ , copyMutableByteArray#
240241 )
241242import GHC.Base (noinline)
242243import GHC.Exts (unsafeCoerce#)
@@ -248,7 +249,6 @@ import Streamly.Internal.Data.Stream.Type (Stream)
248249import Streamly.Internal.Data.SVar.Type (adaptState, defState)
249250import Streamly.Internal.Data.Unfold.Type (Unfold(..))
250251import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
251−import System.IO.Unsafe (unsafePerformIO)
252252
253253import qualified Streamly.Internal.Data.Fold.Type as FL
254254import qualified Streamly.Internal.Data.Producer as Producer
@@ -385,6 +385,8 @@ unpin arr@Array{..} = do
385385-- Alignment must be greater than or equal to machine word size and a power of
386386-- 2.
387387--
388+-- Alignment is ignored if the allocator allocates unpinned memory.
389+--
388390-- /Pre-release/
389391{-# INLINE newArrayWith #-}
390392newArrayWith :: forall m a. (MonadIO m, Unboxed a)
@@ -399,61 +401,25 @@ newArrayWith alloc alignSize count = do
399401 , arrBound = size
400402 }
401403
402−-- XXX Move this to Unboxed and rename this to newPinnedAlignedBytes?
403−-- XXX Similarly have newUnpinnedBytes
404−{-# INLINE newAlignedArrayContents #-}
405−newAlignedArrayContents :: Int -> Int -> IO (MutableByteArray a)
406−newAlignedArrayContents nbytes _align | nbytes < 0 =
407− errorWithoutStackTrace "newAlignedArrayContents: size must be >= 0"
408−newAlignedArrayContents (I# nbytes) (I# align) = IO $ \s ->
409− case newAlignedPinnedByteArray# nbytes align s of
410− (# s', mbarr# #) ->
411− let c = MutableByteArray mbarr#
412− in (# s', c #)
413−
414−{-# NOINLINE nilArrayContents #-}
415−nilArrayContents :: MutableByteArray a
416−nilArrayContents =
417− unsafePerformIO $ newAlignedArrayContents 0 0
418−
419404nil ::
420405#ifdef DEVBUILD
421406 Unboxed a =>
422407#endif
423408 Array a
424−nil = Array nilArrayContents 0 0 0
425−
426−-- | Like 'newArrayWith' but using an allocator that aligns the memory to the
427−-- alignment dictated by the 'Unboxed' instance of the type.
428−--
429−-- /Internal/
430−{-# INLINE newArrayAligned #-}
431−newArrayAligned :: (MonadIO m, Unboxed a) => Int -> Int -> m (Array a)
432−newArrayAligned = newArrayWith (\s a -> liftIO $ newAlignedArrayContents s a)
409+nil = Array Unboxed.nil 0 0 0
433410
434−-- XXX Intead of newArray, make newPinnedArray and newUnpinnedArray. Make it
435−-- more explicit.
436−-- XXX can unaligned allocation be more efficient when alignment is not needed?
437−--
438−-- | Allocates an empty array that can hold 'count' items. The memory of the
439−-- array is uninitialized and the allocation is aligned as per the 'Unboxed'
440−-- instance of the type.
441−--
442−-- /Pre-release/
443−{-# INLINE newArray #-}
444−newArray :: forall m a. (MonadIO m, Unboxed a) => Int -> m (Array a)
445−newArray = newArrayAligned (alignment (undefined :: a))
446411
447412-- | Allocates a pinned empty array that can hold 'count' items. The memory of
448413-- the array is uninitialized and the allocation is aligned as per the
449414-- 'Unboxed' instance of the type.
450415--
451416-- /Pre-release/
452−{-# INLINE newPinnedArrayBytes #-}
453−newPinnedArrayBytes :: forall m a. (MonadIO m, Unboxed a) => Int -> m (Array a)
454−newPinnedArrayBytes bytes = do
417+{-# INLINE newPinnedBytes #-}
418+newPinnedBytes :: forall m a. (MonadIO m, Unboxed a) => Int -> m (Array a)
419+newPinnedBytes bytes = do
455420 contents <-
456− liftIO $ newAlignedArrayContents bytes (alignment (undefined :: a))
421+ liftIO
422+ $ Unboxed.newAlignedPinnedBytes bytes (alignment (undefined :: a))
457423 return $ Array
458424 { arrContents = contents
459425 , arrStart = 0
@@ -461,6 +427,37 @@ newPinnedArrayBytes bytes = do
461427 , arrBound = bytes
462428 }
463429
430+-- | Like 'newArrayWith' but using an allocator is a pinned memory allocator and
431+-- the alignment is dictated by the 'Unboxed' instance of the type.
432+--
433+-- /Internal/
434+{-# INLINE newAlignedPinned #-}
435+newAlignedPinned :: (MonadIO m, Unboxed a) => Int -> Int -> m (Array a)
436+newAlignedPinned =
437+ newArrayWith (\s a -> liftIO $ Unboxed.newAlignedPinnedBytes s a)
438+
439+-- XXX can unaligned allocation be more efficient when alignment is not needed?
440+--
441+-- | Allocates an empty pinned array that can hold 'count' items. The memory of
442+-- the array is uninitialized and the allocation is aligned as per the 'Unboxed'
443+-- instance of the type.
444+--
445+-- /Pre-release/
446+{-# INLINE newPinned #-}
447+newPinned :: forall m a. (MonadIO m, Unboxed a) => Int -> m (Array a)
448+newPinned = newAlignedPinned (alignment (undefined :: a))
449+
450+-- | Allocates an empty unpinned array that can hold 'count' items. The memory
451+-- of the array is uninitialized.
452+--
453+-- /Pre-release/
454+{-# INLINE new #-}
455+new :: (MonadIO m, Unboxed a) => Int -> m (Array a)
456+new =
457+ newArrayWith
458+ (\s _ -> liftIO $ Unboxed.newUnpinnedBytes s)
459+ (error "new: alignment is not used in unpinned arrays.")
460+
464461-- | Allocate an Array of the given size and run an IO action passing the array
465462-- start pointer.
466463--
@@ -469,7 +466,7 @@ newPinnedArrayBytes bytes = do
469466withNewArrayUnsafe ::
470467 (MonadIO m, Unboxed a) => Int -> (Ptr a -> m ()) -> m (Array a)
471468withNewArrayUnsafe count f = do
472− arr <- newArray count
469+ arr <- newPinned count
473470 asPtrUnsafe arr
474471 $ \p -> f p >> return arr
475472
@@ -719,7 +716,7 @@ reallocAligned elemSize alignSize newCapacityInBytes Array{..} = do
719716
720717 -- Allocate new array
721718 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
722− contents <- newAlignedArrayContents newCapMaxInBytes alignSize
719+ contents <- Unboxed.newAlignedPinnedBytes newCapMaxInBytes alignSize
723720 let !(MutableByteArray mbarrFrom#) = arrContents
724721 !(MutableByteArray mbarrTo#) = contents
725722
@@ -1310,7 +1307,7 @@ arraysOf n (D.Stream step state) =
13101307 error $ "Streamly.Internal.Data.Array.Unboxed.Mut.Type.arraysOf: "
13111308 ++ "the size of arrays [" ++ show n
13121309 ++ "] must be a natural number"
1313− Array contents start end bound <- liftIO $ newArray n
1310+ Array contents start end bound <- liftIO $ newPinned n
13141311 return $ D.Skip (GroupBuffer st contents start end bound)
13151312
13161313 step' gst (GroupBuffer st contents start end bound) = do
@@ -1749,13 +1746,13 @@ writeNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
17491746-- conditional in the step function blocks fusion causing 10x performance
17501747-- slowdown.
17511748--
1752−-- >>> writeNUnsafe = Array.writeNWithUnsafe Array.newArray
1749+-- >>> writeNUnsafe = Array.writeNWithUnsafe Array.newPinned
17531750--
17541751-- @since 0.7.0
17551752{-# INLINE_NORMAL writeNUnsafe #-}
17561753writeNUnsafe :: forall m a. (MonadIO m, Unboxed a)
17571754 => Int -> Fold m a (Array a)
1758−writeNUnsafe = writeNWithUnsafe newArray
1755+writeNUnsafe = writeNWithUnsafe newPinned
17591756
17601757-- | @writeNWith alloc n@ folds a maximum of @n@ elements into an array
17611758-- allocated using the @alloc@ function.
@@ -1771,14 +1768,14 @@ writeNWith alloc n = FL.take n (writeNWithUnsafe alloc n)
17711768-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
17721769-- 'Array'.
17731770--
1774−-- >>> writeN = Array.writeNWith Array.newArray
1771+-- >>> writeN = Array.writeNWith Array.newPinned
17751772-- >>> writeN n = Fold.take n (Array.writeNUnsafe n)
1776−-- >>> writeN n = Array.appendN (Array.newArray n) n
1773+-- >>> writeN n = Array.appendN (Array.newPinned n) n
17771774--
17781775-- @since 0.7.0
17791776{-# INLINE_NORMAL writeN #-}
17801777writeN :: forall m a. (MonadIO m, Unboxed a) => Int -> Fold m a (Array a)
1781−writeN = writeNWith newArray
1778+writeN = writeNWith newPinned
17821779
17831780-- | Like writeNWithUnsafe but writes the array in reverse order.
17841781--
@@ -1814,20 +1811,20 @@ writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
18141811-- /Pre-release/
18151812{-# INLINE_NORMAL writeRevN #-}
18161813writeRevN :: forall m a. (MonadIO m, Unboxed a) => Int -> Fold m a (Array a)
1817−writeRevN = writeRevNWith newArray
1814+writeRevN = writeRevNWith newPinned
18181815
18191816-- | @writeNAligned align n@ folds a maximum of @n@ elements from the input
18201817-- stream to an 'Array' aligned to the given size.
18211818--
1822−-- >>> writeNAligned align = Array.writeNWith (Array.newArrayAligned align)
1823−-- >>> writeNAligned align n = Array.appendN (Array.newArrayAligned align n) n
1819+-- >>> writeNAligned align = Array.writeNWith (Array.newAlignedPinned align)
1820+-- >>> writeNAligned align n = Array.appendN (Array.newAlignedPinned align n) n
18241821--
18251822-- /Pre-release/
18261823--
18271824{-# INLINE_NORMAL writeNAligned #-}
18281825writeNAligned :: forall m a. (MonadIO m, Unboxed a)
18291826 => Int -> Int -> Fold m a (Array a)
1830−writeNAligned align = writeNWith (newArrayAligned align)
1827+writeNAligned align = writeNWith (newAlignedPinned align)
18311828
18321829-- XXX Buffer to a list instead?
18331830--
@@ -1870,7 +1867,7 @@ writeChunks n = FL.many (writeN n) FL.toStreamK
18701867--
18711868-- /Caution! Do not use this on infinite streams./
18721869--
1873−-- >>> f n = Array.appendWith (* 2) (Array.newArray n)
1870+-- >>> f n = Array.appendWith (* 2) (Array.newPinned n)
18741871-- >>> writeWith n = Fold.rmapM Array.rightSize (f n)
18751872-- >>> writeWith n = Fold.rmapM Array.fromArrayStreamK (Array.writeChunks n)
18761873--
@@ -1878,7 +1875,7 @@ writeChunks n = FL.many (writeN n) FL.toStreamK
18781875{-# INLINE_NORMAL writeWith #-}
18791876writeWith :: forall m a. (MonadIO m, Unboxed a)
18801877 => Int -> Fold m a (Array a)
1881−-- writeWith n = FL.rmapM rightSize $ appendWith (* 2) (newArray n)
1878+-- writeWith n = FL.rmapM rightSize $ appendWith (* 2) (newPinned n)
18821879writeWith elemCount =
18831880 FL.rmapM extract $ FL.foldlM' step initial
18841881
@@ -1890,7 +1887,7 @@ writeWith elemCount =
18901887
18911888 initial = do
18921889 when (elemCount < 0) $ error "writeWith: elemCount is negative"
1893− liftIO $ newArrayAligned (alignment (undefined :: a)) elemCount
1890+ liftIO $ newAlignedPinned (alignment (undefined :: a)) elemCount
18941891 step arr@(Array _ start end bound) x
18951892 | INDEX_NEXT(end,a) > bound = do
18961893 let oldSize = end - start
@@ -1931,7 +1928,7 @@ fromStreamDN :: forall m a. (MonadIO m, Unboxed a)
19311928 => Int -> D.Stream m a -> m (Array a)
19321929-- fromStreamDN n = D.fold (writeN n)
19331930fromStreamDN limit str = do
1934− arr <- liftIO $ newArray limit
1931+ arr <- liftIO $ newPinned limit
19351932 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
19361933 return $ arr {arrEnd = end}
19371934
@@ -2038,7 +2035,7 @@ spliceCopy arr1 arr2 = liftIO $ do
20382035 len2 = arrEnd arr2 - start2
20392036 newArrContents <-
20402037 liftIO
2041− $ newAlignedArrayContents
2038+ $ Unboxed.newAlignedPinnedBytes
20422039 (len1 + len2)
20432040 (alignment (undefined :: a))
20442041 let len = len1 + len2