@@ -18,7 +18,6 @@ module Streamly.Internal.Data.Array.Unboxed.Mut.Type
18 -- $arrayNotes
18 -- $arrayNotes
19 Array (..)
19 Array (..)
20 , MutableByteArray
20 , MutableByteArray
@@ -28,11 +27,11 @@ module Streamly.Internal.Data.Array.Unboxed.Mut.Type
30 -- *** Uninitialized Arrays
29 -- *** Uninitialized Arrays
31− , newArray
30+ , newPinned
32− , newPinnedArrayBytes
31+ , newPinnedBytes
33− , newArrayAligned
32+ , newAlignedPinned
34 , newArrayWith
34 , newArrayWith
35− , newAlignedArrayContents
37 -- *** Initialized Arrays
36 -- *** Initialized Arrays
38 , withNewArrayUnsafe
37 , withNewArrayUnsafe
@@ -234,9 +233,11 @@ import Streamly.Internal.Data.Unboxed
236import GHC.Base
235import GHC.Base
237− ( IO(..), byteArrayContents#
236+ ( IO(..)
238− , Int(..), newAlignedPinnedByteArray#
237+ , Int(..)
238+ , byteArrayContents#
239− , copyMutableByteArray#, compareByteArrays#
239+ , compareByteArrays#
240+ , copyMutableByteArray#
241import GHC.Base (noinline)
242import GHC.Base (noinline)
242import GHC.Exts (unsafeCoerce#)
243import GHC.Exts (unsafeCoerce#)
@@ -248,7 +249,6 @@ import Streamly.Internal.Data.Stream.Type (Stream)
248import Streamly.Internal.Data.SVar.Type (adaptState, defState)
249import Streamly.Internal.Data.SVar.Type (adaptState, defState)
249import Streamly.Internal.Data.Unfold.Type (Unfold(..))
250import Streamly.Internal.Data.Unfold.Type (Unfold(..))
250import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
251import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
251−import System.IO.Unsafe (unsafePerformIO)
253import qualified Streamly.Internal.Data.Fold.Type as FL
253import qualified Streamly.Internal.Data.Fold.Type as FL
254import qualified Streamly.Internal.Data.Producer as Producer
254import qualified Streamly.Internal.Data.Producer as Producer
@@ -385,6 +385,8 @@ unpin arr@Array{..} = do
385-- Alignment must be greater than or equal to machine word size and a power of
385-- Alignment must be greater than or equal to machine word size and a power of
388+-- Alignment is ignored if the allocator allocates unpinned memory.
388-- /Pre-release/
390-- /Pre-release/
389{-# INLINE newArrayWith #-}
391{-# INLINE newArrayWith #-}
390newArrayWith :: forall m a. (MonadIO m, Unboxed a)
392newArrayWith :: forall m a. (MonadIO m, Unboxed a)
@@ -399,61 +401,25 @@ newArrayWith alloc alignSize count = do
399 , arrBound = size
401 , arrBound = size
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
411− let c = MutableByteArray mbarr#
414−{-# NOINLINE nilArrayContents #-}
415−nilArrayContents :: MutableByteArray a
417− unsafePerformIO $ newAlignedArrayContents 0 0
420#ifdef DEVBUILD
405#ifdef DEVBUILD
421 Unboxed a =>
406 Unboxed a =>
424−nil = Array nilArrayContents 0 0 0
409+nil = Array Unboxed.nil 0 0 0
426−-- | Like 'newArrayWith' but using an allocator that aligns the memory to the
427−-- alignment dictated by the 'Unboxed' instance of the type.
430−{-# INLINE newArrayAligned #-}
431−newArrayAligned :: (MonadIO m, Unboxed a) => Int -> Int -> m (Array a)
432−newArrayAligned = newArrayWith (\s a -> liftIO $ newAlignedArrayContents s a)
434−-- XXX Intead of newArray, make newPinnedArray and newUnpinnedArray. Make it
436−-- XXX can unaligned allocation be more efficient when alignment is not needed?
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.
443−{-# INLINE newArray #-}
444−newArray :: forall m a. (MonadIO m, Unboxed a) => Int -> m (Array a)
445−newArray = newArrayAligned (alignment (undefined :: a))
447-- | Allocates a pinned empty array that can hold 'count' items. The memory of
412-- | Allocates a pinned empty array that can hold 'count' items. The memory of
448-- the array is uninitialized and the allocation is aligned as per the
413-- the array is uninitialized and the allocation is aligned as per the
449-- 'Unboxed' instance of the type.
414-- 'Unboxed' instance of the type.
451-- /Pre-release/
416-- /Pre-release/
452−{-# INLINE newPinnedArrayBytes #-}
417+{-# INLINE newPinnedBytes #-}
453−newPinnedArrayBytes :: forall m a. (MonadIO m, Unboxed a) => Int -> m (Array a)
418+newPinnedBytes :: forall m a. (MonadIO m, Unboxed a) => Int -> m (Array a)
454−newPinnedArrayBytes bytes = do
419+newPinnedBytes bytes = do
455 contents <-
420 contents <-
456− liftIO $ newAlignedArrayContents bytes (alignment (undefined :: a))
422+ $ Unboxed.newAlignedPinnedBytes bytes (alignment (undefined :: a))
457 return $ Array
423 return $ Array
458 { arrContents = contents
424 { arrContents = contents
459 , arrStart = 0
425 , arrStart = 0
@@ -461,6 +427,37 @@ newPinnedArrayBytes bytes = do
461 , arrBound = bytes
427 , arrBound = bytes
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.
434+{-# INLINE newAlignedPinned #-}
435+newAlignedPinned :: (MonadIO m, Unboxed a) => Int -> Int -> m (Array a)
437+ newArrayWith (\s a -> liftIO $ Unboxed.newAlignedPinnedBytes s a)
439+-- XXX can unaligned allocation be more efficient when alignment is not needed?
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.
446+{-# INLINE newPinned #-}
447+newPinned :: forall m a. (MonadIO m, Unboxed a) => Int -> m (Array a)
448+newPinned = newAlignedPinned (alignment (undefined :: a))
450+-- | Allocates an empty unpinned array that can hold 'count' items. The memory
451+-- of the array is uninitialized.
455+new :: (MonadIO m, Unboxed a) => Int -> m (Array a)
458+ (\s _ -> liftIO $ Unboxed.newUnpinnedBytes s)
459+ (error "new: alignment is not used in unpinned arrays.")
464-- | Allocate an Array of the given size and run an IO action passing the array
461-- | Allocate an Array of the given size and run an IO action passing the array
465-- start pointer.
462-- start pointer.
@@ -469,7 +466,7 @@ newPinnedArrayBytes bytes = do
469withNewArrayUnsafe ::
466withNewArrayUnsafe ::
470 (MonadIO m, Unboxed a) => Int -> (Ptr a -> m ()) -> m (Array a)
467 (MonadIO m, Unboxed a) => Int -> (Ptr a -> m ()) -> m (Array a)
471withNewArrayUnsafe count f = do
468withNewArrayUnsafe count f = do
472− arr <- newArray count
469+ arr <- newPinned count
473 asPtrUnsafe arr
470 asPtrUnsafe arr
474 $ \p -> f p >> return arr
471 $ \p -> f p >> return arr
@@ -719,7 +716,7 @@ reallocAligned elemSize alignSize newCapacityInBytes Array{..} = do
720 -- Allocate new array
717 -- Allocate new array
721 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
718 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
722− contents <- newAlignedArrayContents newCapMaxInBytes alignSize
719+ contents <- Unboxed.newAlignedPinnedBytes newCapMaxInBytes alignSize
723 let !(MutableByteArray mbarrFrom#) = arrContents
720 let !(MutableByteArray mbarrFrom#) = arrContents
724 !(MutableByteArray mbarrTo#) = contents
721 !(MutableByteArray mbarrTo#) = contents
@@ -1310,7 +1307,7 @@ arraysOf n (D.Stream step state) =
1310 error $ "Streamly.Internal.Data.Array.Unboxed.Mut.Type.arraysOf: "
1307 error $ "Streamly.Internal.Data.Array.Unboxed.Mut.Type.arraysOf: "
1311 ++ "the size of arrays [" ++ show n
1308 ++ "the size of arrays [" ++ show n
1312 ++ "] must be a natural number"
1309 ++ "] must be a natural number"
1313− Array contents start end bound <- liftIO $ newArray n
1310+ Array contents start end bound <- liftIO $ newPinned n
1314 return $ D.Skip (GroupBuffer st contents start end bound)
1311 return $ D.Skip (GroupBuffer st contents start end bound)
1316 step' gst (GroupBuffer st contents start end bound) = do
1313 step' gst (GroupBuffer st contents start end bound) = do
@@ -1749,13 +1746,13 @@ writeNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1749-- conditional in the step function blocks fusion causing 10x performance
1746-- conditional in the step function blocks fusion causing 10x performance
1750-- slowdown.
1747-- slowdown.
1752−-- >>> writeNUnsafe = Array.writeNWithUnsafe Array.newArray
1749+-- >>> writeNUnsafe = Array.writeNWithUnsafe Array.newPinned
1754-- @since 0.7.0
1751-- @since 0.7.0
1755{-# INLINE_NORMAL writeNUnsafe #-}
1752{-# INLINE_NORMAL writeNUnsafe #-}
1756writeNUnsafe :: forall m a. (MonadIO m, Unboxed a)
1753writeNUnsafe :: forall m a. (MonadIO m, Unboxed a)
1757 => Int -> Fold m a (Array a)
1754 => Int -> Fold m a (Array a)
1758−writeNUnsafe = writeNWithUnsafe newArray
1755+writeNUnsafe = writeNWithUnsafe newPinned
1760-- | @writeNWith alloc n@ folds a maximum of @n@ elements into an array
1757-- | @writeNWith alloc n@ folds a maximum of @n@ elements into an array
1761-- allocated using the @alloc@ function.
1758-- allocated using the @alloc@ function.
@@ -1771,14 +1768,14 @@ writeNWith alloc n = FL.take n (writeNWithUnsafe alloc n)
1771-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
1768-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
1772-- 'Array'.
1769-- 'Array'.
1774−-- >>> writeN = Array.writeNWith Array.newArray
1771+-- >>> writeN = Array.writeNWith Array.newPinned
1775-- >>> writeN n = Fold.take n (Array.writeNUnsafe n)
1772-- >>> 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
1778-- @since 0.7.0
1775-- @since 0.7.0
1779{-# INLINE_NORMAL writeN #-}
1776{-# INLINE_NORMAL writeN #-}
1780writeN :: forall m a. (MonadIO m, Unboxed a) => Int -> Fold m a (Array a)
1777writeN :: forall m a. (MonadIO m, Unboxed a) => Int -> Fold m a (Array a)
1781−writeN = writeNWith newArray
1778+writeN = writeNWith newPinned
1783-- | Like writeNWithUnsafe but writes the array in reverse order.
1780-- | Like writeNWithUnsafe but writes the array in reverse order.
@@ -1814,20 +1811,20 @@ writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
1814-- /Pre-release/
1811-- /Pre-release/
1815{-# INLINE_NORMAL writeRevN #-}
1812{-# INLINE_NORMAL writeRevN #-}
1816writeRevN :: forall m a. (MonadIO m, Unboxed a) => Int -> Fold m a (Array a)
1813writeRevN :: forall m a. (MonadIO m, Unboxed a) => Int -> Fold m a (Array a)
1817−writeRevN = writeRevNWith newArray
1814+writeRevN = writeRevNWith newPinned
1819-- | @writeNAligned align n@ folds a maximum of @n@ elements from the input
1816-- | @writeNAligned align n@ folds a maximum of @n@ elements from the input
1820-- stream to an 'Array' aligned to the given size.
1817-- stream to an 'Array' aligned to the given size.
1822−-- >>> writeNAligned align = Array.writeNWith (Array.newArrayAligned align)
1819+-- >>> writeNAligned align = Array.writeNWith (Array.newAlignedPinned align)
1823−-- >>> writeNAligned align n = Array.appendN (Array.newArrayAligned align n) n
1820+-- >>> writeNAligned align n = Array.appendN (Array.newAlignedPinned align n) n
1825-- /Pre-release/
1822-- /Pre-release/
1827{-# INLINE_NORMAL writeNAligned #-}
1824{-# INLINE_NORMAL writeNAligned #-}
1828writeNAligned :: forall m a. (MonadIO m, Unboxed a)
1825writeNAligned :: forall m a. (MonadIO m, Unboxed a)
1829 => Int -> Int -> Fold m a (Array a)
1826 => Int -> Int -> Fold m a (Array a)
1830−writeNAligned align = writeNWith (newArrayAligned align)
1827+writeNAligned align = writeNWith (newAlignedPinned align)
1832-- XXX Buffer to a list instead?
1829-- XXX Buffer to a list instead?
@@ -1870,7 +1867,7 @@ writeChunks n = FL.many (writeN n) FL.toStreamK
1871-- /Caution! Do not use this on infinite streams./
1868-- /Caution! Do not use this on infinite streams./
1873−-- >>> f n = Array.appendWith (* 2) (Array.newArray n)
1870+-- >>> f n = Array.appendWith (* 2) (Array.newPinned n)
1874-- >>> writeWith n = Fold.rmapM Array.rightSize (f n)
1871-- >>> writeWith n = Fold.rmapM Array.rightSize (f n)
1875-- >>> writeWith n = Fold.rmapM Array.fromArrayStreamK (Array.writeChunks n)
1872-- >>> writeWith n = Fold.rmapM Array.fromArrayStreamK (Array.writeChunks n)
@@ -1878,7 +1875,7 @@ writeChunks n = FL.many (writeN n) FL.toStreamK
1878{-# INLINE_NORMAL writeWith #-}
1875{-# INLINE_NORMAL writeWith #-}
1879writeWith :: forall m a. (MonadIO m, Unboxed a)
1876writeWith :: forall m a. (MonadIO m, Unboxed a)
1880 => Int -> Fold m a (Array a)
1877 => 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)
1882writeWith elemCount =
1879writeWith elemCount =
1883 FL.rmapM extract $ FL.foldlM' step initial
1880 FL.rmapM extract $ FL.foldlM' step initial
@@ -1890,7 +1887,7 @@ writeWith elemCount =
1891 initial = do
1888 initial = do
1892 when (elemCount < 0) $ error "writeWith: elemCount is negative"
1889 when (elemCount < 0) $ error "writeWith: elemCount is negative"
1893− liftIO $ newArrayAligned (alignment (undefined :: a)) elemCount
1890+ liftIO $ newAlignedPinned (alignment (undefined :: a)) elemCount
1894 step arr@(Array _ start end bound) x
1891 step arr@(Array _ start end bound) x
1895 | INDEX_NEXT(end,a) > bound = do
1892 | INDEX_NEXT(end,a) > bound = do
1896 let oldSize = end - start
1893 let oldSize = end - start
@@ -1931,7 +1928,7 @@ fromStreamDN :: forall m a. (MonadIO m, Unboxed a)
1931 => Int -> D.Stream m a -> m (Array a)
1928 => Int -> D.Stream m a -> m (Array a)
1932-- fromStreamDN n = D.fold (writeN n)
1929-- fromStreamDN n = D.fold (writeN n)
1933fromStreamDN limit str = do
1930fromStreamDN limit str = do
1934− arr <- liftIO $ newArray limit
1931+ arr <- liftIO $ newPinned limit
1935 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
1932 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
1936 return $ arr {arrEnd = end}
1933 return $ arr {arrEnd = end}
@@ -2038,7 +2035,7 @@ spliceCopy arr1 arr2 = liftIO $ do
2038 len2 = arrEnd arr2 - start2
2035 len2 = arrEnd arr2 - start2
2039 newArrContents <-
2036 newArrContents <-
2041− $ newAlignedArrayContents
2038+ $ Unboxed.newAlignedPinnedBytes
2042 (len1 + len2)
2039 (len1 + len2)
2043 (alignment (undefined :: a))
2040 (alignment (undefined :: a))
2044 let len = len1 + len2
2041 let len = len1 + len2