2-- Module : Streamly.Benchmark.Data.Fold
3-- Copyright : (c) 2018 Composewell
5-- Maintainer : streamly@composewell.com
7{-# LANGUAGE FlexibleContexts #-}
9{-# LANGUAGE ScopedTypeVariables #-}
11#ifdef __HADDOCK_VERSION__
16{-# LANGUAGE TemplateHaskell #-}
17{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
20module Main (main) where
22import Control.DeepSeq (NFData(..))
23import Control.Exception (SomeException, ErrorCall, try)
25import Data.Word (Word8)
26import Streamly.Internal.Data.Unfold (Unfold)
27import System.IO (Handle, hClose)
28import System.Random (randomRIO)
30import qualified Prelude
31import qualified Streamly.FileSystem.Handle as FH
32import qualified Streamly.Internal.Data.Fold as FL
33import qualified Streamly.Internal.Data.Unfold as UF
34import qualified Streamly.Internal.Data.Unfold.Exception as UF
35import qualified Streamly.Internal.Data.Stream as S
36import qualified Streamly.Internal.Data.Stream as D
37import qualified Streamly.Internal.Data.StreamK as K
39import Gauge hiding (env)
40import Prelude hiding (take, filter, zipWith, map, mapM, takeWhile)
41import Streamly.Benchmark.Common
42import Streamly.Benchmark.Common.Handle
45import Control.Monad.Catch (MonadCatch)
50benchIO :: (NFData b) => String -> (Int -> IO b) -> Benchmark
51benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
53-------------------------------------------------------------------------------
54-- Stream generation and elimination
55-------------------------------------------------------------------------------
57-- generate numbers up to the argument value
59source :: Monad m => Int -> Unfold m Int Int
60source n = UF.second n UF.enumerateFromToIntegral
62-------------------------------------------------------------------------------
64-------------------------------------------------------------------------------
66{-# INLINE drainGeneration #-}
67drainGeneration :: Monad m => Unfold m a b -> a -> m ()
68drainGeneration unf seed = UF.fold FL.drain unf seed
70{-# INLINE drainTransformation #-}
72 Monad m => Unfold m a b -> (Unfold m a b -> Unfold m c d) -> c -> m ()
73drainTransformation unf f seed = drainGeneration (f unf) seed
75{-# INLINE drainTransformationDefault #-}
76drainTransformationDefault ::
77 Monad m => Int -> (Unfold m Int Int -> Unfold m c d) -> c -> m ()
78drainTransformationDefault to =
79 drainTransformation (UF.second to UF.enumerateFromToIntegral)
81{-# INLINE drainProduct #-}
86 -> (Unfold m a b -> Unfold m c d -> Unfold m e f)
89drainProduct unf1 unf2 f seed = drainGeneration (f unf1 unf2) seed
91{-# INLINE drainProductDefault #-}
95 -> (Unfold m Int Int -> Unfold m Int Int -> Unfold m e f)
98drainProductDefault to = drainProduct src src
102 src = UF.second to UF.enumerateFromToIntegral
104-------------------------------------------------------------------------------
105-- Operations on input
106-------------------------------------------------------------------------------
109lmap :: Monad m => Int -> Int -> m ()
111 drainTransformationDefault (size + start) (UF.lmap (+ 1)) start
114lmapM :: Monad m => Int -> Int -> m ()
116 drainTransformationDefault (size + start) (UF.lmapM (return . (+) 1)) start
119both :: Monad m => Int -> Int -> m ()
121 drainTransformationDefault (size + start) (UF.both start) undefined
125first :: Monad m => Int -> Int -> m ()
128 (UF.take size UF.enumerateFromThenIntegral)
133second :: Monad m => Int -> Int -> m ()
136 (UF.take size UF.enumerateFromThenIntegral)
140{-# INLINE discardFirst #-}
141discardFirst :: Monad m => Int -> Int -> m ()
142discardFirst size start =
143 drainTransformationDefault (size + start) UF.discardFirst (start, start)
145{-# INLINE discardSecond #-}
146discardSecond :: Monad m => Int -> Int -> m ()
147discardSecond size start =
148 drainTransformationDefault (size + start) UF.discardSecond (start, start)
151swap :: Monad m => Int -> Int -> m ()
154 (UF.take size UF.enumerateFromThenIntegral)
158-------------------------------------------------------------------------------
160-------------------------------------------------------------------------------
162{-# INLINE fromStream #-}
163fromStream :: Int -> Int -> IO ()
164fromStream size start =
165 drainGeneration UF.fromStream (S.replicate size start :: S.Stream IO Int)
167-- XXX INVESTIGATE: Although the performance of this should be equivalant to
168-- fromStream, this is considerably worse. More than 4x worse.
169{-# INLINE fromStreamK #-}
170fromStreamK :: Monad m => Int -> Int -> m ()
171fromStreamK size start = drainGeneration UF.fromStreamK (K.replicate size start)
173{-# INLINE fromStreamD #-}
174fromStreamD :: Monad m => Int -> Int -> m ()
175fromStreamD size start =
176 drainGeneration UF.fromStreamD (D.replicate size start)
179_nilM :: Monad m => Int -> Int -> m ()
180_nilM _ start = drainGeneration (UF.nilM return) start
183consM :: Monad m => Int -> Int -> m ()
185 drainTransformationDefault (size + start) (UF.consM return) start
187{-# INLINE _functionM #-}
188_functionM :: Monad m => Int -> Int -> m ()
189_functionM _ start = drainGeneration (UF.functionM return) start
191{-# INLINE _function #-}
192_function :: Monad m => Int -> Int -> m ()
193_function _ start = drainGeneration (UF.function id) start
195{-# INLINE _identity #-}
196_identity :: Monad m => Int -> Int -> m ()
197_identity _ start = drainGeneration UF.identity start
200_const :: Monad m => Int -> Int -> m ()
202 drainGeneration (UF.take size (UF.fromEffect (return start))) undefined
204{-# INLINE unfoldrM #-}
205unfoldrM :: Monad m => Int -> Int -> m ()
206unfoldrM size start = drainGeneration (UF.unfoldrM step) start
212 $ if i < start + size
216{-# INLINE fromList #-}
217fromList :: Monad m => Int -> Int -> m ()
218fromList size start = drainGeneration UF.fromList [start .. start + size]
220{-# INLINE fromListM #-}
221fromListM :: Monad m => Int -> Int -> m ()
222fromListM size start =
223 drainGeneration UF.fromListM (Prelude.map return [start .. start + size])
225{-# INLINE _fromSVar #-}
226_fromSVar :: Int -> Int -> m ()
229{-# INLINE _fromProducer #-}
230_fromProducer :: Int -> Int -> m ()
231_fromProducer = undefined
233{-# INLINE replicateM #-}
234replicateM :: Monad m => Int -> Int -> m ()
235replicateM size start = drainGeneration UF.replicateM (size, return start)
237{-# INLINE repeatM #-}
238repeatM :: Monad m => Int -> Int -> m ()
239repeatM size start = drainGeneration (UF.take size UF.repeatM) (return start)
241{-# INLINE iterateM #-}
242iterateM :: Monad m => Int -> Int -> m ()
244 drainGeneration (UF.take size (UF.iterateM return)) (return start)
246{-# INLINE fromIndicesM #-}
247fromIndicesM :: Monad m => Int -> Int -> m ()
248fromIndicesM size start =
249 drainGeneration (UF.take size (UF.fromIndicesM return)) start
251{-# INLINE enumerateFromThenIntegral #-}
252enumerateFromThenIntegral :: Monad m => Int -> Int -> m ()
253enumerateFromThenIntegral size start =
254 drainGeneration (UF.take size UF.enumerateFromThenIntegral) (start, 1)
256{-# INLINE enumerateFromToIntegral #-}
257enumerateFromToIntegral :: Monad m => Int -> Int -> m ()
258enumerateFromToIntegral size start =
262 UF.enumerateFromToIntegral
265{-# INLINE enumerateFromIntegral #-}
266enumerateFromIntegral :: Monad m => Int -> Int -> m ()
267enumerateFromIntegral size start =
268 drainGeneration (UF.take size UF.enumerateFromIntegral) start
270{-# INLINE enumerateFromStepNum #-}
271enumerateFromStepNum :: Monad m => Int -> Int -> m ()
272enumerateFromStepNum size start =
273 drainGeneration (UF.take size (UF.enumerateFromThenNum)) (start, 1)
275{-# INLINE enumerateFromNum #-}
276enumerateFromNum :: Monad m => Int -> Int -> m ()
277enumerateFromNum size start = drainGeneration (UF.take size UF.enumerateFromNum) start
279{-# INLINE enumerateFromToFractional #-}
280enumerateFromToFractional :: Monad m => Int -> Int -> m ()
281enumerateFromToFractional size start =
282 let intToDouble x = (fromInteger (fromIntegral x)) :: Double
285 (intToDouble $ start + size)
286 UF.enumerateFromToFractional
290-------------------------------------------------------------------------------
291-- Stream transformation
292-------------------------------------------------------------------------------
294{-# INLINE postscan #-}
295postscan :: Monad m => Int -> Int -> m ()
297 drainTransformationDefault (size + start) (UF.postscan FL.sum) start
300map :: Monad m => Int -> Int -> m ()
301map size start = drainTransformationDefault (size + start) (UF.map (+1)) start
304mapM :: Monad m => Int -> Int -> m ()
306 drainTransformationDefault (size + start) (UF.mapM (return . (+) 1)) start
309mapM2 :: Monad m => Int -> Int -> m ()
311 drainTransformationDefault
313 (UF.mapM2 (\a b -> return $ a + b))
316-------------------------------------------------------------------------------
318-------------------------------------------------------------------------------
320{-# INLINE takeWhileM #-}
321takeWhileM :: Monad m => Int -> Int -> m ()
322takeWhileM size start =
323 drainTransformationDefault
325 (UF.takeWhileM (\b -> return (b <= size + start)))
328{-# INLINE takeWhile #-}
329takeWhile :: Monad m => Int -> Int -> m ()
330takeWhile size start =
331 drainTransformationDefault
333 (UF.takeWhile (\b -> b <= size + start))
337take :: Monad m => Int -> Int -> m ()
338take size start = drainTransformationDefault (size + start) (UF.take size) start
341filter :: Monad m => Int -> Int -> m ()
343 drainTransformationDefault (size + start) (UF.filter (\_ -> True)) start
345{-# INLINE filterM #-}
346filterM :: Monad m => Int -> Int -> m ()
348 drainTransformationDefault
350 (UF.filterM (\_ -> (return True)))
353{-# INLINE _dropOne #-}
354_dropOne :: Monad m => Int -> Int -> m ()
356 drainTransformationDefault (size + start) (UF.drop 1) start
358{-# INLINE dropAll #-}
359dropAll :: Monad m => Int -> Int -> m ()
361 drainTransformationDefault (size + start) (UF.drop (size + 1)) start
363{-# INLINE dropWhileTrue #-}
364dropWhileTrue :: Monad m => Int -> Int -> m ()
365dropWhileTrue size start =
366 drainTransformationDefault
368 (UF.dropWhileM (\_ -> return True))
371{-# INLINE dropWhileFalse #-}
372dropWhileFalse :: Monad m => Int -> Int -> m ()
373dropWhileFalse size start =
374 drainTransformationDefault
376 (UF.dropWhileM (\_ -> return False))
379{-# INLINE dropWhileMTrue #-}
380dropWhileMTrue :: Monad m => Int -> Int -> m ()
381dropWhileMTrue size start =
382 drainTransformationDefault
384 (UF.dropWhileM (\_ -> return True))
387{-# INLINE dropWhileMFalse #-}
388dropWhileMFalse :: Monad m => Int -> Int -> m ()
389dropWhileMFalse size start =
390 drainTransformationDefault
392 (UF.dropWhileM (\_ -> return False))
395-------------------------------------------------------------------------------
397-------------------------------------------------------------------------------
399{-# INLINE zipWith #-}
400zipWith :: Monad m => Int -> Int -> m ()
402 drainProductDefault (size + start) (UF.zipWith (+)) start
404{-# INLINE zipWithM #-}
405zipWithM :: Monad m => Int -> Int -> m ()
409 (UF.zipWithM (\a b -> return $ a + b))
412{-# INLINE teeZipWith #-}
413teeZipWith :: Monad m => Int -> Int -> m ()
414teeZipWith size start =
415 drainProductDefault (size + start) (UF.zipWith (+)) start
417-------------------------------------------------------------------------------
419-------------------------------------------------------------------------------
421nthRoot :: Double -> Int -> Int
422nthRoot n value = round (fromIntegral value**(1/n))
424{-# INLINE toNullAp #-}
425toNullAp :: Monad m => Int -> Int -> m ()
426toNullAp value start =
427 let end = start + nthRoot 2 value
429 -- in UF.fold ((+) <$> s <*> s) FL.drain start
430 in UF.fold FL.drain ((+) `fmap` s `UF.crossApply` s) start
432{-# INLINE _apDiscardFst #-}
433_apDiscardFst :: Int -> Int -> m ()
434_apDiscardFst = undefined
436{-# INLINE _apDiscardSnd #-}
437_apDiscardSnd :: Int -> Int -> m ()
438_apDiscardSnd = undefined
440-------------------------------------------------------------------------------
442-------------------------------------------------------------------------------
444{-# INLINE concatMapM #-}
445concatMapM :: Monad m => Int -> Int -> m ()
446concatMapM value start =
447 val `seq` drainGeneration (UF.concatMapM unfoldInGen unfoldOut) start
451 val = nthRoot 2 value
452 unfoldInGen i = return (UF.second (i + val) UF.enumerateFromToIntegral)
453 unfoldOut = UF.second (start + val) UF.enumerateFromToIntegral
456toNull :: Monad m => Int -> Int -> m ()
458 let end = start + nthRoot 2 value
466 u = src `UF.bind` \x ->
469 in UF.fold FL.drain u start
472{-# INLINE toNull3 #-}
473toNull3 :: Monad m => Int -> Int -> m ()
475 let end = start + nthRoot 3 value
484 u = src `UF.bind` \x ->
487 in UF.fold FL.drain u start
490toList :: Monad m => Int -> Int -> m [Int]
491toList value start = do
492 let end = start + nthRoot 2 value
500 u = src `UF.bind` \x ->
503 in UF.fold FL.toList u start
505{-# INLINE toListSome #-}
506toListSome :: Monad m => Int -> Int -> m [Int]
507toListSome value start = do
508 let end = start + nthRoot 2 value
516 u = src `UF.bind` \x ->
519 in UF.fold FL.toList (UF.take 1000 u) start
521{-# INLINE filterAllOut #-}
522filterAllOut :: Monad m => Int -> Int -> m ()
523filterAllOut value start = do
524 let end = start + nthRoot 2 value
531 u = src `UF.bind` \x ->
536 else UF.nilM (return . const ())
537 in UF.fold FL.drain u start
539{-# INLINE filterAllIn #-}
540filterAllIn :: Monad m => Int -> Int -> m ()
541filterAllIn value start = do
542 let end = start + nthRoot 2 value
549 u = src `UF.bind` \x ->
554 else UF.nilM (return . const ())
555 in UF.fold FL.drain u start
557{-# INLINE filterSome #-}
558filterSome :: Monad m => Int -> Int -> m ()
559filterSome value start = do
560 let end = start + nthRoot 2 value
567 u = src `UF.bind` \x ->
572 else UF.nilM (return . const ())
573 in UF.fold FL.drain u start
575{-# INLINE breakAfterSome #-}
576breakAfterSome :: Int -> Int -> IO ()
577breakAfterSome value start =
578 let end = start + nthRoot 2 value
585 u = src `UF.bind` \x ->
592 (_ :: Either ErrorCall ()) <- try $ UF.fold FL.drain u start
595-------------------------------------------------------------------------------
597-------------------------------------------------------------------------------
599-- n * (n + 1) / 2 == linearCount
600concatCount :: Int -> Int
601concatCount linearCount =
602 round (((1 + 8 * fromIntegral linearCount)**(1/2::Double) - 1) / 2)
605many :: Monad m => Int -> Int -> m ()
606many linearCount start = do
607 let end = start + concatCount linearCount
608 UF.fold FL.drain (UF.many (source end) (source end)) start
610-------------------------------------------------------------------------------
612-------------------------------------------------------------------------------
615moduleName = "Data.Unfold"
617o_1_space_transformation_input :: Int -> [Benchmark]
618o_1_space_transformation_input size =
620 "transformation/input"
621 [ benchIO "lmap" $ lmap size
622 , benchIO "lmapM" $ lmapM size
623 , benchIO "both" $ both size
624 , benchIO "first" $ first size
625 , benchIO "second" $ second size
626 , benchIO "discardFirst" $ discardFirst size
627 , benchIO "discardSecond" $ discardSecond size
628 , benchIO "swap" $ swap size
632o_1_space_generation :: Int -> [Benchmark]
633o_1_space_generation size =
636 [ benchIO "fromStream" $ fromStream size
637 , benchIO "fromStreamK" $ fromStreamK size
638 , benchIO "fromStreamD" $ fromStreamD size
639 -- Very small benchmarks, reporting in ns
640 -- , benchIO "nilM" $ nilM size
641 , benchIO "consM" $ consM size
642 -- , benchIO "functionM" $ functionM size
643 -- , benchIO "function" $ function size
644 -- , benchIO "identity" $ identity size
645 -- , benchIO "const" $ const size
646 , benchIO "unfoldrM" $ unfoldrM size
647 , benchIO "fromList" $ fromList size
648 , benchIO "fromListM" $ fromListM size
650 -- , benchIO "fromSVar" $ fromSVar size
651 -- , benchIO "fromProducer" $ fromProducer size
652 , benchIO "replicateM" $ replicateM size
653 , benchIO "repeatM" $ repeatM size
654 , benchIO "iterateM" $ iterateM size
655 , benchIO "fromIndicesM" $ fromIndicesM size
656 , benchIO "enumerateFromThenIntegral" $ enumerateFromThenIntegral size
657 , benchIO "enumerateFromToIntegral" $ enumerateFromToIntegral size
658 , benchIO "enumerateFromIntegral" $ enumerateFromIntegral size
659 , benchIO "enumerateFromStepNum" $ enumerateFromStepNum size
660 , benchIO "enumerateFromNum" $ enumerateFromNum size
661 , benchIO "enumerateFromToFractional" $ enumerateFromToFractional size
665o_1_space_transformation :: Int -> [Benchmark]
666o_1_space_transformation size =
669 [ benchIO "map" $ map size
670 , benchIO "mapM" $ mapM size
671 , benchIO "mapM2" $ mapM2 size
672 , benchIO "postscan" $ postscan size
676o_1_space_filtering :: Int -> [Benchmark]
677o_1_space_filtering size =
680 [ benchIO "takeWhileM" $ takeWhileM size
681 , benchIO "takeWhile" $ takeWhile size
682 , benchIO "take" $ take size
683 , benchIO "filter" $ filter size
684 , benchIO "filterM" $ filterM size
685 -- Very small benchmark, reporting in ns
686 -- , benchIO "dropOne" $ dropOne size
687 , benchIO "dropAll" $ dropAll size
688 , benchIO "dropWhileTrue" $ dropWhileTrue size
689 , benchIO "dropWhileFalse" $ dropWhileFalse size
690 , benchIO "dropWhileMTrue" $ dropWhileMTrue size
691 , benchIO "dropWhileMFalse" $ dropWhileMFalse size
695o_1_space_zip :: Int -> [Benchmark]
699 [ benchIO "zipWithM" $ zipWithM size
700 , benchIO "zipWith" $ zipWith size
701 , benchIO "teeZipWith" $ teeZipWith size
706lf = fromIntegral (ord '\n')
708-- | Split on line feed.
709foldManySepBy :: Handle -> IO Int
711 let u = UF.foldMany (FL.takeEndBy_ (== lf) FL.drain) FH.reader
712 in UF.fold FL.length u
714o_1_space_nested :: BenchEnv -> Int -> [Benchmark]
715o_1_space_nested env size =
718 [ benchIO "(<*>) (sqrt n x sqrt n)" $ toNullAp size
720 -- , benchIO "apDiscardFst" $ apDiscardFst size
721 -- , benchIO "apDiscardSnd" $ apDiscardSnd size
723 , benchIO "concatMapM (sqrt n x sqrt n)" $ concatMapM size
724 , benchIO "(>>=) (sqrt n x sqrt n)" $ toNull size
725 , benchIO "(>>=) (cubert n x cubert n x cubert n)" $ toNull3 size
726 , benchIO "breakAfterSome" $ breakAfterSome size
727 , benchIO "filterAllOut" $ filterAllOut size
728 , benchIO "filterAllIn" $ filterAllIn size
729 , benchIO "filterSome" $ filterSome size
731 , benchIO "many" $ many size
732 , mkBench "foldMany (Fold.takeEndBy_ (== lf) Fold.drain)" env
733 $ \inh _ -> foldManySepBy inh
737o_n_space_nested :: Int -> [Benchmark]
738o_n_space_nested size =
741 [ benchIO "toList" $ toList size
742 , benchIO "toListSome" $ toListSome size
746-------------------------------------------------------------------------------
747-- Unfold Exception Benchmarks
748-------------------------------------------------------------------------------
749-- | Send the file contents to /dev/null with exception handling
750readWriteOnExceptionUnfold :: Handle -> Handle -> IO ()
751readWriteOnExceptionUnfold inh devNull =
752 let readEx = UF.onException (\_ -> hClose inh) FH.reader
753 in S.fold (FH.write devNull) $ S.unfold readEx inh
756-- inspect $ hasNoTypeClasses 'readWriteOnExceptionUnfold
757-- inspect $ 'readWriteOnExceptionUnfold `hasNoType` ''Step
760-- | Send the file contents to /dev/null with exception handling
761readWriteHandleExceptionUnfold :: Handle -> Handle -> IO ()
762readWriteHandleExceptionUnfold inh devNull =
763 let handler (_e :: SomeException) = hClose inh >> return 10
764 readEx = UF.handle (UF.functionM handler) FH.reader
765 in S.fold (FH.write devNull) $ S.unfold readEx inh
768-- hasNoTypeClasses started failing in GHC 9.4.4
769-- inspect $ hasNoTypeClasses 'readWriteHandleExceptionUnfold
770-- inspect $ 'readWriteHandleExceptionUnfold `hasNoType` ''Step
773-- | Send the file contents to /dev/null with exception handling
774readWriteFinally_Unfold :: Handle -> Handle -> IO ()
775readWriteFinally_Unfold inh devNull =
776 let readEx = UF.finally_ (\_ -> hClose inh) FH.reader
777 in S.fold (FH.write devNull) $ S.unfold readEx inh
780#if __GLASGOW_HASKELL__ >= 906
781inspect $ hasNoTypeClassesExcept 'readWriteFinally_Unfold [''MonadCatch]
783inspect $ hasNoTypeClasses 'readWriteFinally_Unfold
785-- inspect $ 'readWriteFinallyUnfold `hasNoType` ''Step
788readWriteFinallyUnfold :: Handle -> Handle -> IO ()
789readWriteFinallyUnfold inh devNull =
790 let readEx = UF.finally (\_ -> hClose inh) FH.reader
791 in S.fold (FH.write devNull) $ S.unfold readEx inh
793-- | Send the file contents to /dev/null with exception handling
794readWriteBracket_Unfold :: Handle -> Handle -> IO ()
795readWriteBracket_Unfold inh devNull =
796 let readEx = UF.bracket_ return (\_ -> hClose inh) FH.reader
797 in S.fold (FH.write devNull) $ S.unfold readEx inh
800#if __GLASGOW_HASKELL__ >= 906
801inspect $ hasNoTypeClassesExcept 'readWriteBracket_Unfold [''MonadCatch]
803inspect $ hasNoTypeClasses 'readWriteBracket_Unfold
805-- inspect $ 'readWriteBracketUnfold `hasNoType` ''Step
808readWriteBracketUnfold :: Handle -> Handle -> IO ()
809readWriteBracketUnfold inh devNull =
810 let readEx = UF.bracket return (\_ -> hClose inh) FH.reader
811 in S.fold (FH.write devNull) $ S.unfold readEx inh
813o_1_space_copy_read_exceptions :: BenchEnv -> [Benchmark]
814o_1_space_copy_read_exceptions env =
815 [ bgroup "exceptions"
816 [ mkBenchSmall "UF.onException" env $ \inh _ ->
817 readWriteOnExceptionUnfold inh (nullH env)
818 , mkBenchSmall "UF.handle" env $ \inh _ ->
819 readWriteHandleExceptionUnfold inh (nullH env)
820 , mkBenchSmall "UF.finally_" env $ \inh _ ->
821 readWriteFinally_Unfold inh (nullH env)
822 , mkBenchSmall "UF.finally" env $ \inh _ ->
823 readWriteFinallyUnfold inh (nullH env)
824 , mkBenchSmall "UF.bracket_" env $ \inh _ ->
825 readWriteBracket_Unfold inh (nullH env)
826 , mkBenchSmall "UF.bracket" env $ \inh _ ->
827 readWriteBracketUnfold inh (nullH env)
832-------------------------------------------------------------------------------
834-------------------------------------------------------------------------------
838 env <- mkHandleBenchEnv
839 runWithCLIOpts defaultStreamSize (allBenchmarks env)
843 allBenchmarks env size =
844 [ bgroup (o_1_space_prefix moduleName)
846 [ o_1_space_transformation_input size
847 , o_1_space_generation size
848 , o_1_space_transformation size
849 , o_1_space_filtering size
851 , o_1_space_nested env size
852 , o_1_space_copy_read_exceptions env
854 , bgroup (o_n_space_prefix moduleName)
855 $ Prelude.concat [o_n_space_nested size]
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list