mariadb-haskell-0.1.0.0: validation/hs/Validation/Stage4Bench.hs
-- | Complete request-boundary costs: reset/restore/prepare versus opening,
-- initializing, preparing and closing a new connection. Both paths perform the
-- same application work and deliberately leave state for the next boundary.
module Validation.Stage4Bench (run) where
import Control.Exception (bracket, evaluate)
import Control.Monad
import Data.List (intercalate, isSuffixOf, isInfixOf)
import Database.MySQL.Base
import GHC.Clock
import GHC.Stats
import System.Mem
import qualified System.IO.Streams as S
import Validation.Common
run :: String -> Int -> IO ()
run ident iterations
| iterations <= 0 = fail "positive reuse benchmark count required"
| ident == "session.snapshot" = withConn $ \conn -> do
let loop 0 !total = pure (toInteger total)
loop remaining !total = do
state <- getSessionState conn
equal "autocommit observed" (Just True) (sessionAutocommit state)
equal "no transaction observed" (Just False) (sessionInTransaction state)
loop (remaining - 1) (total + (1 :: Int))
measure ident iterations (loop iterations 0)
| otherwise = do
ci <- config
path <- socketPath
name <- env "MB_TLS_NAME" "localhost"
let open | ".tcp." `isInfixOf` ident = connect ci
| ".tls." `isInfixOf` ident = tlsConnect ci name
| ".socket." `isInfixOf` ident = connectUnixSocket path ci
| otherwise = fail "unknown reuse transport"
initialize conn = exec conn "SET time_zone='+00:00',sql_mode='STRICT_TRANS_TABLES',autocommit=1"
request conn = do
-- Preparation is intentionally inside timing. RESET and a new
-- connection both remove the preceding request's statement.
statement <- prepareStatement conn "SELECT 7,@@time_zone,@@sql_mode,@mb_stage4_bench IS NULL"
(_, stream) <- queryPrepared statement []
result <- S.toList stream
case result of
[[n,MySQLText zone,MySQLText modes,clean]] -> do
equal "request result" 7 (number n)
equal "application timezone restored" "+00:00" zone
equal "application SQL mode restored" "STRICT_TRANS_TABLES" modes
equal "no prior request's variable" 1 (number clean)
_ -> fail "reuse benchmark request shape mismatch"
exec conn "SET @mb_stage4_bench=7,time_zone='+01:00'"
pure 1
if ".reset" `isSuffixOf` ident
then withConnect open $ \conn -> measure ident iterations $ sum <$> replicateM iterations
(resetConnectionWith conn initialize >> request conn)
else if ".reconnect" `isSuffixOf` ident
then measure ident iterations $ sum <$> replicateM iterations
(bracket open close (\conn -> initialize conn >> request conn))
else fail "unknown reuse benchmark mode"
-- Same warmups/GC/RTS convention as the native recorder. Units are complete
-- requests, or snapshot calls for session.snapshot; the checksum is one/unit.
measure :: String -> Int -> IO Integer -> IO ()
measure ident count operation = do
void operation
void operation
performGC
before <- getRTSStats
start <- getMonotonicTimeNSec
checksum <- operation >>= evaluate
end <- getMonotonicTimeNSec
performGC
after <- getRTSStats
equal "reuse benchmark checksum" (toInteger count) checksum
putStrLn (intercalate "\t" ["STAGE4",ident,show count,show (end-start),
show (allocated_bytes after-allocated_bytes before),show (cpu_ns after-cpu_ns before),
show (gc_cpu_ns after-gc_cpu_ns before),show checksum])