Bodigrim / tasty-bench

Featherlight benchmark framework, drop-in replacement for criterion and gauge.
https://hackage.haskell.org/package/tasty-bench
MIT License
80 stars 11 forks source link

Even less dependencies? #35

Closed hasufell closed 1 year ago

hasufell commented 2 years ago

Tried using this in filepath, but on windows I get circular dependencies:

Not sure what exactly is causing it. I think something about optparse-applicative.

For now I disabled the benchmark suite on windows, but I fear this could cause issues down the line.

Bodigrim commented 2 years ago

Backjump limit reached (currently 4000, change with --max-backjumps or try to run with --reorder-goals).

Could you try this suggestion please? There is a build plan for tasty, but a rather exotic one with Win32-2.4 and ansi-terminal-0.8.0.3, so I assume that adding tasty-bench simply exceeds --max-backjumps limit.

hasufell commented 2 years ago

I'm currently ripping out all tasty code from the module and will try to integrate it into my bench suite directly.

It seems I can get away with measureUntil or measure as my runner functions. Since cabal files can't set flags on dependencies, I cannot force -f-tasty.

Bodigrim commented 2 years ago

I'm almost sure that increasing --max-backjumps should work, but otherwise you don't need to rip anything manually, just copy-paste Test.Tasty.Bench into your tree and import it.

hasufell commented 2 years ago

If someone else comes across this, I went with something like:

data Config = Config {
    format  :: Format
  , stdev   :: Double
  , timeout :: Integer
  }

data Format = Print
            | CSV
  deriving (Read, Show)

defaultConfig :: Config
defaultConfig = Config defaultFormat defaultStdev defaultTimeout

defaultFormat :: Format
defaultFormat = Print

defaultStdev :: Double
defaultStdev = 0.02

defaultTimeout :: Integer
defaultTimeout = 800000

parseConfig :: [String] -> Config
parseConfig [] = defaultConfig
parseConfig xs =
  let format'  = maybe defaultFormat  (read . fromJust . stripPrefix "--format=" ) $ find ("--format="  `isPrefixOf`) xs
      stdev'   = maybe defaultStdev   (read . fromJust . stripPrefix "--stdev="  ) $ find ("--stdev="   `isPrefixOf`) xs
      timeout' = maybe defaultTimeout (read . fromJust . stripPrefix "--timeout=") $ find ("--timeout=" `isPrefixOf`) xs
  in Config format' stdev' timeout'

main :: IO ()
main = do
  args <- getArgs
  let config = parseConfig args
  benchGroup config
    [ ("filepath (string)",
      [("splitExtension (posix)"      , nf PF.splitExtension posixPath),
      ....
      ]
   ]

benchGroup :: Config -> [(String, [(String, Benchmarkable)])] -> IO ()
benchGroup _ [] = pure ()
benchGroup format ((name, benchs):xs) = do
  putStrLn name
  bench format benchs
  benchGroup format xs

bench :: Config -> [(String, Benchmarkable)] -> IO ()
bench _ [] = pure ()
bench config@Config{..} (x:xs) = do
  let (name, benchmarkable) = x
  case format of
    CSV -> putStr (name ++ ",")
    Print -> putStr ("    " ++ name ++ ": ")
  est <- measureUntil CpuTime False (Timeout timeout "") (RelStDev stdev) benchmarkable
  case format of
    CSV -> putStr $ csvEstimate est
    Print -> putStr $ "\n      " ++ prettyEstimate est
  putStr "\n"
  bench config xs
Bodigrim commented 2 years ago

@hasufell sorry, I don't quite understand. Why do you need to craft https://gitlab.haskell.org/haskell/filepath/-/blob/master/bench/TastyBench.hs yourself? Would not it work if you replace its contents with the original Test.Tasty.Bench (without adding tasty to build-depends)? In any case please retain provenance, so that future generations of maintainers would have a clue where to look for patches / bug fixes.

If all boot libraries used tasty-bench, it would be easy to dump benchmarks to CSV and use it for GHC performance dashboard. Probably tasty itself can use less dependencies. I'd like to have an opportunity to take a look, but I'm busy for the next two weeks.

Bodigrim commented 2 years ago

The key bit in https://gitlab.haskell.org/haskell/filepath/-/jobs/1087047 is

[_15] rejecting: mintty:+win32-2-13-1 (conflict: Win32==2.4.0.0, mintty
+win32-2-13-1 => Win32>=2.13.1)
[_15] rejecting: mintty:-win32-2-13-1 (cyclic dependencies; conflict set:
ansi-terminal, ansi-wl-pprint, filepath, mintty, optparse-applicative, tasty,
tasty-bench)

It should be resolved by https://github.com/RyanGlScott/mintty/issues/5.

hasufell commented 2 years ago

@Bodigrim I'm not sure what you're asking here. I want zero added dependencies and I don't want to tweak cabal resolver to be able to build the benchmarks. When I inline a package, I want to inline the minimal amount of code, so I remove all ifdefs and functions I don't need, in order to keep it light and reduce maintenance.

Bodigrim commented 1 year ago

Closing, this is tracked further upstream in https://github.com/UnkindPartition/ansi-terminal/issues/151.