import CmdLine
import Text.Printf
-import Text.Html hiding ((!))
+import Text.Html hiding (cols, rows, (!))
import qualified Text.Html as Html ((!))
import qualified Data.Map as Map
import Data.Map (Map)
-import System.Console.GetOpt
import System.Exit ( exitWith, ExitCode(..) )
-import Numeric ( showFloat, showFFloat, showSigned )
+import Control.Monad
import Data.Maybe ( isNothing )
import Data.Char
import System.IO
die :: String -> IO a
die s = hPutStr stderr s >> exitWith (ExitFailure 1)
-usageHeader = "usage: nofib-analyse [OPTION...] <logfile1> <logfile2> ..."
-
+main :: IO ()
main = do
- if not (null cmdline_errors) || OptHelp `elem` flags
- then die (concat cmdline_errors ++ usageInfo usageHeader argInfo)
- else do
+ when (not (null cmdline_errors) || OptHelp `elem` flags) $
+ die (concat cmdline_errors ++ usage)
let { html = OptHTMLOutput `elem` flags;
latex = OptLaTeXOutput `elem` flags;
ascii = OptASCIIOutput `elem` flags
}
- if ascii && html
- then die "Can't produce both ASCII and HTML"
- else do
-
- if devs && nodevs
- then die "Can't both display and hide deviations"
- else do
+ when (ascii && html) $ die "Can't produce both ASCII and HTML"
+ when (devs && nodevs) $ die "Can't both display and hide deviations"
results <- parse_logs other_args
let column_headings = map (reverse . takeWhile (/= '/') . reverse) other_args
-- sanity check
- sequence_ [ checkTimes prog res | table <- results,
- (prog,res) <- Map.toList table ]
+ sequence_ [ checkTimes prog res | result_table <- results,
+ (prog,res) <- Map.toList result_table ]
case () of
_ | html ->
(a -> Bool) -- Result within reasonable limits?
-- The various per-program aspects of execution that we can generate results for.
+size_spec, alloc_spec, runtime_spec, muttime_spec, gctime_spec,
+ gcwork_spec, instrs_spec, mreads_spec, mwrite_spec, cmiss_spec
+ :: PerProgTableSpec
size_spec = SpecP "Binary Sizes" "Size" "binary-sizes" binary_size compile_status always_ok
alloc_spec = SpecP "Allocations" "Allocs" "allocations" allocs run_status always_ok
runtime_spec = SpecP "Run Time" "Runtime" "run-times" (mean run_time) run_status time_ok
mwrite_spec = SpecP "Memory Writes" "Writes" "mem-writes" mem_writes run_status always_ok
cmiss_spec = SpecP "Cache Misses" "Misses" "cache-misses" cache_misses run_status always_ok
+all_specs :: [PerProgTableSpec]
all_specs = [
size_spec,
alloc_spec,
-- These are the per-prog tables we want to generate
+per_prog_result_tab :: [PerProgTableSpec]
per_prog_result_tab =
[ size_spec, alloc_spec, runtime_spec, muttime_spec, gctime_spec,
gcwork_spec, instrs_spec, mreads_spec, mwrite_spec, cmiss_spec ]
-- A single summary table, giving comparison figures for a number of
-- aspects, each in its own column. Only works when comparing two runs.
+normal_summary_specs :: [PerProgTableSpec]
normal_summary_specs =
[ size_spec, alloc_spec, runtime_spec ]
+cachegrind_summary_specs :: [PerProgTableSpec]
cachegrind_summary_specs =
[ size_spec, alloc_spec, instrs_spec, mreads_spec, mwrite_spec ]
| isNothing (instrs (head (Map.elems (head rs)))) = normal_summary_specs
| otherwise = cachegrind_summary_specs
+per_module_result_tab :: [PerModuleTableSpec]
per_module_result_tab =
[ SpecM "Module Sizes" "mod-sizes" module_size always_ok
, SpecM "Compile Times" "compile-time" compile_time time_ok
-----------------------------------------------------------------------------
-- HTML page generation
---htmlPage :: Results -> [String] -> Html
+htmlPage :: [ResultTable] -> [String] -> Html
htmlPage results args
= header << thetitle << reportTitle
+++ hr
base_stat = get_stat base_r
just_result Nothing s = RunFailed s
- just_result (Just a) s = toBox a
+ just_result (Just a) _ = toBox a
- percentage Nothing s base = RunFailed s
- percentage (Just a) s base = Percentage
+ percentage Nothing s _ = RunFailed s
+ percentage (Just a) _ base = Percentage
(convert_to_percentage base a)
-----------------------------------------------------------------------------
-- Calculating geometric means and standard deviations
-- We assume an Int is a size, and print it in kilobytes.
instance Result Int where
- convert_to_percentage 0 size = 100
- convert_to_percentage base size = (fromIntegral size / fromIntegral base) * 100
+ convert_to_percentage 0 _ = 100
+ convert_to_percentage base size
+ = (fromIntegral size / fromIntegral base) * 100
- toBox = BoxInt
+ toBox = BoxInt
instance Result Integer where
- convert_to_percentage 0 size = 100
- convert_to_percentage base size = (fromInteger size / fromInteger base) * 100
- toBox = BoxInteger
-
+ convert_to_percentage 0 _ = 100
+ convert_to_percentage base size
+ = (fromInteger size / fromInteger base) * 100
+ toBox = BoxInteger
instance Result Float where
- convert_to_percentage 0.0 size = 100.0
- convert_to_percentage base size = size / base * 100
+ convert_to_percentage 0.0 _ = 100.0
+ convert_to_percentage base size = size / base * 100
- toBox = BoxFloat
+ toBox = BoxFloat
-- -----------------------------------------------------------------------------
-- BoxValues
showBox :: BoxValue -> String
showBox (RunFailed stat) = show_stat stat
-showBox (Percentage f) = show_pcntage f
+showBox (Percentage f) = printf "%+.1f%%" (f-100)
showBox (BoxFloat f) = printf "%.2f" f
showBox (BoxInt n) = show (n `div` 1024) ++ "k"
showBox (BoxInteger n) = show (n `div` 1024) ++ "k"
showBox (BoxString s) = s
-instance Show BoxValue where { show = showBox }
-
-show_pcntage n = show_float_signed (n-100) ++ "%"
-
-show_float_signed n
- | n >= 0 = printf "+%.1f" n
- | otherwise = printf "%.1f" n
+instance Show BoxValue where
+ show = showBox
+show_stat :: Status -> String
show_stat Success = "(no result)"
show_stat WrongStdout = "(stdout)"
show_stat WrongStderr = "(stderr)"