content: #!/usr/bin/env runghc
  {-# LANGUAGE NamedFieldPuns #-}
  
  -- | This script runs all Harlan benchmarks.  It is based on a Haskell
  -- benchmarking framework called HSBencher.  Its main advantage is
  -- that it supports uploading of benchmark timings to a Google Fusion
  -- Table.
  
  -- Requires hsbencher >= 0.2
  
  import Control.Monad
  import Data.Maybe
  import qualified Data.ByteString.Char8 as B
  import System.Directory
  import System.FilePath
  import System.Exit
  import System.Environment (getArgs)
  import System.Process
  import GHC.Conc (getNumProcessors)
  import System.IO.Unsafe (unsafePerformIO)
  import Debug.Trace
  
  import HSBencher (defaultMainModifyConfig)
  import HSBencher.Types
  import HSBencher.Methods (makeMethod)
  import HSBencher.Logging (log)
  import HSBencher.MeasureProcess
  import HSBencher.Utils (runLogged, defaultTimeout)
  
  import HSBencher.Backend.Fusion  (defaultFusionPlugin)
  import HSBencher.Backend.Dribble (defaultDribblePlugin)
  
  import Prelude hiding (log)
  --------------------------------------------------------------------------------
  
  main :: IO ()
  main = defaultMainModifyConfig myconf
  
  all_benchmarks :: [Benchmark DefaultParamMeaning]
  all_benchmarks =
    [ mkBenchmark "test/bench-add-vector.kfc" [show sz] defaultCfgSpc  | sz <- [1,3 .. 90] ] ++ 
    [ mkBenchmark "test/bench-nbody.kfc"      [show sz] defaultCfgSpc  | sz <- [1 .. 66] ] ++ 
    [ mkBenchmark "test/bench-mandelbrot.kfc"      [show sz] defaultCfgSpc  | sz <- [1 .. 50] ] ++
    [ mkBenchmark "test/bench-bfs-color.kfc" [show sz, "16"] defaultCfgSpc 
    | sz <- [100, 1000, 10^4, 10^5, 10^5] ] ++
    [ mkBenchmark "test/bench-raytrace.kfc" [show flag, "100"] defaultCfgSpc | flag <- [0,1] ]
  
  -- Default configuration space over which to vary settings:
  defaultCfgSpc = Or [gpu]
   where
     cpu = And [ Set (Variant "CPU") (RuntimeEnv "HARLAN_DEVICE" "cpu") ]
     gpu = And [ Set (Variant "GPU") (RuntimeEnv "HARLAN_DEVICE" "gpu")
               , Set NoMeaning (RuntimeEnv "HARLAN_MIN_REGION_SIZE" "134217728") ]
  
  -- | Put it all together as a full HSBencher configuration.
  myconf :: Config -> Config
  myconf conf =
    conf
     { benchlist = all_benchmarks
     , buildMethods = [ harlanMethod ]
     , plugIns   = [ SomePlugin defaultFusionPlugin,
                     SomePlugin defaultDribblePlugin ]
     }
  
  -- | Teach HSBencher how to build Harlan files From HSBencher's
  -- perspective, it just runs pre-built binaries compiled with harlanc.
  harlanMethod :: BuildMethod
  harlanMethod = BuildMethod
        { methodName = "harlanMethod"
        , canBuild = WithExtension ".kfc"
        , concurrentBuild = False
        , setThreads      = Nothing
        , clean = \_ _ _ -> return ()
        , compile = \ _ _ _ targetpath -> do
           log$ tag++" Compiling harlan file: "++targetpath
           runSuccessful " [harlanc] " ("./harlanc "++targetpath)
           return (StandAloneBinary ("./" ++ (takeBaseName targetpath)))
        }
   where
      tag = " [run-benchmarks] "
  
  
  -- | A simple wrapper for a command that is expected to succeed (and whose output we
  -- don't care about).  Throws an exception if the command fails.
  runSuccessful :: String -> String -> BenchM [B.ByteString]
  runSuccessful tag cmd = do
    (res,lines) <- runLogged tag cmd
    case res of
      ExitError code  -> error$ "expected this command to succeed! But it exited with code "++show code++ ":\n  "++ cmd
      RunTimeOut {}   -> error "Methods.hs/runSuccessful - internal error!"
      RunCompleted {} -> return lines
  