Skip to content

Commit 2823eb9

Browse files
committed
Only read stdout when running with --more-verbose
When not running with `-V` or `--more-verbose`, we now pipe the stdout of the executable under test to /dev/null. This prevents quickbench from running out of memory in case the output is huge (GBs). MINOR REMARK With my version of GHC (9.6.6), all exceptions unfortunately get annoted `withBinaryFile`, see https://gitlab.haskell.org/ghc/ghc/-/issues/20886. For example, when running `quickbench -w doesnotexist`, the error message is: ``` /dev/null: withBinaryFile: does not exist (No such file or directory) ``` When running `quickbench -w doesnotexist --more-verbose`, avoiding the call to `withBinaryFile`, the error message is the much clearer: ``` doesnotexist: readCreateProcess: posix_spawnp: does not exist (No such file or directory) ``` This is not ideal, but I believe using the latest version of GHC will fix it.
1 parent 1857a8e commit 2823eb9

File tree

1 file changed

+24
-8
lines changed

1 file changed

+24
-8
lines changed

src/QuickBench.hs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ import Data.Maybe
1818
import Data.Time.Clock
1919
import Data.Time.Format
2020
import Data.Time.LocalTime
21+
import GHC.IO.Exception (IOErrorType(..))
2122
import Safe
2223
import System.Console.Docopt
2324
import System.Directory
2425
import System.Environment
2526
import System.Exit
2627
import System.IO
28+
import System.IO.Error (mkIOError)
2729
import System.Process
2830
import Text.Megaparsec (ParsecT, Stream (Token), between, many, noneOf, runParser, satisfy, sepBy, takeWhile1P, (<|>))
2931
import Text.Megaparsec.Char (char)
@@ -219,17 +221,31 @@ time :: Opts -> String -> [String] -> IO Float
219221
time opts exe args = do
220222
dbg opts $ printf "running: %s\n" (show (exe,args))
221223
t1 <- getCurrentTime
222-
(c, o, e) <- readProcessWithExitCode' exe args ""
224+
maybeOutput <- if (moreVerbose opts)
225+
then Just <$> readCreateProcess (proc exe args) ""
226+
else const Nothing <$> callProcessIgnoreOutput exe args
223227
t2 <- getCurrentTime
224-
when (not $ null o) $ outvv opts $ (if verbose opts then "\n" else "") ++ o
225-
unless (c == ExitSuccess) $ out opts $ " (error: " ++ strip e ++ ") "
228+
case maybeOutput of
229+
Just o -> when (not $ null o) $ outvv opts $ (if verbose opts then "\n" else "") ++ o
230+
Nothing -> return ()
226231
return $ realToFrac $ diffUTCTime t2 t1
227232

228-
-- ^ This variant also returns a failure when the executable is missing.
229-
readProcessWithExitCode' :: FilePath -> [String] -> String -> IO (ExitCode, String, String)
230-
readProcessWithExitCode' exe args inp =
231-
readProcessWithExitCode exe args inp
232-
`catch` \(e :: IOException) -> return (ExitFailure 1, "", show e)
233+
callProcessIgnoreOutput :: FilePath -> [String] -> IO ()
234+
callProcessIgnoreOutput cmd args =
235+
withBinaryFile "/dev/null" WriteMode $ \devNull ->
236+
withCreateProcess (proc cmd args){std_out = UseHandle devNull} $ \_ _ _ ph -> do
237+
exit_code <- waitForProcess ph
238+
case exit_code of
239+
ExitSuccess -> return ()
240+
ExitFailure r -> processFailedException "callProcessIgnoreOutput" cmd args r
241+
242+
-- Copy/paste from "process" System.Process.
243+
processFailedException :: String -> String -> [String] -> Int -> IO a
244+
processFailedException fun cmd args exit_code =
245+
ioError (mkIOError OtherError (fun ++ ": " ++ cmd ++
246+
concatMap ((' ':) . show) args ++
247+
" (exit " ++ show exit_code ++ ")")
248+
Nothing Nothing)
233249

234250
printSummary :: Opts -> [String] -> [String] -> Int -> [[[Float]]] -> IO ()
235251
printSummary opts cmds exes cyc results = do

0 commit comments

Comments
 (0)