Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
69d8344
Add ifThenElse combinator for combining streams
harendra-kumar Jul 2, 2026
bbf202f
Add overflow tests for enumeration unfolds/streams
harendra-kumar Jul 1, 2026
570bcd8
Add a test for a corner case of enumerateFromThenTo
harendra-kumar Jul 2, 2026
06c54d7
Fix enumerateFromThenToIntegral
harendra-kumar Jul 1, 2026
980fc3e
Fix overflow in enumerateFromToIntegral
harendra-kumar Jul 2, 2026
88961e8
Move enumerateFromStepNum to Producer module
harendra-kumar Jul 2, 2026
4d07468
Move enumerateFromStepIntegral to Producer module
harendra-kumar Jul 2, 2026
a6fe06a
Move enumerateFromThenToIntegral to the Producer module
harendra-kumar Jul 2, 2026
f53c739
Move takeEndByM to the Producer module
harendra-kumar Jul 2, 2026
044486a
Fix overflow in enumerateFromToIntegral Unfold
harendra-kumar Jul 2, 2026
013f664
Fix overflow in enumerateFromThenIntegralBounded
harendra-kumar Jul 2, 2026
03d99cc
Split out Stream enumeration ops in a separate module
harendra-kumar Jul 2, 2026
e8250b1
Synchronize Stream and Unfold Enumeration modules
harendra-kumar Jul 2, 2026
8f4987c
Fix enumerateFromTo Unfold
harendra-kumar Jul 2, 2026
919124e
Make bounded as default in Stream Enumeration
harendra-kumar Jul 2, 2026
e417d4c
Make bounded versions default in Unfold enumeration
harendra-kumar Jul 3, 2026
cdb49ff
Add a simplified upward enumeration operation
harendra-kumar Jul 4, 2026
66afe37
Update single yield point guidelines
harendra-kumar Jul 4, 2026
47ed510
Add Fuse annotation on EnumState
harendra-kumar Jul 7, 2026
7d06df4
Make enumerateFromThenTo fusible
harendra-kumar Jul 4, 2026
3108576
Use Num APIs in general and specialize RealFloat, Bounded
harendra-kumar Jul 6, 2026
576c714
Do not use Producer for Stream generation
harendra-kumar Jul 8, 2026
128c6a3
Fix deprecation warning in Unfold benchmarks
harendra-kumar Jul 8, 2026
a15cfa0
Make enumerated values strict to improve perf
harendra-kumar Jul 10, 2026
b7794a0
Simplify enumeration states for better fusion
harendra-kumar Jul 10, 2026
64cd131
Use ANN Fuse on Stream EnumState
harendra-kumar Jul 11, 2026
0b3a049
Use fusion-plugin based inspection annotations in Scanl
harendra-kumar Jul 11, 2026
a647d5f
Allow exceptions in Scanl fusion for GHC-9.14
harendra-kumar Jul 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 119 additions & 32 deletions benchmark/Streamly/Benchmark/Data/Scanl/Container.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
-- Benchmarks for operations exported from Streamly.Internal.Data.Scanl.Container.
module Scanl.Container (benchmarks) where

-- import Data.IntSet (IntSet)
import Data.IntSet (IntSet)
import Data.IORef (IORef, newIORef, readIORef, modifyIORef)
import Data.Map.Strict (Map)
-- import Data.Set (Set)
-- import Data.STRef (STRef)
import Streamly.Internal.Data.Scanl (Scanl(..))
import Data.Set (Set)
import Data.STRef (STRef)
import Streamly.Internal.Data.Scanl (Scanl(..), Tuple'Fused)
import Streamly.Internal.Data.Stream (Stream)
-- import Streamly.Internal.Data.Tuple.Strict (Tuple', Tuple3')
import Streamly.Internal.Data.Tuple.Strict (Tuple', Tuple3')
import System.IO.Unsafe (unsafePerformIO)
import System.Random (randomRIO)

Expand Down Expand Up @@ -83,42 +83,59 @@ getScanl k = do
-- Set operations
-------------------------------------------------------------------------------

-- {-# ANN toSet (PermitTypes [''Int,''Set,''STRef,''(,)]) #-}
{-# ANN toSet (PermitTypes [''Int,''Set,''STRef,''(,)]) #-}
{-# ANN toSet (PermitTypeClasses []) #-}
{-# ANN toSet (MaxCoreSize 1000) #-}
{-# NOINLINE toSet #-}
toSet :: Int -> IO ()
toSet n = withPostscanl n Scanl.toSet

-- {-# ANN toIntSet (PermitTypes [''Int,''STRef,''IntSet,''(,)]) #-}
{-# ANN toIntSet (PermitTypes [''Int,''STRef,''IntSet,''(,)]) #-}
{-# ANN toIntSet (PermitTypeClasses []) #-}
{-# ANN toIntSet (MaxCoreSize 1000) #-}
{-# NOINLINE toIntSet #-}
toIntSet :: Int -> IO ()
toIntSet n = withPostscanl n Scanl.toIntSet

-- {-# ANN countDistinct (PermitTypes [''Int,''STRef,''Set,''(,)]) #-}
{-# ANN countDistinct (PermitTypes [''Int,''STRef,''Set,''(,)]) #-}
{-# ANN countDistinct (PermitTypeClasses []) #-}
{-# ANN countDistinct (MaxCoreSize 1000) #-}
{-# NOINLINE countDistinct #-}
countDistinct :: Int -> IO ()
countDistinct n = withPostscanl n Scanl.countDistinct

-- {-# ANN countDistinctInt (PermitTypes [''Int,''STRef,''IntSet,''(,)]) #-}
{-# ANN countDistinctInt (PermitTypes [''Int,''STRef,''IntSet,''(,)]) #-}
{-# ANN countDistinctInt (PermitTypeClasses []) #-}
{-# ANN countDistinctInt (MaxCoreSize 1000) #-}
{-# NOINLINE countDistinctInt #-}
countDistinctInt :: Int -> IO ()
countDistinctInt n = withPostscanl n Scanl.countDistinctInt

-- {-# ANN nub (PermitTypes [''Int,''STRef,''Set,''Maybe,''Tuple',''(,)]) #-}
{-# ANN nub (PermitTypes
[ ''Int
, ''STRef
, ''Set
, ''Maybe
, ''Tuple'
, ''(,)
-- For GHC-9.14
, ''Scanl.Step
]) #-}
{-# ANN nub (PermitTypeClasses []) #-}
{-# ANN nub (MaxCoreSize 1000) #-}
{-# NOINLINE nub #-}
nub :: Int -> IO ()
nub n = withPostscanl n Scanl.nub

-- {-# ANN nubInt (PermitTypes [''Int,''STRef,''IntSet,''(,)]) #-}
{-# ANN nubInt (PermitTypes
[ ''Int
, ''STRef
, ''IntSet
, ''(,)
-- For GHC-9.14
, ''Tuple'
, ''Scanl.Step
]) #-}
{-# ANN nubInt (PermitTypeClasses []) #-}
{-# ANN nubInt (MaxCoreSize 1000) #-}
{-# NOINLINE nubInt #-}
Expand All @@ -129,8 +146,19 @@ nubInt n = withPostscanl n Scanl.nubInt
-- Demultiplexing
-------------------------------------------------------------------------------

-- {-# ANN demuxIOOneShot (PermitTypes [''Int,''STRef,''IORef,''Map,''Scanl,
-- ''FL.Step, ''Scanl.Step,''(,)]) #-}
{-# ANN demuxIOOneShot (PermitTypes
[ ''Int
, ''STRef
, ''IORef
, ''Map
, ''Scanl
, ''FL.Step
, ''Scanl.Step
, ''(,)
-- For GHC-9.14
, ''Tuple'
, ''Maybe
]) #-}
{-# ANN demuxIOOneShot (PermitTypeClasses []) #-}
{-# ANN demuxIOOneShot (MaxCoreSize 2000) #-}
{-# NOINLINE demuxIOOneShot #-}
Expand All @@ -140,10 +168,21 @@ demuxIOOneShot len =
Stream.fold FL.drain
. Stream.postscanl (Scanl.demuxIO (getKey 64) getScanl)

-- {-# ANN demuxIOSum (PermitTypes
-- [''Int,''STRef,''IORef,''Map,''Scanl,''FL.Step,''Scanl.Step,''(,)]) #-}
{-# ANN demuxIOSum (PermitTypes
[ ''Int
, ''STRef
, ''IORef
, ''Map
, ''Scanl
, ''FL.Step
, ''Scanl.Step
, ''(,)
-- For GHC-9.14
, ''Tuple'
, ''Maybe
]) #-}
{-# ANN demuxIOSum (PermitTypeClasses []) #-}
{-# ANN demuxIOSum (MaxCoreSize 1000) #-}
{-# ANN demuxIOSum (MaxCoreSize 2000) #-}
{-# NOINLINE demuxIOSum #-}
demuxIOSum :: Int -> IO ()
demuxIOSum len =
Expand All @@ -152,9 +191,21 @@ demuxIOSum len =
. Stream.postscanl
(Scanl.demuxIO (getKey 64) (const (pure (Just Scanl.sum))))

-- {-# ANN demuxSum (PermitTypes [''Int,''STRef,''IO,''Map,''Scanl,''FL.Step,''Scanl.Step,''(,)]) #-}
{-# ANN demuxSum (PermitTypes
[ ''Int
, ''STRef
, ''IO
, ''Map
, ''Scanl
, ''FL.Step
, ''Scanl.Step
, ''(,)
-- For GHC-9.14
, ''Tuple'
, ''Maybe
]) #-}
{-# ANN demuxSum (PermitTypeClasses []) #-}
{-# ANN demuxSum (MaxCoreSize 1000) #-}
{-# ANN demuxSum (MaxCoreSize 2000) #-}
{-# NOINLINE demuxSum #-}
demuxSum :: Int -> IO ()
demuxSum len =
Expand All @@ -163,10 +214,10 @@ demuxSum len =
. Stream.postscanl
(Scanl.demux (getKey 64) (const (pure (Just Scanl.sum))))

-- {-# ANN demuxGenericSum (PermitTypes
-- [''Int,''STRef,''Map,''Maybe,''Scanl,''FL.Step,''Scanl.Step,''(,)]) #-}
{-# ANN demuxGenericSum (PermitTypes
[''Int,''STRef,''Map,''Maybe,''Scanl,''FL.Step,''Scanl.Step,''(,)]) #-}
{-# ANN demuxGenericSum (PermitTypeClasses []) #-}
{-# ANN demuxGenericSum (MaxCoreSize 1000) #-}
{-# ANN demuxGenericSum (MaxCoreSize 2000) #-}
{-# NOINLINE demuxGenericSum #-}
demuxGenericSum :: Int -> IO ()
demuxGenericSum len =
Expand All @@ -176,10 +227,10 @@ demuxGenericSum len =
(Scanl.demuxGeneric (getKey 64) (const (pure (Just Scanl.sum)))
:: Scanl IO Int (IO (Map Int Int), Maybe (Int, Int)))

-- {-# ANN demuxGenericIOSum (PermitTypes
-- [''Int,''STRef,''Map,''Maybe,''Scanl,''FL.Step,''Scanl.Step,''(,)]) #-}
{-# ANN demuxGenericIOSum (PermitTypes
[''Int,''STRef,''Map,''Maybe,''Scanl,''FL.Step,''Scanl.Step,''(,)]) #-}
{-# ANN demuxGenericIOSum (PermitTypeClasses []) #-}
{-# ANN demuxGenericIOSum (MaxCoreSize 1000) #-}
{-# ANN demuxGenericIOSum (MaxCoreSize 2000) #-}
{-# NOINLINE demuxGenericIOSum #-}
demuxGenericIOSum :: Int -> IO ()
demuxGenericIOSum len =
Expand All @@ -193,17 +244,42 @@ demuxGenericIOSum len =
-- Classifying
-------------------------------------------------------------------------------

-- {-# ANN classifyLimitedSum (PermitTypes [''Int,''STRef,''IORef,''Map,''Set,''Tuple',''(,)]) #-}
{-# ANN classifyLimitedSum (PermitTypes
[ ''Int
, ''STRef
, ''IORef
, ''Map
, ''Set
, ''Tuple'
, ''Tuple'Fused
, ''(,)
-- For GHC-9.14
, ''Tuple3'
, ''Scanl.Step
, ''Maybe
]) #-}
{-# ANN classifyLimitedSum (PermitTypeClasses []) #-}
{-# ANN classifyLimitedSum (MaxCoreSize 1000) #-}
{-# ANN classifyLimitedSum (MaxCoreSize 2000) #-}
{-# NOINLINE classifyLimitedSum #-}
classifyLimitedSum :: Int -> IO ()
classifyLimitedSum len =
withStream len $
Stream.fold FL.drain
. Stream.postscanl (Scanl.classifyIO (getKey 64) (limitedSum 100))

-- {-# ANN classifyIOSum (PermitTypes [''Int,''STRef,''IORef,''Map,''Tuple',''(,)]) #-}
{-# ANN classifyIOSum (PermitTypes
[ ''Int
, ''STRef
, ''IORef
, ''Map
, ''Tuple'
, ''(,)
-- For GHC-9.14
, ''Set
, ''Tuple3'
, ''Scanl.Step
, ''Maybe
]) #-}
{-# ANN classifyIOSum (PermitTypeClasses []) #-}
{-# ANN classifyIOSum (MaxCoreSize 1000) #-}
{-# NOINLINE classifyIOSum #-}
Expand All @@ -213,7 +289,18 @@ classifyIOSum len =
Stream.fold FL.drain
. Stream.postscanl (Scanl.classifyIO (getKey 64) Scanl.sum)

-- {-# ANN classifySum (PermitTypes [''Int,''STRef,''Map,''Tuple',''(,)]) #-}
{-# ANN classifySum (PermitTypes
[ ''Int
, ''STRef
, ''Map
, ''Tuple'
, ''(,)
-- For GHC-9.14
, ''Set
, ''Tuple3'
, ''Scanl.Step
, ''Maybe
]) #-}
{-# ANN classifySum (PermitTypeClasses []) #-}
{-# ANN classifySum (MaxCoreSize 1000) #-}
{-# NOINLINE classifySum #-}
Expand All @@ -223,9 +310,9 @@ classifySum len =
Stream.fold FL.drain
. Stream.postscanl (Scanl.classify (getKey 64) Scanl.sum)

-- {-# ANN classifyGenericSum (PermitTypes [''Int,''STRef,''Map,''Maybe,''Set,''Tuple',''Tuple3',''(,)]) #-}
{-# ANN classifyGenericSum (PermitTypes [''Int,''STRef,''Map,''Maybe,''Set,''Tuple',''Tuple3',''(,)]) #-}
{-# ANN classifyGenericSum (PermitTypeClasses []) #-}
{-# ANN classifyGenericSum (MaxCoreSize 1000) #-}
{-# ANN classifyGenericSum (MaxCoreSize 1500) #-}
{-# NOINLINE classifyGenericSum #-}
classifyGenericSum :: Int -> IO ()
classifyGenericSum len =
Expand All @@ -235,9 +322,9 @@ classifyGenericSum len =
(Scanl.classifyGeneric (getKey 64) Scanl.sum
:: Scanl IO Int (IO (Map Int Int), Maybe (Int, Int)))

-- {-# ANN classifyGenericIOSum (PermitTypes [''Int,''STRef,''Map,''Maybe,''Set,''Tuple',''Tuple3',''(,)]) #-}
{-# ANN classifyGenericIOSum (PermitTypes [''Int,''STRef,''Map,''Maybe,''Set,''Tuple',''Tuple3',''(,)]) #-}
{-# ANN classifyGenericIOSum (PermitTypeClasses []) #-}
{-# ANN classifyGenericIOSum (MaxCoreSize 1000) #-}
{-# ANN classifyGenericIOSum (MaxCoreSize 1500) #-}
{-# NOINLINE classifyGenericIOSum #-}
classifyGenericIOSum :: Int -> IO ()
classifyGenericIOSum len =
Expand Down
3 changes: 2 additions & 1 deletion benchmark/Streamly/Benchmark/Data/Stream/Generate.hs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module Stream.Generate (benchmarks) where
import GHC.Types (SPEC(..))
import Test.Inspection
import qualified Streamly.Internal.Data.Fold as Fold
import qualified Streamly.Internal.Data.Producer as Producer
#endif

import Control.Monad.IO.Class (MonadIO)
Expand Down Expand Up @@ -89,7 +90,7 @@ sourceIntFromThenTo value = withDrain $ \n ->
#ifdef INSPECTION
inspect $ hasNoTypeClasses 'sourceIntFromThenTo
inspect $ 'sourceIntFromThenTo `hasNoType` ''Stream.Step
inspect $ 'sourceIntFromThenTo `hasNoType` ''Stream.EnumState
inspect $ 'sourceIntFromThenTo `hasNoType` ''Producer.EnumState
inspect $ 'sourceIntFromThenTo `hasNoType` ''Fold.Step
inspect $ 'sourceIntFromThenTo `hasNoType` ''SPEC
#endif
Expand Down
12 changes: 10 additions & 2 deletions benchmark/Streamly/Benchmark/Data/Stream/Nesting/LogicUnfold.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@

{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskellQuotes #-}

module Stream.Nesting.LogicUnfold (benchmarks) where

import Streamly.Internal.Data.Producer (InterleaveState(..))
import Streamly.Data.Stream (Stream)
import Streamly.Data.Unfold (Unfold)

Expand All @@ -22,6 +24,7 @@ import Stream.Type (benchIO, withRandomIntIO)
import Streamly.Benchmark.Common
import qualified Stream.Type as Type
import Prelude hiding (concatMap, zipWith)
import Fusion.Plugin.Types

-------------------------------------------------------------------------------
-- Monad
Expand All @@ -32,7 +35,7 @@ infiniteIntsUnfold :: Monad m => Int -> Int -> Unfold m ((), ()) Int
infiniteIntsUnfold _ _ =
Unfold.interleave
(Unfold.supply (0 :: Int) Unfold.enumerateFrom)
(Unfold.supply (-1, -2) Unfold.enumerateFromThen)
(Unfold.supply (-1) Unfold.enumerateDownFromNum)

{-# INLINE unfoldCrossEqn #-}
unfoldCrossEqn :: Monad m => Int -> Unfold m ((), ()) Int -> m ()
Expand Down Expand Up @@ -72,6 +75,11 @@ fairUnfoldSchedEqn maxVal input ints =
$ Stream.mapM (Type.checkPair maxVal)
$ Stream.fairUnfoldSched intu ints

-- GHC 9.14.1 cannot fuse InterleaveState, though 9.10 can
{-# ANN unfoldCrossBounded (PermitTypes [''Int,''Maybe,''InterleaveState]) #-}
{-# ANN unfoldCrossBounded (PermitTypeClasses []) #-}
{-# ANN unfoldCrossBounded (MaxCoreSize 20000) #-}
{-# NOINLINE unfoldCrossBounded #-}
unfoldCrossBounded :: Int -> IO ()
unfoldCrossBounded maxVal = unfoldCrossEqn maxVal (Type.boundedIntsUnfold maxVal 0)

Expand Down
6 changes: 3 additions & 3 deletions benchmark/Streamly/Benchmark/Data/Stream/Type/Logic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,21 @@ boundedInts :: Monad m => Int -> Int -> Stream m Int
boundedInts n _ =
Stream.interleave
(Stream.enumerateFromTo (0 :: Int) n)
(Stream.enumerateFromThenTo (-1) (-2) (-n))
(Stream.enumerateDownFromToNum (-1) (-n))

{-# INLINE infiniteInts #-}
infiniteInts :: Monad m => Int -> Int -> Stream m Int
infiniteInts _ _ =
Stream.interleave
(Stream.enumerateFrom (0 :: Int))
(Stream.enumerateFromThen (-1) (-2))
(Stream.enumerateDownFromNum (-1))

{-# INLINE boundedIntsUnfold #-}
boundedIntsUnfold :: Monad m => Int -> Int -> Unfold m ((), ()) Int
boundedIntsUnfold n _ =
Unfold.interleave
(Unfold.supply (0 :: Int, n) Unfold.enumerateFromTo)
(Unfold.supply (-1, -2, -n) Unfold.enumerateFromThenTo)
(Unfold.supply (-1, -n) Unfold.enumerateDownFromToNum)

{-# INLINE checkStream #-}
checkStream :: Applicative m =>
Expand Down
Loading
Loading