packages feed

phino-0.0.81: benchmark/Main.hs

-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
-- SPDX-License-Identifier: MIT

module Main where

import AST (Expression (ExRoot))
import Control.Exception (evaluate)
import Control.Monad (replicateM, replicateM_)
import Data.Time.Clock
import Deps (dontSaveStep)
import Encoding (Encoding (UNICODE))
import Functions (buildTerm)
import Lining (LineFormat (MULTILINE, SINGLELINE))
import Margin (defaultMargin)
import Must (Must (MtDisabled))
import Parser (parseProgramThrows)
import Printer (printProgram')
import Rewriter (RewriteContext (RewriteContext), rewrite)
import Sugar (SugarType (SALTY, SWEET))
import Text.Printf (printf)
import XMIR (parseXMIRThrows, xmirToPhi)
import Yaml (normalizationRules)

warmups :: Int
warmups = 3

iterations :: Int
iterations = 10

targetBatchMs :: Double
targetBatchMs = 20.0

rewriteCtx :: RewriteContext
rewriteCtx =
  RewriteContext
    ExRoot
    100
    100
    False
    buildTerm
    MtDisabled
    Nothing
    dontSaveStep

timeAction :: IO a -> IO Double
timeAction action = do
  start <- getCurrentTime
  _ <- evaluate =<< action
  end <- getCurrentTime
  pure (realToFrac (diffUTCTime end start) * 1e6)

timeBatch :: Int -> IO a -> IO Double
timeBatch batch action = do
  start <- getCurrentTime
  replicateM_ batch (evaluate =<< action)
  end <- getCurrentTime
  pure (realToFrac (diffUTCTime end start) * 1e6 / fromIntegral batch)

calibrate :: IO a -> IO Int
calibrate action = do
  t <- timeAction action
  pure (max 1 (round (targetBatchMs * 1000.0 / t)))

stdDev :: [Double] -> Double -> Double
stdDev xs avg = sqrt (sum (map (\x -> (x - avg) ^ (2 :: Int)) xs) / fromIntegral (length xs))

runBench :: String -> IO a -> IO ()
runBench name action = do
  replicateM_ warmups action
  batch <- calibrate action
  times <- replicateM iterations (timeBatch batch action)
  let total = sum times * fromIntegral batch
      avg = sum times / fromIntegral iterations
      mn = minimum times
      mx = maximum times
      sd = stdDev times avg
  putStrLn $ "=== " ++ name ++ " ==="
  putStrLn $ printf "  warmup:     %d iterations" warmups
  putStrLn $ printf "  batches:    %d x %d" iterations batch
  putStrLn $ printf "  total:      %.3f μs" total
  putStrLn $ printf "  avg:        %.3f μs" avg
  putStrLn $ printf "  min:        %.3f μs" mn
  putStrLn $ printf "  max:        %.3f μs" mx
  putStrLn $ printf "  std dev:    %.3f μs" sd

main :: IO ()
main = do
  src <- readFile "benchmark/tmp/native.phi"
  xsrc <- readFile "benchmark/tmp/Native.xmir"
  prog <- parseProgramThrows src
  runBench "parse/phi" (parseProgramThrows src)
  runBench "parse/xmir" (parseXMIRThrows xsrc >>= xmirToPhi)
  runBench "rewrite/normalize" (rewrite prog normalizationRules rewriteCtx)
  runBench
    "print/sweet/multiline"
    (evaluate (length (printProgram' prog (SWEET, UNICODE, MULTILINE, defaultMargin))))
  runBench
    "print/sweet/flat"
    (evaluate (length (printProgram' prog (SWEET, UNICODE, SINGLELINE, defaultMargin))))
  runBench
    "print/salty/multiline"
    (evaluate (length (printProgram' prog (SALTY, UNICODE, MULTILINE, defaultMargin))))