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.Stream.IsStream as S
35import qualified Streamly.Internal.Data.Stream.StreamD as D
36import qualified Streamly.Internal.Data.Stream.StreamK as K
37import qualified Streamly.Prelude as SP
39import Gauge hiding (env)
40import Prelude hiding (concat, take, filter, zipWith, map, mapM, takeWhile)
41import Streamly.Benchmark.Common
42import Streamly.Benchmark.Common.Handle
49benchIO :: (NFData b) => String -> (Int -> IO b) -> Benchmark
50benchIO name f = bench name $ nfIO $ randomRIO (1,1) >>= f
52-------------------------------------------------------------------------------
53-- Stream generation and elimination
54-------------------------------------------------------------------------------
56-- generate numbers up to the argument value
58source :: Monad m => Int -> Unfold m Int Int
59source n = UF.second n UF.enumerateFromToIntegral
61-------------------------------------------------------------------------------
63-------------------------------------------------------------------------------
65{-# INLINE drainGeneration #-}
66drainGeneration :: Monad m => Unfold m a b -> a -> m ()
67drainGeneration unf seed = UF.fold FL.drain unf seed
69{-# INLINE drainTransformation #-}
71 Monad m => Unfold m a b -> (Unfold m a b -> Unfold m c d) -> c -> m ()
72drainTransformation unf f seed = drainGeneration (f unf) seed
74{-# INLINE drainTransformationDefault #-}
75drainTransformationDefault ::
76 Monad m => Int -> (Unfold m Int Int -> Unfold m c d) -> c -> m ()
77drainTransformationDefault to =
78 drainTransformation (UF.second to UF.enumerateFromToIntegral)
80{-# INLINE drainProduct #-}
85 -> (Unfold m a b -> Unfold m c d -> Unfold m e f)
88drainProduct unf1 unf2 f seed = drainGeneration (f unf1 unf2) seed
90{-# INLINE drainProductDefault #-}
94 -> (Unfold m Int Int -> Unfold m Int Int -> Unfold m e f)
97drainProductDefault to = drainProduct src src
101 src = UF.second to UF.enumerateFromToIntegral
103-------------------------------------------------------------------------------
104-- Operations on input
105-------------------------------------------------------------------------------
108lmap :: Monad m => Int -> Int -> m ()
110 drainTransformationDefault (size + start) (UF.lmap (+ 1)) start
113lmapM :: Monad m => Int -> Int -> m ()
115 drainTransformationDefault (size + start) (UF.lmapM (return . (+) 1)) start
118both :: Monad m => Int -> Int -> m ()
120 drainTransformationDefault (size + start) (UF.both start) undefined
124first :: Monad m => Int -> Int -> m ()
127 (UF.take size UF.enumerateFromThenIntegral)
132second :: Monad m => Int -> Int -> m ()
135 (UF.take size UF.enumerateFromThenIntegral)
139{-# INLINE discardFirst #-}
140discardFirst :: Monad m => Int -> Int -> m ()
141discardFirst size start =
142 drainTransformationDefault (size + start) UF.discardFirst (start, start)
144{-# INLINE discardSecond #-}
145discardSecond :: Monad m => Int -> Int -> m ()
146discardSecond size start =
147 drainTransformationDefault (size + start) UF.discardSecond (start, start)
150swap :: Monad m => Int -> Int -> m ()
153 (UF.take size UF.enumerateFromThenIntegral)
157-------------------------------------------------------------------------------
159-------------------------------------------------------------------------------
161{-# INLINE fromStream #-}
162fromStream :: Int -> Int -> IO ()
163fromStream size start =
164 drainGeneration UF.fromStream (S.replicate size start :: S.SerialT IO Int)
166-- XXX INVESTIGATE: Although the performance of this should be equivalant to
167-- fromStream, this is considerably worse. More than 4x worse.
168{-# INLINE fromStreamK #-}
169fromStreamK :: Monad m => Int -> Int -> m ()
170fromStreamK size start = drainGeneration UF.fromStreamK (K.replicate size start)
172{-# INLINE fromStreamD #-}
173fromStreamD :: Monad m => Int -> Int -> m ()
174fromStreamD size start =
175 drainGeneration UF.fromStreamD (D.replicate size start)
178_nilM :: Monad m => Int -> Int -> m ()
179_nilM _ start = drainGeneration (UF.nilM return) start
182consM :: Monad m => Int -> Int -> m ()
184 drainTransformationDefault (size + start) (UF.consM return) start
186{-# INLINE _functionM #-}
187_functionM :: Monad m => Int -> Int -> m ()
188_functionM _ start = drainGeneration (UF.functionM return) start
190{-# INLINE _function #-}
191_function :: Monad m => Int -> Int -> m ()
192_function _ start = drainGeneration (UF.function id) start
194{-# INLINE _identity #-}
195_identity :: Monad m => Int -> Int -> m ()
196_identity _ start = drainGeneration UF.identity start
199_const :: Monad m => Int -> Int -> m ()
201 drainGeneration (UF.take size (UF.fromEffect (return start))) undefined
203{-# INLINE unfoldrM #-}
204unfoldrM :: Monad m => Int -> Int -> m ()
205unfoldrM size start = drainGeneration (UF.unfoldrM step) start
211 $ if i < start + size
215{-# INLINE fromList #-}
216fromList :: Monad m => Int -> Int -> m ()
217fromList size start = drainGeneration UF.fromList [start .. start + size]
219{-# INLINE fromListM #-}
220fromListM :: Monad m => Int -> Int -> m ()
221fromListM size start =
222 drainGeneration UF.fromListM (Prelude.map return [start .. start + size])
224{-# INLINE _fromSVar #-}
225_fromSVar :: Int -> Int -> m ()
228{-# INLINE _fromProducer #-}
229_fromProducer :: Int -> Int -> m ()
230_fromProducer = undefined
232{-# INLINE replicateM #-}
233replicateM :: Monad m => Int -> Int -> m ()
234replicateM size start = drainGeneration (UF.replicateM size) (return start)
236{-# INLINE repeatM #-}
237repeatM :: Monad m => Int -> Int -> m ()
238repeatM size start = drainGeneration (UF.take size UF.repeatM) (return start)
240{-# INLINE iterateM #-}
241iterateM :: Monad m => Int -> Int -> m ()
243 drainGeneration (UF.take size (UF.iterateM return)) (return start)
245{-# INLINE fromIndicesM #-}
246fromIndicesM :: Monad m => Int -> Int -> m ()
247fromIndicesM size start =
248 drainGeneration (UF.take size (UF.fromIndicesM return)) start
250{-# INLINE enumerateFromThenIntegral #-}
251enumerateFromThenIntegral :: Monad m => Int -> Int -> m ()
252enumerateFromThenIntegral size start =
253 drainGeneration (UF.take size UF.enumerateFromThenIntegral) (start, 1)
255{-# INLINE enumerateFromToIntegral #-}
256enumerateFromToIntegral :: Monad m => Int -> Int -> m ()
257enumerateFromToIntegral size start =
261 UF.enumerateFromToIntegral
264{-# INLINE enumerateFromIntegral #-}
265enumerateFromIntegral :: Monad m => Int -> Int -> m ()
266enumerateFromIntegral size start =
267 drainGeneration (UF.take size UF.enumerateFromIntegral) start
269{-# INLINE enumerateFromStepNum #-}
270enumerateFromStepNum :: Monad m => Int -> Int -> m ()
271enumerateFromStepNum size start =
272 drainGeneration (UF.take size (UF.enumerateFromThenNum)) (start, 1)
274{-# INLINE enumerateFromNum #-}
275enumerateFromNum :: Monad m => Int -> Int -> m ()
276enumerateFromNum size start = drainGeneration (UF.take size UF.enumerateFromNum) start
278{-# INLINE enumerateFromToFractional #-}
279enumerateFromToFractional :: Monad m => Int -> Int -> m ()
280enumerateFromToFractional size start =
281 let intToDouble x = (fromInteger (fromIntegral x)) :: Double
284 (intToDouble $ start + size)
285 UF.enumerateFromToFractional
289-------------------------------------------------------------------------------
290-- Stream transformation
291-------------------------------------------------------------------------------
293{-# INLINE postscan #-}
294postscan :: Monad m => Int -> Int -> m ()
296 drainTransformationDefault (size + start) (UF.postscan FL.sum) start
299map :: Monad m => Int -> Int -> m ()
300map size start = drainTransformationDefault (size + start) (UF.map (+1)) start
303mapM :: Monad m => Int -> Int -> m ()
305 drainTransformationDefault (size + start) (UF.mapM (return . (+) 1)) start
307{-# INLINE mapMWithInput #-}
308mapMWithInput :: Monad m => Int -> Int -> m ()
309mapMWithInput size start =
310 drainTransformationDefault
312 (UF.mapMWithInput (\a b -> return $ a + b))
315-------------------------------------------------------------------------------
317-------------------------------------------------------------------------------
319{-# INLINE takeWhileM #-}
320takeWhileM :: Monad m => Int -> Int -> m ()
321takeWhileM size start =
322 drainTransformationDefault
324 (UF.takeWhileM (\b -> return (b <= size + start)))
327{-# INLINE takeWhile #-}
328takeWhile :: Monad m => Int -> Int -> m ()
329takeWhile size start =
330 drainTransformationDefault
332 (UF.takeWhile (\b -> b <= size + start))
336take :: Monad m => Int -> Int -> m ()
337take size start = drainTransformationDefault (size + start) (UF.take size) start
340filter :: Monad m => Int -> Int -> m ()
342 drainTransformationDefault (size + start) (UF.filter (\_ -> True)) start
344{-# INLINE filterM #-}
345filterM :: Monad m => Int -> Int -> m ()
347 drainTransformationDefault
349 (UF.filterM (\_ -> (return True)))
352{-# INLINE _dropOne #-}
353_dropOne :: Monad m => Int -> Int -> m ()
355 drainTransformationDefault (size + start) (UF.drop 1) start
357{-# INLINE dropAll #-}
358dropAll :: Monad m => Int -> Int -> m ()
360 drainTransformationDefault (size + start) (UF.drop (size + 1)) start
362{-# INLINE dropWhileTrue #-}
363dropWhileTrue :: Monad m => Int -> Int -> m ()
364dropWhileTrue size start =
365 drainTransformationDefault
367 (UF.dropWhileM (\_ -> return True))
370{-# INLINE dropWhileFalse #-}
371dropWhileFalse :: Monad m => Int -> Int -> m ()
372dropWhileFalse size start =
373 drainTransformationDefault
375 (UF.dropWhileM (\_ -> return False))
378{-# INLINE dropWhileMTrue #-}
379dropWhileMTrue :: Monad m => Int -> Int -> m ()
380dropWhileMTrue size start =
381 drainTransformationDefault
383 (UF.dropWhileM (\_ -> return True))
386{-# INLINE dropWhileMFalse #-}
387dropWhileMFalse :: Monad m => Int -> Int -> m ()
388dropWhileMFalse size start =
389 drainTransformationDefault
391 (UF.dropWhileM (\_ -> return False))
394-------------------------------------------------------------------------------
396-------------------------------------------------------------------------------
398{-# INLINE zipWith #-}
399zipWith :: Monad m => Int -> Int -> m ()
401 drainProductDefault (size + start) (UF.zipWith (+)) start
403{-# INLINE zipWithM #-}
404zipWithM :: Monad m => Int -> Int -> m ()
408 (UF.zipWithM (\a b -> return $ a + b))
411{-# INLINE teeZipWith #-}
412teeZipWith :: Monad m => Int -> Int -> m ()
413teeZipWith size start =
414 drainProductDefault (size + start) (UF.zipWith (+)) start
416-------------------------------------------------------------------------------
418-------------------------------------------------------------------------------
420{-# INLINE toNullAp #-}
421toNullAp :: Monad m => Int -> Int -> m ()
422toNullAp value start =
423 let end = start + nthRoot 2 value
425 -- in UF.fold ((+) <$> s <*> s) FL.drain start
426 in UF.fold FL.drain ((+) `fmap` s `UF.apply` s) start
428{-# INLINE _apDiscardFst #-}
429_apDiscardFst :: Int -> Int -> m ()
430_apDiscardFst = undefined
432{-# INLINE _apDiscardSnd #-}
433_apDiscardSnd :: Int -> Int -> m ()
434_apDiscardSnd = undefined
436-------------------------------------------------------------------------------
438-------------------------------------------------------------------------------
440nthRoot :: Double -> Int -> Int
441nthRoot n value = round (fromIntegral value**(1/n))
443{-# INLINE concatMapM #-}
444concatMapM :: Monad m => Int -> Int -> m ()
445concatMapM value start =
446 val `seq` drainGeneration (UF.concatMapM unfoldInGen unfoldOut) start
450 val = nthRoot 2 value
451 unfoldInGen i = return (UF.second (i + val) UF.enumerateFromToIntegral)
452 unfoldOut = UF.second (start + val) UF.enumerateFromToIntegral
455toNull :: Monad m => Int -> Int -> m ()
457 let end = start + nthRoot 2 value
465 u = src `UF.bind` \x ->
468 in UF.fold FL.drain u start
471{-# INLINE toNull3 #-}
472toNull3 :: Monad m => Int -> Int -> m ()
474 let end = start + nthRoot 3 value
483 u = src `UF.bind` \x ->
486 in UF.fold FL.drain u start
489toList :: Monad m => Int -> Int -> m [Int]
490toList value start = do
491 let end = start + nthRoot 2 value
499 u = src `UF.bind` \x ->
502 in UF.fold FL.toList u start
504{-# INLINE toListSome #-}
505toListSome :: Monad m => Int -> Int -> m [Int]
506toListSome value start = do
507 let end = start + nthRoot 2 value
515 u = src `UF.bind` \x ->
518 in UF.fold FL.toList (UF.take 1000 u) start
520{-# INLINE filterAllOut #-}
521filterAllOut :: Monad m => Int -> Int -> m ()
522filterAllOut value start = do
523 let end = start + nthRoot 2 value
530 u = src `UF.bind` \x ->
535 else UF.nilM (return . const ())
536 in UF.fold FL.drain u start
538{-# INLINE filterAllIn #-}
539filterAllIn :: Monad m => Int -> Int -> m ()
540filterAllIn value start = do
541 let end = start + nthRoot 2 value
548 u = src `UF.bind` \x ->
553 else UF.nilM (return . const ())
554 in UF.fold FL.drain u start
556{-# INLINE filterSome #-}
557filterSome :: Monad m => Int -> Int -> m ()
558filterSome value start = do
559 let end = start + nthRoot 2 value
566 u = src `UF.bind` \x ->
571 else UF.nilM (return . const ())
572 in UF.fold FL.drain u start
574{-# INLINE breakAfterSome #-}
575breakAfterSome :: Int -> Int -> IO ()
576breakAfterSome value start =
577 let end = start + nthRoot 2 value
584 u = src `UF.bind` \x ->
591 (_ :: Either ErrorCall ()) <- try $ UF.fold FL.drain u start
594-------------------------------------------------------------------------------
596-------------------------------------------------------------------------------
598-- n * (n + 1) / 2 == linearCount
599concatCount :: Int -> Int
600concatCount linearCount =
601 round (((1 + 8 * fromIntegral linearCount)**(1/2::Double) - 1) / 2)
604concat :: Monad m => Int -> Int -> m ()
605concat linearCount start = do
606 let end = start + concatCount linearCount
607 UF.fold FL.drain (UF.many (source end) (source end)) start
609-------------------------------------------------------------------------------
611-------------------------------------------------------------------------------
614moduleName = "Data.Unfold"
616o_1_space_transformation_input :: Int -> [Benchmark]
617o_1_space_transformation_input size =
619 "transformation/input"
620 [ benchIO "lmap" $ lmap size
621 , benchIO "lmapM" $ lmapM size
622 , benchIO "both" $ both size
623 , benchIO "first" $ first size
624 , benchIO "second" $ second size
625 , benchIO "discardFirst" $ discardFirst size
626 , benchIO "discardSecond" $ discardSecond size
627 , benchIO "swap" $ swap size
631o_1_space_generation :: Int -> [Benchmark]
632o_1_space_generation size =
635 [ benchIO "fromStream" $ fromStream size
636 , benchIO "fromStreamK" $ fromStreamK size
637 , benchIO "fromStreamD" $ fromStreamD size
638 -- Very small benchmarks, reporting in ns
639 -- , benchIO "nilM" $ nilM size
640 , benchIO "consM" $ consM size
641 -- , benchIO "functionM" $ functionM size
642 -- , benchIO "function" $ function size
643 -- , benchIO "identity" $ identity size
644 -- , benchIO "const" $ const size
645 , benchIO "unfoldrM" $ unfoldrM size
646 , benchIO "fromList" $ fromList size
647 , benchIO "fromListM" $ fromListM size
649 -- , benchIO "fromSVar" $ fromSVar size
650 -- , benchIO "fromProducer" $ fromProducer size
651 , benchIO "replicateM" $ replicateM size
652 , benchIO "repeatM" $ repeatM size
653 , benchIO "iterateM" $ iterateM size
654 , benchIO "fromIndicesM" $ fromIndicesM size
655 , benchIO "enumerateFromThenIntegral" $ enumerateFromThenIntegral size
656 , benchIO "enumerateFromToIntegral" $ enumerateFromToIntegral size
657 , benchIO "enumerateFromIntegral" $ enumerateFromIntegral size
658 , benchIO "enumerateFromStepNum" $ enumerateFromStepNum size
659 , benchIO "enumerateFromNum" $ enumerateFromNum size
660 , benchIO "enumerateFromToFractional" $ enumerateFromToFractional size
664o_1_space_transformation :: Int -> [Benchmark]
665o_1_space_transformation size =
668 [ benchIO "map" $ map size
669 , benchIO "mapM" $ mapM size
670 , benchIO "mapMWithInput" $ mapMWithInput size
671 , benchIO "postscan" $ postscan size
675o_1_space_filtering :: Int -> [Benchmark]
676o_1_space_filtering size =
679 [ benchIO "takeWhileM" $ takeWhileM size
680 , benchIO "takeWhile" $ takeWhile size
681 , benchIO "take" $ take size
682 , benchIO "filter" $ filter size
683 , benchIO "filterM" $ filterM size
684 -- Very small benchmark, reporting in ns
685 -- , benchIO "dropOne" $ dropOne size
686 , benchIO "dropAll" $ dropAll size
687 , benchIO "dropWhileTrue" $ dropWhileTrue size
688 , benchIO "dropWhileFalse" $ dropWhileFalse size
689 , benchIO "dropWhileMTrue" $ dropWhileMTrue size
690 , benchIO "dropWhileMFalse" $ dropWhileMFalse size
694o_1_space_zip :: Int -> [Benchmark]
698 [ benchIO "zipWithM" $ zipWithM size
699 , benchIO "zipWith" $ zipWith size
700 , benchIO "teeZipWith" $ teeZipWith size
705lf = fromIntegral (ord '\n')
707-- | Split on line feed.
708foldManySepBy :: Handle -> IO Int
710 let u = UF.foldMany (FL.takeEndBy_ (== lf) FL.drain) FH.read
711 in UF.fold FL.length u
713o_1_space_nested :: BenchEnv -> Int -> [Benchmark]
714o_1_space_nested env size =
717 [ benchIO "(<*>) (sqrt n x sqrt n)" $ toNullAp size
719 -- , benchIO "apDiscardFst" $ apDiscardFst size
720 -- , benchIO "apDiscardSnd" $ apDiscardSnd size
722 , benchIO "concatMapM (sqrt n x sqrt n)" $ concatMapM size
723 , benchIO "(>>=) (sqrt n x sqrt n)" $ toNull size
724 , benchIO "(>>=) (cubert n x cubert n x cubert n)" $ toNull3 size
725 , benchIO "breakAfterSome" $ breakAfterSome size
726 , benchIO "filterAllOut" $ filterAllOut size
727 , benchIO "filterAllIn" $ filterAllIn size
728 , benchIO "filterSome" $ filterSome size
730 , benchIO "concat" $ concat size
731 , mkBench "foldMany (Fold.takeEndBy_ (== lf) Fold.drain)" env
732 $ \inh _ -> foldManySepBy inh
736o_n_space_nested :: Int -> [Benchmark]
737o_n_space_nested size =
740 [ benchIO "toList" $ toList size
741 , benchIO "toListSome" $ toListSome size
745-------------------------------------------------------------------------------
746-- Unfold Exception Benchmarks
747-------------------------------------------------------------------------------
748-- | Send the file contents to /dev/null with exception handling
749readWriteOnExceptionUnfold :: Handle -> Handle -> IO ()
750readWriteOnExceptionUnfold inh devNull =
751 let readEx = UF.onException (\_ -> hClose inh) FH.read
752 in SP.fold (FH.write devNull) $ SP.unfold readEx inh
755inspect $ hasNoTypeClasses 'readWriteOnExceptionUnfold
756-- inspect $ 'readWriteOnExceptionUnfold `hasNoType` ''Step
759-- | Send the file contents to /dev/null with exception handling
760readWriteHandleExceptionUnfold :: Handle -> Handle -> IO ()
761readWriteHandleExceptionUnfold inh devNull =
762 let handler (_e :: SomeException) = hClose inh >> return 10
763 readEx = UF.handle (UF.functionM handler) FH.read
764 in SP.fold (FH.write devNull) $ SP.unfold readEx inh
767inspect $ hasNoTypeClasses 'readWriteHandleExceptionUnfold
768-- inspect $ 'readWriteHandleExceptionUnfold `hasNoType` ''Step
771-- | Send the file contents to /dev/null with exception handling
772readWriteFinally_Unfold :: Handle -> Handle -> IO ()
773readWriteFinally_Unfold inh devNull =
774 let readEx = UF.finally_ (\_ -> hClose inh) FH.read
775 in SP.fold (FH.write devNull) $ SP.unfold readEx inh
778inspect $ hasNoTypeClasses 'readWriteFinally_Unfold
779-- inspect $ 'readWriteFinallyUnfold `hasNoType` ''Step
782readWriteFinallyUnfold :: Handle -> Handle -> IO ()
783readWriteFinallyUnfold inh devNull =
784 let readEx = UF.finally (\_ -> hClose inh) FH.read
785 in SP.fold (FH.write devNull) $ SP.unfold readEx inh
787-- | Send the file contents to /dev/null with exception handling
788readWriteBracket_Unfold :: Handle -> Handle -> IO ()
789readWriteBracket_Unfold inh devNull =
790 let readEx = UF.bracket_ return (\_ -> hClose inh) FH.read
791 in SP.fold (FH.write devNull) $ SP.unfold readEx inh
794inspect $ hasNoTypeClasses 'readWriteBracket_Unfold
795-- inspect $ 'readWriteBracketUnfold `hasNoType` ''Step
798readWriteBracketUnfold :: Handle -> Handle -> IO ()
799readWriteBracketUnfold inh devNull =
800 let readEx = UF.bracket return (\_ -> hClose inh) FH.read
801 in SP.fold (FH.write devNull) $ S.unfold readEx inh
803o_1_space_copy_read_exceptions :: BenchEnv -> [Benchmark]
804o_1_space_copy_read_exceptions env =
805 [ bgroup "exceptions"
806 [ mkBenchSmall "UF.onException" env $ \inh _ ->
807 readWriteOnExceptionUnfold inh (nullH env)
808 , mkBenchSmall "UF.handle" env $ \inh _ ->
809 readWriteHandleExceptionUnfold inh (nullH env)
810 , mkBenchSmall "UF.finally_" env $ \inh _ ->
811 readWriteFinally_Unfold inh (nullH env)
812 , mkBenchSmall "UF.finally" env $ \inh _ ->
813 readWriteFinallyUnfold inh (nullH env)
814 , mkBenchSmall "UF.bracket_" env $ \inh _ ->
815 readWriteBracket_Unfold inh (nullH env)
816 , mkBenchSmall "UF.bracket" env $ \inh _ ->
817 readWriteBracketUnfold inh (nullH env)
822-------------------------------------------------------------------------------
824-------------------------------------------------------------------------------
828 env <- mkHandleBenchEnv
829 runWithCLIOpts defaultStreamSize (allBenchmarks env)
833 allBenchmarks env size =
834 [ bgroup (o_1_space_prefix moduleName)
836 [ o_1_space_transformation_input size
837 , o_1_space_generation size
838 , o_1_space_transformation size
839 , o_1_space_filtering size
841 , o_1_space_nested env size
842 , o_1_space_copy_read_exceptions env
844 , bgroup (o_n_space_prefix moduleName)
845 $ 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