From f216dd0134b3c581dde683f16a75885457e4c60b Mon Sep 17 00:00:00 2001 From: simonmar Date: Fri, 2 Apr 2004 14:28:57 +0000 Subject: [PATCH] [project @ 2004-04-02 14:28:57 by simonmar] Some updates I've had sitting in my tree for a while: - when there are two logs only, print a summary table at the beginning of the output with columns for allocs, runtime, memory reads/writes, instrs. - handle multiple runs of each program, and average the results. (changes to nofib build system to follow). --- glafp-utils/nofib-analyse/CmdLine.hs | 3 + glafp-utils/nofib-analyse/Main.hs | 285 ++++++++++++++++++++++++++-------- glafp-utils/nofib-analyse/Slurp.hs | 132 ++++++++-------- 3 files changed, 286 insertions(+), 134 deletions(-) diff --git a/glafp-utils/nofib-analyse/CmdLine.hs b/glafp-utils/nofib-analyse/CmdLine.hs index c16d786..b265d76 100644 --- a/glafp-utils/nofib-analyse/CmdLine.hs +++ b/glafp-utils/nofib-analyse/CmdLine.hs @@ -32,6 +32,7 @@ reportTitle = case [ t | OptTitle t <- flags ] of data CLIFlags = OptASCIIOutput + | OptLaTeXOutput | OptHTMLOutput | OptIgnoreSmallTimes Float | OptDeviations @@ -52,6 +53,8 @@ argInfo = "Ignore runtimes smaller than " , Option ['d'] ["deviations"] (NoArg OptDeviations) "Display deviations (default)" + , Option ['l'] ["latex"] (NoArg OptLaTeXOutput) + "Produce LaTeX output" , Option ['n'] ["nodeviations"] (NoArg OptNoDeviations) "Hide deviations" , Option ['t'] ["title"] (ReqArg OptTitle "title") diff --git a/glafp-utils/nofib-analyse/Main.hs b/glafp-utils/nofib-analyse/Main.hs index c073eab..75de9e9 100644 --- a/glafp-utils/nofib-analyse/Main.hs +++ b/glafp-utils/nofib-analyse/Main.hs @@ -1,5 +1,5 @@ ----------------------------------------------------------------------------- --- $Id: Main.hs,v 1.8 2002/09/18 12:36:39 simonmar Exp $ +-- $Id: Main.hs,v 1.9 2004/04/02 14:28:57 simonmar Exp $ -- (c) Simon Marlow 1997-1999 ----------------------------------------------------------------------------- @@ -17,11 +17,12 @@ import GlaExts import FiniteMap import GetOpt +import Maybe ( isNothing ) import Char import IO -import Array import System import List +import Data.List (foldl') ( putStr (renderHtml (htmlPage results column_headings)) + _ | latex -> putStr (latexOutput results column_headings) + _ | otherwise -> putStr (asciiPage results column_headings) parse_logs :: [String] -> IO [ResultTable] @@ -76,6 +79,7 @@ data PerProgTableSpec = forall a . Result a => SpecP String -- Name of the table + String -- Short name (for column heading) String -- HTML tag for the table (Results -> Maybe a) -- How to get the result (Results -> Status) -- How to get the status of this result @@ -89,18 +93,45 @@ data PerModuleTableSpec = (Results -> FiniteMap String a) -- get the module map (a -> Bool) -- Result within reasonable limits? +-- The various per-program aspects of execution that we can generate results for. +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 +muttime_spec = SpecP "Mutator Time" "MutTime" "mutator-time" (mean mut_time) run_status time_ok +gctime_spec = SpecP "GC Time" "GCTime" "gc-time" (mean gc_time) run_status time_ok +gcwork_spec = SpecP "GC Work" "GCWork" "gc-work" gc_work run_status always_ok +instrs_spec = SpecP "Instructions" "Instrs" "instrs" instrs run_status always_ok +mreads_spec = SpecP "Memory Reads" "Reads" "mem-reads" mem_reads run_status always_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 + +mean :: (Results -> [Float]) -> Results -> Maybe Float +mean f results = go (f results) + where go [] = Nothing + go fs = Just (foldl' (+) 0 fs / fromIntegral (length fs)) + +-- These are the per-prog tables we want to generate per_prog_result_tab = - [ SpecP "Binary Sizes" "binary-sizes" binary_size compile_status always_ok - , SpecP "Allocations" "allocations" allocs run_status always_ok - , SpecP "Run Time" "run-times" run_time run_status time_ok - , SpecP "Mutator Time" "mutator-time" mut_time run_status time_ok - , SpecP "GC Time" "gc-time" gc_time run_status time_ok - , SpecP "GC Work" "gc-work" gc_work run_status always_ok - , SpecP "Instructions" "instrs" instrs run_status always_ok - , SpecP "Memory Reads" "mem-reads" mem_reads run_status always_ok - , SpecP "Memory Writes" "mem-writes" mem_writes run_status always_ok - , SpecP "Cache Misses" "cache-misses" cache_misses run_status always_ok - ] + [ 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 = + [ size_spec, alloc_spec, runtime_spec ] + +cachegrind_summary_specs = + [ size_spec, alloc_spec, instrs_spec, mreads_spec, mwrite_spec ] + +latex_summary_specs = [ size_spec, instrs_spec, mreads_spec, mwrite_spec ] + +-- Pick an appropriate summary table: if we're cachegrinding, then +-- we're probably not interested in the runtime, but we are interested +-- in instructions, mem reads and mem writes (and vice-versa). +pickSummary :: [ResultTable] -> [PerProgTableSpec] +pickSummary rs + | isNothing (instrs (head (eltsFM (head rs)))) = normal_summary_specs + | otherwise = cachegrind_summary_specs per_module_result_tab = [ SpecM "Module Sizes" "mod-sizes" module_size always_ok @@ -128,14 +159,14 @@ htmlPage results args gen_menu = unordList (map (prog_menu_item) per_prog_result_tab ++ map (module_menu_item) per_module_result_tab) -prog_menu_item (SpecP name anc _ _ _) = anchor Int -> (String, [BoxValue a]) -> HtmlTable +tableRow :: Int -> (String, [BoxValue]) -> HtmlTable tableRow row_no (prog, results) = td besides (map (\s -> td besides (map (\s -> td 10 = chr (i-10 + ord 'a') | otherwise = chr (i + ord '0') ----------------------------------------------------------------------------- +-- LaTeX table generation (just the summary for now) + +latexOutput results args = + (if (length results == 2) + then ascii_summary_table True results latex_summary_specs . str "\n\n" + else id) "" + + +----------------------------------------------------------------------------- -- ASCII page generation asciiPage results args = ( str reportTitle . str "\n\n" + -- only show the summary table if we're comparing two runs + . (if (length results == 2) + then ascii_summary_table False results (pickSummary results) . str "\n\n" + else id) . interleave "\n\n" (map (asciiGenProgTable results args) per_prog_result_tab) . str "\n" . interleave "\n\n" (map (asciiGenModTable results args) per_module_result_tab) ) "\n" -asciiGenProgTable results args (SpecP title anc get_result get_status result_ok) +asciiGenProgTable results args (SpecP title _ anc get_result get_status result_ok) = str title . str "\n" . ascii_show_results results args get_result get_status result_ok @@ -298,11 +342,11 @@ asciiGenModTable results args (SpecM title anc get_result result_ok) . str "\n" . ascii_show_multi_results results args get_result result_ok -ascii_header ss +ascii_header width ss = str "\n-------------------------------------------------------------------------------\n" . str (rjustify 15 "Program") . str (space 5) - . foldr (.) id (map (str . rjustify fIELD_WIDTH) ss) + . foldr (.) id (map (str . rjustify width) ss) . str "\n-------------------------------------------------------------------------------\n" ascii_show_results @@ -315,7 +359,7 @@ ascii_show_results -> ShowS ascii_show_results (r:rs) ss f stat result_ok - = ascii_header ss + = ascii_header fIELD_WIDTH ss . interleave "\n" (map show_per_prog_results results_per_prog) . if nodevs then id else str "\n" @@ -331,6 +375,60 @@ ascii_show_results (r:rs) ss f stat result_ok results_per_run = transpose (map snd results_per_prog) (lows,gms,highs) = unzip3 (map calc_gmsd results_per_run) +-- A summary table, useful only when we are comparing two runs. This table +-- shows a number of different result categories, one per column. +ascii_summary_table + :: Bool -- generate a LaTeX table? + -> [ResultTable] + -> [PerProgTableSpec] + -> ShowS +ascii_summary_table latex (r1:r2:_) specs + | latex = makeLatexTable (rows ++ TableLine : av_rows) + | otherwise = + makeTable (table_layout (length specs) width) + (TableLine : TableRow header : TableLine : rows ++ TableLine : av_rows) + where + header = BoxString "Program" : map BoxString headings + + (headings, columns, av_cols) = unzip3 (map calc_col specs) + av_heads = [BoxString "Min", BoxString "Max", BoxString "Geometric Mean"] + baseline = fmToList r1 + progs = map BoxString (keysFM r1) + rows' = map TableRow (zipWith (:) progs (transpose columns)) + + rows | latex = mungeForLaTeX rows' + | otherwise = rows' + + av_rows = map TableRow (zipWith (:) av_heads (transpose av_cols)) + width = 10 + + calc_col (SpecP _ heading _ getr gets ok) + = (heading, column, [min,max,mean]) -- throw away the baseline result + where (_, boxes) = unzip (map calc_one_result baseline) + calc_one_result = calc_result [r2] getr gets ok + column = map (\(_:b:_) -> b) boxes + (_,mean,_) = calc_gmsd column + (min,max) = calc_minmax column + +mungeForLaTeX :: [TableRow] -> [TableRow] +mungeForLaTeX = filter keep_it + where keep_it (TableRow (BoxString s: _)) = ok s + keep_it TableLine = True + keep_it _ = False + + ok s = s `elem` progs_to_keep + +progs_to_keep = [ + "anna", "cacheprof", "circsim", "compress", + "fem", "fulsom", "fibheaps", "hidden", + "infer", "typecheck", "scs", "simple" + ] + +table_layout n width = + (str . rjustify 15) : + (\s -> str (space 5) . str (rjustify width s)) : + replicate (n-1) (str . rjustify width) + ascii_show_multi_results :: Result a => [ResultTable] @@ -340,7 +438,7 @@ ascii_show_multi_results -> ShowS ascii_show_multi_results (r:rs) ss f result_ok - = ascii_header ss + = ascii_header fIELD_WIDTH ss . interleave "\n" (map show_results_for_prog results_per_prog_mod_run) . str "\n" . if nodevs then id @@ -379,40 +477,17 @@ ascii_show_multi_results (r:rs) ss f result_ok (_,xs) <- mods] (lows,gms,highs) = unzip3 (map calc_gmsd results_per_run) -show_per_prog_results :: Result a => (String, [BoxValue a]) -> ShowS -show_per_prog_results (prog,results) - = str (rjustify 15 prog) - . str (space 5) - . foldr (.) id (map (str . rjustify fIELD_WIDTH . show_box) results) ------------------------------------------------------------------------------ --- Show the Results - -class Num a => Result a where - result_to_string :: a -> String - convert_to_percentage :: a -> a -> Float +show_per_prog_results :: (String, [BoxValue]) -> ShowS +show_per_prog_results = show_per_prog_results_width fIELD_WIDTH --- 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 - - result_to_string n = show (n `div` 1024) ++ "k" - -instance Result Integer where - convert_to_percentage 0 size = 100 - convert_to_percentage base size = (fromInteger size / fromInteger base) * 100 - - result_to_string n = show (n `quot` 1024) ++ "k" - -instance Result Float where - convert_to_percentage 0.0 size = 100.0 - convert_to_percentage base size = size / base * 100 - - result_to_string = showFloat' Nothing (Just 2) +show_per_prog_results_width width (prog,results) + = str (rjustify 15 prog) + . str (space 5) + . foldr (.) id (map (str . rjustify width . showBox) results) -data BoxValue a = RunFailed Status | Percentage Float | Result a +-- --------------------------------------------------------------------------- +-- Generic stuff for results generation -- calc_result is a nice exercise in higher-order programming... calc_result @@ -422,7 +497,7 @@ calc_result -> (b -> Status) -- get a status from the b -> (a -> Bool) -- is this result ok? -> (String,b) -- the baseline result - -> (String,[BoxValue a]) + -> (String,[BoxValue]) calc_result rts get_maybe_a get_stat result_ok (prog,base_r) = (prog, (just_result baseline base_stat : @@ -445,15 +520,11 @@ calc_result rts get_maybe_a get_stat result_ok (prog,base_r) = base_stat = get_stat base_r just_result Nothing s = RunFailed s - just_result (Just a) s = Result a + just_result (Just a) s = toBox a percentage Nothing s base = RunFailed s percentage (Just a) s base = Percentage (convert_to_percentage base a) -show_box (RunFailed s) = show_stat s -show_box (Percentage p) = show_pcntage p -show_box (Result a) = result_to_string a - ----------------------------------------------------------------------------- -- Calculating geometric means and standard deviations @@ -486,7 +557,7 @@ We therefore return a (low, mean, high) triple. -} -calc_gmsd :: [BoxValue a] -> (BoxValue Float, BoxValue Float, BoxValue Float) +calc_gmsd :: [BoxValue] -> (BoxValue, BoxValue, BoxValue) calc_gmsd xs | null percentages = (RunFailed NotDone, RunFailed NotDone, RunFailed NotDone) | otherwise = let sqr x = x * x @@ -506,8 +577,63 @@ calc_gmsd xs -- can't do log(0.0), so exclude zeros -- small values have inordinate effects so cap at -95%. +calc_minmax :: [BoxValue] -> (BoxValue, BoxValue) +calc_minmax xs + | null percentages = (RunFailed NotDone, RunFailed NotDone) + | otherwise = (Percentage (minimum percentages), + Percentage (maximum percentages)) + where + percentages = [ if f < 5 then 5 else f | Percentage f <- xs ] + + ----------------------------------------------------------------------------- --- Generic stuff for results generation +-- Show the Results + +class Num a => Result a where + toBox :: a -> BoxValue + convert_to_percentage :: a -> a -> Float + +-- 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 + + toBox = BoxInt + +instance Result Integer where + convert_to_percentage 0 size = 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 + + toBox = BoxFloat + +-- ----------------------------------------------------------------------------- +-- BoxValues + +-- The contents of a box in a table +data BoxValue + = RunFailed Status + | Percentage Float + | BoxFloat Float + | BoxInt Int + | BoxInteger Integer + | BoxString String + +showBox :: BoxValue -> String +showBox (RunFailed stat) = show_stat stat +showBox (Percentage f) = show_pcntage f +showBox (BoxFloat f) = showFloat' Nothing (Just 2) 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) ++ "%" @@ -521,6 +647,37 @@ show_stat OutOfHeap = "(heap)" show_stat OutOfStack = "(stack)" show_stat NotDone = "-----" +-- ----------------------------------------------------------------------------- +-- Table layout + +data TableRow + = TableRow [BoxValue] + | TableLine + +type Layout = [String -> ShowS] + +makeTable :: Layout -> [TableRow] -> ShowS +makeTable p = interleave "\n" . map do_row + where do_row (TableRow boxes) = applyLayout p boxes + do_row TableLine = str (take 80 (repeat '-')) + +makeLatexTable :: [TableRow] -> ShowS +makeLatexTable = foldr (.) id . map do_row + where do_row (TableRow boxes) + = applyLayout latexTableLayout boxes . str "\\\\\n" + do_row TableLine + = str "\\hline\n" + +latexTableLayout :: Layout +latexTableLayout = str : repeat (str . (" & "++)) + +applyLayout :: Layout -> [BoxValue] -> ShowS +applyLayout layout values = + foldr (.) id [ f (show val) | (val,f) <- zip values layout ] + +-- ----------------------------------------------------------------------------- +-- General Utils + str = showString interleave s = foldr1 (\a b -> a . str s . b) diff --git a/glafp-utils/nofib-analyse/Slurp.hs b/glafp-utils/nofib-analyse/Slurp.hs index 5fe15dd..ed21716 100644 --- a/glafp-utils/nofib-analyse/Slurp.hs +++ b/glafp-utils/nofib-analyse/Slurp.hs @@ -1,5 +1,5 @@ ----------------------------------------------------------------------------- --- $Id: Slurp.hs,v 1.4 2002/09/18 12:36:40 simonmar Exp $ +-- $Id: Slurp.hs,v 1.5 2004/04/02 14:28:57 simonmar Exp $ -- (c) Simon Marlow 1997-1999 ----------------------------------------------------------------------------- @@ -30,14 +30,14 @@ data Results = Results { module_size :: FiniteMap String Int, binary_size :: Maybe Int, link_time :: Maybe Float, - run_time :: Maybe Float, - mut_time :: Maybe Float, + run_time :: [Float], + mut_time :: [Float], instrs :: Maybe Integer, mem_reads :: Maybe Integer, mem_writes :: Maybe Integer, cache_misses :: Maybe Integer, gc_work :: Maybe Integer, - gc_time :: Maybe Float, + gc_time :: [Float], allocs :: Maybe Integer, run_status :: Status, compile_status :: Status @@ -48,13 +48,13 @@ emptyResults = Results { module_size = emptyFM, binary_size = Nothing, link_time = Nothing, - run_time = Nothing, - mut_time = Nothing, + run_time = [], + mut_time = [], instrs = Nothing, mem_reads = Nothing, mem_writes = Nothing, cache_misses = Nothing, - gc_time = Nothing, + gc_time = [], gc_work = Nothing, allocs = Nothing, compile_status = NotDone, @@ -128,8 +128,11 @@ parse_log combine_results :: [(String,Results)] -> FiniteMap String Results combine_results = foldr f emptyFM where - f (prog,results) fm = addToFM_C comb fm prog results - comb Results{ compile_time = ct1, link_time = lt1, + f (prog,results) fm = addToFM_C combine2Results fm prog results + + +combine2Results + Results{ compile_time = ct1, link_time = lt1, module_size = ms1, run_time = rt1, mut_time = mt1, instrs = is1, mem_reads = mr1, mem_writes = mw1, @@ -148,13 +151,13 @@ combine_results = foldr f emptyFM = Results{ compile_time = plusFM_C const ct1 ct2, module_size = plusFM_C const ms1 ms2, link_time = combMaybes lt1 lt2, - run_time = combMaybes rt1 rt2, - mut_time = combMaybes mt1 mt2, + run_time = rt1 ++ rt2, + mut_time = mt1 ++ mt2, instrs = combMaybes is1 is2, mem_reads = combMaybes mr1 mr2, mem_writes = combMaybes mw1 mw2, cache_misses = combMaybes cm1 cm2, - gc_time = combMaybes gt1 gt2, + gc_time = gt1 ++ gt2, gc_work = combMaybes gw1 gw2, binary_size = combMaybes bs1 bs2, allocs = combMaybes al1 al2, @@ -180,7 +183,7 @@ process_chunk :: ([String],[String]) -> [(String,Results)] process_chunk (prog : what : mod : _, chk) = case what of "time to compile" -> parse_compile_time prog mod chk - "time to run" -> parse_run_time prog (reverse chk) NotDone + "time to run" -> parse_run_time prog (reverse chk) emptyResults NotDone "time to link" -> parse_link_time prog chk "size of" -> parse_size prog mod chk _ -> error ("process_chunk: "++what) @@ -263,97 +266,86 @@ parse_link_time prog (l:ls) = parse_link_time prog ls }} -parse_run_time prog [] NotDone = [] -parse_run_time prog [] ex =[(prog,emptyResults{run_status=ex})] -parse_run_time prog (l:ls) ex = + +-- There might be multiple runs of the program, so we have to collect up +-- all the results. Variable results like runtimes are aggregated into +-- a list, whereas the non-variable aspects are just kept singly. +parse_run_time prog [] res NotDone = [] +parse_run_time prog [] res ex = [(prog, res{run_status=ex})] +parse_run_time prog (l:ls) res ex = case matchRegex ghc1_re l of { Just (allocs:_:_:_:_:init:_:mut:_:gc:_) -> - let - read_mut = read mut - read_gc = read gc - time = (read init + read_mut + read_gc) :: Float - in - [(prog,emptyResults{run_time = Just time, - mut_time = Just read_mut, - gc_time = Just read_gc, - allocs = Just (read allocs), - run_status = Success })]; + got_run_result allocs init mut gc Nothing + Nothing Nothing Nothing Nothing; Nothing -> case matchRegex ghc2_re l of { Just (allocs:_:_:_:_:_:init:_:mut:_:gc:_) -> - let - read_mut = read mut - read_gc = read gc - time = (read init + read_mut + read_gc) :: Float - in - [(prog,emptyResults{run_time = Just time, - mut_time = Just read_mut, - gc_time = Just read_gc, - allocs = Just (read allocs), - run_status = Success })]; + got_run_result allocs init mut gc Nothing + Nothing Nothing Nothing Nothing; + Nothing -> case matchRegex ghc3_re l of { Just (allocs:_:_:_:_:gc_work:_:init:_:mut:_:gc:_) -> - let - read_mut = read mut - read_gc = read gc - read_gc_work = read gc_work - time = (read init + read_mut + read_gc) :: Float - in - [(prog,emptyResults{run_time = Just time, - mut_time = Just read_mut, - gc_work = Just read_gc_work, - gc_time = Just read_gc, - allocs = Just (read allocs), - run_status = Success })]; + got_run_result allocs init mut gc (Just (read gc_work)) + Nothing Nothing Nothing Nothing; + Nothing -> case matchRegex ghc4_re l of { Just (allocs:_:_:_:_:gc_work:_:init:_:mut:_:gc:_:is:mem_rs:mem_ws:cache_misses:_) -> - let - read_mut = read mut - read_gc = read gc - read_gc_work = read gc_work - time = (read init + read_mut + read_gc) :: Float - in - [(prog,emptyResults{run_time = Just time, - mut_time = Just read_mut, - gc_work = Just read_gc_work, - gc_time = Just read_gc, - instrs = Just (read is), - mem_reads = Just (read mem_rs), - mem_writes = Just (read mem_ws), - cache_misses = Just (read cache_misses), - allocs = Just (read allocs), - run_status = Success })]; + got_run_result allocs init mut gc (Just (read gc_work)) + (Just (read is)) (Just (read mem_rs)) + (Just (read mem_ws)) (Just (read cache_misses)); + Nothing -> case matchRegex wrong_output l of { Just ("stdout":_) -> - parse_run_time prog ls (combineRunResult WrongStdout ex); + parse_run_time prog ls res (combineRunResult WrongStdout ex); Just ("stderr":_) -> - parse_run_time prog ls (combineRunResult WrongStderr ex); + parse_run_time prog ls res (combineRunResult WrongStderr ex); Nothing -> case matchRegex wrong_exit_status l of { Just (wanted:got:_) -> - parse_run_time prog ls (combineRunResult (Exit (read got)) ex); + parse_run_time prog ls res (combineRunResult (Exit (read got)) ex); Nothing -> case matchRegex out_of_heap l of { Just _ -> - parse_run_time prog ls (combineRunResult OutOfHeap ex); + parse_run_time prog ls res (combineRunResult OutOfHeap ex); Nothing -> case matchRegex out_of_stack l of { Just _ -> - parse_run_time prog ls (combineRunResult OutOfStack ex); + parse_run_time prog ls res (combineRunResult OutOfStack ex); Nothing -> - parse_run_time prog ls ex; + parse_run_time prog ls res ex; }}}}}}}} + where + got_run_result allocs init mut gc gc_work instrs mem_rs mem_ws cache_misses + = let + read_mut = read mut + read_gc = read gc + time = (read init + read_mut + read_gc) :: Float + res' = combine2Results res + emptyResults{ run_time = [time], + mut_time = [read_mut], + gc_time = [read_gc], + gc_work = gc_work, + allocs = Just (read allocs), + instrs = instrs, + mem_reads = mem_rs, + mem_writes = mem_ws, + cache_misses = cache_misses, + run_status = Success + } + in + parse_run_time prog ls res' Success + combineRunResult OutOfHeap _ = OutOfHeap combineRunResult _ OutOfHeap = OutOfHeap -- 1.7.10.4