packages feed

streamly-0.11.0: benchmark/streamly-benchmarks.cabal

cabal-version:      2.2
name:               streamly-benchmarks
version:            0.0.0
synopsis:           Benchmarks for streamly
description: Benchmarks are separated from the main package because we
  want to have a library for benchmarks to reuse the code across different
  benchmark executables. For example, we have common benchmarking code for
  different types of streams. We need different benchmarking executables
  for serial, async, ahead style streams, therefore, we need to use
  the common code in several benchmarks, just changing the type of
  the stream. It takes a long time to compile this file and it gets
  compiled for each benchmark once if we do not have a library.  Cabal
  does not support internal libraries without per-component builds and
  per-component builds are not supported with Configure, so we are not
  left with any other choice.

flag fusion-plugin
  description: Use fusion plugin for benchmarks and executables
  manual: True
  default: False

flag limit-build-mem
  description: Limits memory when building the executables
  manual: True
  default: False

flag inspection
  description: Enable inspection testing
  manual: True
  default: False

flag debug
  description: Debug build with asserts enabled
  manual: True
  default: False

flag dev
  description: Development build
  manual: True
  default: False

flag include-strict-utf8
  description: Include strict utf8 input benchmarks
  manual: True
  default: False

flag has-llvm
  description: Use llvm backend for better performance
  manual: True
  default: False

flag opt
  description: off=-O0 (faster builds), on=-O2
  manual: True
  default: True

flag use-streamly-core
  description: Benchmark only core package
  manual: True
  default: False

flag use-prelude
  description: Use Prelude instead of Data.Stream for serial benchmarks
  manual: True
  default: False

-------------------------------------------------------------------------------
-- Common stanzas
-------------------------------------------------------------------------------

common default-extensions
    default-language: Haskell2010

    -- GHC2024 may include more extensions than we are actually using, see the
    -- full list below. We enable this to ensure that we are able to compile
    -- with this i.e. there is no interference by other extensions.
    if impl(ghc >= 9.10)
      default-language: GHC2024

    if impl(ghc >= 9.2) && impl(ghc < 9.10)
      default-language: GHC2021

    if impl(ghc >= 8.10)
      default-extensions: StandaloneKindSignatures

    -- In GHC 2024
    default-extensions:
        BangPatterns
        ConstraintKinds
        DeriveDataTypeable
        DeriveGeneric
        DeriveTraversable
        ExistentialQuantification
        FlexibleContexts
        FlexibleInstances
        GeneralizedNewtypeDeriving
        InstanceSigs
        KindSignatures
        LambdaCase
        MultiParamTypeClasses
        RankNTypes
        ScopedTypeVariables
        TupleSections
        TypeApplications
        TypeOperators

        -- Not in GHC2024
        CPP
        MagicHash
        RecordWildCards

common compile-options
    import: default-extensions

    if flag(use-streamly-core)
      cpp-options:    -DUSE_STREAMLY_CORE

    if flag(dev)
      cpp-options:    -DDEVBUILD

    if flag(include-strict-utf8)
      cpp-options:    -DINCLUDE_STRICT_UTF8

    if flag(inspection)
      cpp-options:    -DINSPECTION

    ghc-options:    -Weverything
                    -Wno-implicit-prelude
                    -Wno-missing-deriving-strategies
                    -Wno-missing-exported-signatures
                    -Wno-missing-import-lists
                    -Wno-missing-local-signatures
                    -Wno-missing-safe-haskell-mode
                    -Wno-missed-specialisations
                    -Wno-all-missed-specialisations
                    -Wno-monomorphism-restriction
                    -Wno-prepositive-qualified-module
                    -Wno-unsafe
                    -Wno-unused-packages
                    -Rghc-timing

    if impl(ghc >= 9.2)
      ghc-options:
        -Wno-missing-kind-signatures
        -Wno-operator-whitespace

    if impl(ghc >= 9.8)
      ghc-options:
        -Wno-missing-role-annotations

    if flag(has-llvm)
      ghc-options: -fllvm

    if flag(dev)
      ghc-options:    -Wmissed-specialisations
                      -Wall-missed-specialisations

common optimization-options
  if flag(opt)
    ghc-options: -O2
                 -fdicts-strict
                 -fspec-constr-recursive=16
                 -fmax-worker-args=16

    -- For this to be effective it must come after the -O2 option
    if flag(dev) || flag(debug)
      ghc-options: -fno-ignore-asserts

    if flag(fusion-plugin) && !impl(ghcjs) && !impl(ghc < 8.6)
      ghc-options: -fplugin Fusion.Plugin
  else
    ghc-options: -O0

common lib-options
  import: compile-options, optimization-options

common bench-depends
  build-depends:
    -- Core libraries shipped with ghc, the min and max
    -- constraints of these libraries should match with
    -- the GHC versions we support
      base                >= 4.9   && < 4.22
    , deepseq             >= 1.4.1 && < 1.6
    , mtl                 >= 2.2   && < 2.3.2

    -- other libraries
    , exceptions >= 0.8   && < 0.11
    , random              >= 1.0   && < 2.0
    , transformers        >= 0.4   && < 0.7
    , containers          >= 0.5   && < 0.8
    , hashable            >= 1.3   && < 1.6
    , unordered-containers >= 0.2 && < 0.3
    , process             >= 1.4 && < 1.7
    , directory         >= 1.2.2 && < 1.4
    , filepath          >= 1.4.1 && < 1.6
    , ghc-prim          >= 0.4   && < 0.14
    , tasty-bench       >= 0.3 && < 0.5
    , tasty             >= 1.4.1 && < 1.6
    , streamly-core

  if !flag(use-streamly-core)
    build-depends:
          streamly
        , bench-test-lib

  if flag(fusion-plugin) && !impl(ghcjs) && !impl(ghc < 8.6)
    build-depends:
        fusion-plugin     >= 0.2   && < 0.3
  if flag(inspection)
    build-depends:     template-haskell   >= 2.14  && < 2.24
                     , inspection-testing >= 0.4   && < 0.6
  -- Array uses a Storable constraint in dev build making several inspection
  -- tests fail
  if flag(dev) && flag(inspection)
    build-depends: inspection-and-dev-flags-cannot-be-used-together

-------------------------------------------------------------------------------
-- Library
-------------------------------------------------------------------------------

library
    import: lib-options, bench-depends
    hs-source-dirs: lib
    exposed-modules: Streamly.Benchmark.Common
                    , Streamly.Benchmark.Common.Handle
    if flag(use-prelude)
      exposed-modules: Streamly.Benchmark.Prelude


-------------------------------------------------------------------------------
-- Benchmarks
-------------------------------------------------------------------------------

common bench-options
  import: compile-options, optimization-options, bench-depends
  include-dirs: .
  ghc-options: -rtsopts -with-rtsopts "-t"
  if flag(limit-build-mem)
    ghc-options: +RTS -M512M -RTS
  build-depends: streamly-benchmarks == 0.0.0

-- Some benchmarks are threaded some are not
common bench-options-threaded
  import: compile-options, optimization-options, bench-depends
  -- -threaded and -N2 is important because some GC and space leak issues
  -- trigger only with these options.
  ghc-options: -threaded -rtsopts -with-rtsopts "-t -N2"
  if flag(limit-build-mem)
    ghc-options: +RTS -M512M -RTS
  build-depends: streamly-benchmarks == 0.0.0

-------------------------------------------------------------------------------
-- Listed in alphabetical order
-------------------------------------------------------------------------------

benchmark Data.Array
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: ., Streamly/Benchmark/Data
  main-is: Streamly/Benchmark/Data/Array.hs
  other-modules:
      Stream.Common
  if flag(use-streamly-core)
    buildable: False
  else
    buildable: True
  if flag(limit-build-mem)
    ghc-options: +RTS -M1500M -RTS

benchmark Data.Array.Generic
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: ., Streamly/Benchmark/Data
  main-is: Streamly/Benchmark/Data/Array/Generic.hs
  other-modules:
      Stream.Common
  if flag(use-streamly-core)
    buildable: False
  else
    buildable: True
  if flag(limit-build-mem)
    ghc-options: +RTS -M1000M -RTS

benchmark Data.Array.Stream
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Array
  main-is: Stream.hs
  if flag(use-streamly-core) || impl(ghcjs)
    buildable: False
  else
    buildable: True
    build-depends: exceptions >= 0.8   && < 0.11

benchmark Data.Fold
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data
  main-is: Fold.hs
  if impl(ghcjs)
    buildable: False
  else
    buildable: True

benchmark Data.Fold.Prelude
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Fold
  -- XXX Using the name Prelude.hs causes compilation error
  main-is: Prelood.hs
  if flag(use-streamly-core) || impl(ghcjs)
    buildable: False
  else
    buildable: True

benchmark Data.Fold.Window
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Fold
  main-is: Window.hs
  -- MonoLocalBinds increases the memory requirement from 400MB to 1000MB,
  -- observed on macOS.
  if flag(limit-build-mem)
    ghc-options: +RTS -M1000M -RTS

benchmark Data.MutArray
  import: bench-options
  type: exitcode-stdio-1.0
  main-is: Streamly/Benchmark/Data/MutArray.hs
  if flag(limit-build-mem)
    ghc-options: +RTS -M1500M -RTS
  if flag(use-streamly-core)
    buildable: False
  else
    buildable: True

benchmark Data.Parser
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data
  main-is: Parser.hs
  if impl(ghcjs)
    buildable: False
  else
    buildable: True
    build-depends: exceptions >= 0.8   && < 0.11
  if flag(limit-build-mem)
    if flag(dev)
      ghc-options: +RTS -M3000M -RTS
    else
      ghc-options: +RTS -M2500M -RTS

benchmark Data.ParserK
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data
  cpp-options: -DBENCH_SINGULAR
  main-is: ParserK.hs
  if impl(ghcjs)
    buildable: False
  else
    buildable: True
    build-depends: exceptions >= 0.8   && < 0.11

benchmark Data.ParserK.Chunked
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data
  cpp-options: -DBENCH_CHUNKED
  main-is: ParserK.hs
  if impl(ghcjs)
    buildable: False
  else
    buildable: True
    build-depends: exceptions >= 0.8   && < 0.11

benchmark Data.ParserK.Chunked.Generic
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data
  cpp-options: -DBENCH_CHUNKED_GENERIC
  main-is: ParserK.hs
  if impl(ghcjs)
    buildable: False
  else
    buildable: True
    build-depends: exceptions >= 0.8   && < 0.11

benchmark Data.RingArray
  import: bench-options
  type: exitcode-stdio-1.0
  main-is: Streamly/Benchmark/Data/RingArray.hs
  if flag(limit-build-mem)
    ghc-options: +RTS -M1500M -RTS

benchmark Data.Scanl
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data
  main-is: Scanl.hs

benchmark Data.Scanl.Window
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Scanl
  main-is: Window.hs

benchmark Data.Scanl.Concurrent
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Scanl
  main-is: Concurrent.hs
  if flag(use-streamly-core) || impl(ghcjs)
    buildable: False
  else
    buildable: True

-- XXX Should be renamed to MutByteArray
benchmark Data.Serialize
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: .
  cpp-options: -DUSE_TH
  main-is: Streamly/Benchmark/Data/Serialize.hs
  build-depends: QuickCheck, template-haskell
  other-modules:
      Streamly.Benchmark.Data.Serialize.TH
      Streamly.Benchmark.Data.Serialize.RecCompatible
      Streamly.Benchmark.Data.Serialize.RecNonCompatible
  if flag(limit-build-mem)
    ghc-options: +RTS -M1000M -RTS

benchmark Data.SmallArray
  import: bench-options
  type: exitcode-stdio-1.0
  main-is: Streamly/Benchmark/Data/Array/SmallArray.hs
  if flag(dev) && !flag(use-streamly-core)
    buildable: True
  else
    buildable: False

benchmark Data.Stream
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data
  main-is: Stream.hs
  other-modules:
      Stream.Generate
      Stream.Eliminate
      Stream.Transform
      Stream.Reduce
      Stream.Expand
      Stream.Lift
      Stream.Split
      Stream.Common
  if !flag(use-streamly-core)
    other-modules:
      Stream.Exceptions
  if flag(limit-build-mem)
    if flag(dev)
      ghc-options: +RTS -M3500M -RTS
    else
      ghc-options: +RTS -M2500M -RTS

benchmark Data.Stream.Adaptive
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Stream
  main-is: Adaptive.hs
  if flag(use-streamly-core) || impl(ghcjs)
    buildable: False
  else
    buildable: True

benchmark Data.Stream.Concurrent
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/
  main-is: Concurrent.hs
  other-modules:
      Stream.ConcurrentCommon
      Stream.Common
  if flag(use-streamly-core) || impl(ghcjs)
    buildable: False
  else
    buildable: True

benchmark Data.Stream.ConcurrentEager
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/
  main-is: ConcurrentEager.hs
  other-modules:
      Stream.ConcurrentCommon
      Stream.Common
  if flag(use-streamly-core) || impl(ghcjs)
    buildable: False
  else
    buildable: True

benchmark Data.Stream.ConcurrentInterleaved
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/
  main-is: ConcurrentInterleaved.hs
  other-modules:
      Stream.ConcurrentCommon
      Stream.Common
  if flag(use-streamly-core) || impl(ghcjs)
    buildable: False
  else
    buildable: True

benchmark Data.Stream.ConcurrentOrdered
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/
  main-is: ConcurrentOrdered.hs
  other-modules:
      Stream.ConcurrentCommon
      Stream.Common
  if flag(use-streamly-core) || impl(ghcjs)
    buildable: False
  else
    buildable: True

benchmark Data.Stream.ConcurrentThreadHeavy
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Stream
  main-is: ConcurrentThreadHeavy.hs
  if flag(use-streamly-core) || impl(ghcjs)
    buildable: False
  else
    buildable: True

benchmark Data.Stream.Rate
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/Stream/, Streamly/Benchmark/Data/
  main-is: Rate.hs
  other-modules:
      Stream.ConcurrentCommon
      Stream.Common
  if flag(use-streamly-core) || impl(ghcjs)
    buildable: False
  else
    buildable: True

benchmark Data.StreamK
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data
  main-is: StreamK.hs
  if impl(ghcjs)
    buildable: False

-- XXX This needs to be cleaned up
benchmark Data.StreamK.FromStream
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/StreamK
  main-is: FromStream.hs
  if !flag(dev) || impl(ghcjs)
    buildable: False

benchmark Data.StreamK.StreamKAlt
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data/StreamK
  main-is: StreamKAlt.hs
  if !flag(dev) || impl(ghcjs)
    buildable: False

benchmark Data.Unbox
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: .
  cpp-options: -DUSE_UNBOX
  main-is: Streamly/Benchmark/Data/Serialize.hs

benchmark Data.Unbox.Derive.TH
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: .
  cpp-options: -DUSE_UNBOX
  cpp-options: -DUSE_TH
  main-is: Streamly/Benchmark/Data/Serialize.hs

benchmark Data.Unfold
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: .
  main-is: Streamly/Benchmark/Data/Unfold.hs
  if impl(ghcjs)
    buildable: False
  else
    buildable: True

benchmark FileSystem.Handle
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/FileSystem
  main-is: Handle.hs
  other-modules:
      Handle.Read
    , Handle.ReadWrite
  if flag(limit-build-mem)
    ghc-options: +RTS -M1000M -RTS
  if flag(use-streamly-core)
    buildable: False
  else
    buildable: True

benchmark FileSystem.DirIO
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/FileSystem
  main-is: DirIO.hs
  if flag(use-streamly-core)
    buildable: False
  else
    buildable: True
  -- Fix this benchmark for Windows
  if os(windows)
    buildable: False

benchmark Unicode.Char
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Unicode
  main-is: Char.hs
  -- Takes too much memory for ghcjs
  if flag(use-streamly-core) || impl(ghcjs)
    buildable: False

benchmark Unicode.Parser
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Unicode
  main-is: Parser.hs

executable nano-bench
  import: bench-options
  hs-source-dirs: .
  main-is: NanoBenchmarks.hs
  if !flag(dev)
    buildable: False

benchmark Unicode.Stream
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Unicode
  main-is: Stream.hs
  if flag(limit-build-mem)
    ghc-options: +RTS -M1000M -RTS
  if flag(use-streamly-core)
    buildable: False
  else
    buildable: True

benchmark Unicode.Utf8
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Unicode
  main-is: Utf8.hs
  if flag(use-streamly-core)
    buildable: False
  else
    buildable: True

-------------------------------------------------------------------------------
-- Deprecated
-------------------------------------------------------------------------------

benchmark Prelude
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Data
  main-is: Stream.hs
  other-modules:
      Stream.Generate
      Stream.Eliminate
      Stream.Transform
      Stream.Reduce
      Stream.Expand
      Stream.Lift
      Stream.Common
      Stream.Exceptions
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False
  if flag(limit-build-mem)
    if flag(dev)
      ghc-options: +RTS -M3500M -RTS
    else
      ghc-options: +RTS -M2500M -RTS

benchmark Prelude.WSerial
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Prelude
  main-is: WSerial.hs
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False
  if flag(limit-build-mem)
    ghc-options: +RTS -M750M -RTS

benchmark Prelude.Merge
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Prelude
  main-is: Merge.hs
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False

benchmark Prelude.ZipSerial
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Prelude
  main-is: ZipSerial.hs
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False

benchmark Prelude.ZipAsync
  import: bench-options
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Prelude
  main-is: ZipAsync.hs
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False
  if flag(limit-build-mem)
    ghc-options: +RTS -M1000M -RTS

benchmark Prelude.Ahead
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Prelude
  main-is: Ahead.hs
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False

benchmark Prelude.Async
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Prelude
  main-is: Async.hs
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False

benchmark Prelude.WAsync
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Prelude
  main-is: WAsync.hs
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False

benchmark Prelude.Parallel
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Prelude
  main-is: Parallel.hs
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False
  if flag(limit-build-mem)
    ghc-options: +RTS -M2000M -RTS

benchmark Prelude.Concurrent
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Prelude
  main-is: Concurrent.hs
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False

benchmark Prelude.Adaptive
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Prelude
  main-is: Adaptive.hs
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False

benchmark Prelude.Rate
  import: bench-options-threaded
  type: exitcode-stdio-1.0
  hs-source-dirs: Streamly/Benchmark/Prelude
  main-is: Rate.hs
  cpp-options: -DUSE_PRELUDE
  if !flag(use-prelude)
    buildable: False