1
-----------------------------------------------------------------------------
2
-- $Id: Slurp.hs,v 1.4 2002/09/18 12:36:40 simonmar Exp $
4
-- (c) Simon Marlow 1997-1999
5
-----------------------------------------------------------------------------
7
module Slurp (Status(..), Results(..), ResultTable(..), parse_log) where
14
-----------------------------------------------------------------------------
15
-- This is the structure into which we collect our results:
17
type ResultTable = FiniteMap String Results
28
data Results = Results {
29
compile_time :: FiniteMap String Float,
30
module_size :: FiniteMap String Int,
31
binary_size :: Maybe Int,
32
link_time :: Maybe Float,
33
run_time :: Maybe Float,
34
mut_time :: Maybe Float,
35
instrs :: Maybe Integer,
36
mem_reads :: Maybe Integer,
37
mem_writes :: Maybe Integer,
38
cache_misses :: Maybe Integer,
39
gc_work :: Maybe Integer,
40
gc_time :: Maybe Float,
41
allocs :: Maybe Integer,
43
compile_status :: Status
46
emptyResults = Results {
47
compile_time = emptyFM,
48
module_size = emptyFM,
49
binary_size = Nothing,
56
cache_misses = Nothing,
60
compile_status = NotDone,
64
-----------------------------------------------------------------------------
70
==nofib== awards: size of QSort.o follows...
71
==nofib== banner: size of banner follows...
72
==nofib== awards: time to link awards follows...
73
==nofib== awards: time to run awards follows...
74
==nofib== boyer2: time to compile Checker follows...
77
banner_re = mkRegex "^==nofib==[ \t]+([A-Za-z0-9_]+):[ \t]+(size of|time to link|time to run|time to compile)[ \t]+([A-Za-z0-9_]+)(\\.o)?[ \t]+follows"
80
This regexp for the output of "time" works on FreeBSD, other versions
81
of "time" will need different regexps.
84
time_re = mkRegex "^[ \t]*([0-9.]+)[ \t]+real[ \t]+([0-9.]+)[ \t]+user[ \t]+([0-9.]+)[ \t]+sys[ \t]*$"
86
time_gnu17_re = mkRegex "^[ \t]*([0-9.]+)user[ \t]+([0-9.]+)system[ \t]+([0-9.:]+)elapsed"
87
-- /usr/bin/time --version reports: GNU time 1.7
88
-- notice the order is different, and the elapsed time is [hh:]mm:ss.s
90
size_re = mkRegex "^[ \t]*([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)"
93
<<ghc: 5820820 bytes, 0 GCs, 0/0 avg/max bytes residency (0 samples), 41087234 bytes GC work, 0.00 INIT (0.05 elapsed), 0.08 MUT (0.18 elapsed), 0.00 GC (0.00 elapsed) :ghc>>
95
= (bytes, gcs, avg_resid, max_resid, samples, gc_work,
96
init, init_elapsed, mut, mut_elapsed, gc, gc_elapsed)
98
ghc1_re = pre GHC 4.02
99
ghc2_re = GHC 4.02 (includes "xxM in use")
100
ghc3_re = GHC 4.03 (includes "xxxx bytes GC work")
103
ghc1_re = mkRegex "^<<ghc:[ \t]+([0-9]+)[ \t]+bytes,[ \t]*([0-9]+)[ \t]+GCs,[ \t]*([0-9]+)/([0-9]+)[ \t]+avg/max bytes residency \\(([0-9]+) samples\\), ([0-9]+) bytes GC work, ([0-9.]+) INIT \\(([0-9.]+) elapsed\\), ([0-9.]+) MUT \\(([0-9.]+) elapsed\\), ([0-9.]+) GC \\(([0-9.]+) elapsed\\) :ghc>>"
105
ghc2_re = mkRegex "^<<ghc:[ \t]+([0-9]+)[ \t]+bytes,[ \t]*([0-9]+)[ \t]+GCs,[ \t]*([0-9]+)/([0-9]+)[ \t]+avg/max bytes residency \\(([0-9]+) samples\\), ([0-9]+)M in use, ([0-9.]+) INIT \\(([0-9.]+) elapsed\\), ([0-9.]+) MUT \\(([0-9.]+) elapsed\\), ([0-9.]+) GC \\(([0-9.]+) elapsed\\) :ghc>>"
107
ghc3_re = mkRegex "^<<ghc:[ \t]+([0-9]+)[ \t]+bytes,[ \t]*([0-9]+)[ \t]+GCs,[ \t]*([0-9]+)/([0-9]+)[ \t]+avg/max bytes residency \\(([0-9]+) samples\\), ([0-9]+) bytes GC work, ([0-9]+)M in use, ([0-9.]+) INIT \\(([0-9.]+) elapsed\\), ([0-9.]+) MUT \\(([0-9.]+) elapsed\\), ([0-9.]+) GC \\(([0-9.]+) elapsed\\) :ghc>>"
109
ghc4_re = mkRegex "^<<ghc-instrs:[ \t]+([0-9]+)[ \t]+bytes,[ \t]*([0-9]+)[ \t]+GCs,[ \t]*([0-9]+)/([0-9]+)[ \t]+avg/max bytes residency \\(([0-9]+) samples\\), ([0-9]+) bytes GC work, ([0-9]+)M in use, ([0-9.]+) INIT \\(([0-9.]+) elapsed\\), ([0-9.]+) MUT \\(([0-9.]+) elapsed\\), ([0-9.]+) GC \\(([0-9.]+) elapsed\\), ([0-9]+) instructions, ([0-9]+) memory reads, ([0-9]+) memory writes, ([0-9]+) L2 cache misses :ghc-instrs>>"
111
wrong_exit_status = mkRegex "^\\**[ \t]*expected exit status ([0-9]+) not seen ; got ([0-9]+)"
113
wrong_output = mkRegex "^expected (stdout|stderr) not matched by reality$"
115
out_of_heap = mkRegex "^\\+ Heap exhausted;$"
117
out_of_stack = mkRegex "^\\+ Stack space overflow:"
119
parse_log :: String -> ResultTable
121
= combine_results -- collate information
123
. map process_chunk -- get information from each chunk
124
. tail -- first chunk is junk
125
. chunk_log [] [] -- break at banner lines
128
combine_results :: [(String,Results)] -> FiniteMap String Results
129
combine_results = foldr f emptyFM
131
f (prog,results) fm = addToFM_C comb fm prog results
132
comb Results{ compile_time = ct1, link_time = lt1,
134
run_time = rt1, mut_time = mt1,
135
instrs = is1, mem_reads = mr1, mem_writes = mw1,
137
gc_time = gt1, gc_work = gw1,
138
binary_size = bs1, allocs = al1,
139
run_status = rs1, compile_status = cs1 }
140
Results{ compile_time = ct2, link_time = lt2,
142
run_time = rt2, mut_time = mt2,
143
instrs = is2, mem_reads = mr2, mem_writes = mw2,
145
gc_time = gt2, gc_work = gw2,
146
binary_size = bs2, allocs = al2,
147
run_status = rs2, compile_status = cs2 }
148
= Results{ compile_time = plusFM_C const ct1 ct2,
149
module_size = plusFM_C const ms1 ms2,
150
link_time = combMaybes lt1 lt2,
151
run_time = combMaybes rt1 rt2,
152
mut_time = combMaybes mt1 mt2,
153
instrs = combMaybes is1 is2,
154
mem_reads = combMaybes mr1 mr2,
155
mem_writes = combMaybes mw1 mw2,
156
cache_misses = combMaybes cm1 cm2,
157
gc_time = combMaybes gt1 gt2,
158
gc_work = combMaybes gw1 gw2,
159
binary_size = combMaybes bs1 bs2,
160
allocs = combMaybes al1 al2,
161
run_status = combStatus rs1 rs2,
162
compile_status = combStatus cs1 cs2 }
164
combMaybes m1 m2 = case maybeToList m1 ++ maybeToList m2 of
168
combStatus NotDone x = x
169
combStatus x NotDone = x
172
chunk_log :: [String] -> [String] -> [String] -> [([String],[String])]
173
chunk_log header chunk [] = [(header,chunk)]
174
chunk_log header chunk (l:ls) =
175
case matchRegex banner_re l of
176
Nothing -> chunk_log header (l:chunk) ls
177
Just stuff -> (header,chunk) : chunk_log stuff [] ls
179
process_chunk :: ([String],[String]) -> [(String,Results)]
180
process_chunk (prog : what : mod : _, chk) =
182
"time to compile" -> parse_compile_time prog mod chk
183
"time to run" -> parse_run_time prog (reverse chk) NotDone
184
"time to link" -> parse_link_time prog chk
185
"size of" -> parse_size prog mod chk
186
_ -> error ("process_chunk: "++what)
188
parse_compile_time prog mod [] = []
189
parse_compile_time prog mod (l:ls) =
190
case matchRegex time_re l of {
191
Just (real:user:system:_) ->
192
let ct = addToFM emptyFM mod (read user)
194
[(prog,emptyResults{compile_time = ct})];
197
case matchRegex time_gnu17_re l of {
198
Just (user:system:elapsed:_) ->
199
let ct = addToFM emptyFM mod (read user)
201
[(prog,emptyResults{compile_time = ct})];
204
case matchRegex ghc1_re l of {
205
Just (allocs:_:_:_:_:init:_:mut:_:gc:_) ->
209
time = (read init + read_mut + read_gc) :: Float
210
ct = addToFM emptyFM mod time
212
[(prog,emptyResults{compile_time = ct})];
215
case matchRegex ghc2_re l of {
216
Just (allocs:_:_:_:_:_:init:_:mut:_:gc:_) ->
220
time = (read init + read_mut + read_gc) :: Float
221
ct = addToFM emptyFM mod time
223
[(prog,emptyResults{compile_time = ct})];
226
case matchRegex ghc3_re l of {
227
Just (allocs:_:_:_:_:_:_:init:_:mut:_:gc:_) ->
231
time = (read init + read_mut + read_gc) :: Float
232
ct = addToFM emptyFM mod time
234
[(prog,emptyResults{compile_time = ct})];
237
case matchRegex ghc4_re l of {
238
Just (allocs:_:_:_:_:_:_:init:_:mut:_:gc:_:_:_:_) ->
242
time = (read init + read_mut + read_gc) :: Float
243
ct = addToFM emptyFM mod time
245
[(prog,emptyResults{compile_time = ct})];
248
parse_compile_time prog mod ls
251
parse_link_time prog [] = []
252
parse_link_time prog (l:ls) =
253
case matchRegex time_re l of {
254
Just (real:user:system:_) ->
255
[(prog,emptyResults{link_time = Just (read user)})];
258
case matchRegex time_gnu17_re l of {
259
Just (user:system:elapsed:_) ->
260
[(prog,emptyResults{link_time = Just (read user)})];
263
parse_link_time prog ls
266
parse_run_time prog [] NotDone = []
267
parse_run_time prog [] ex =[(prog,emptyResults{run_status=ex})]
268
parse_run_time prog (l:ls) ex =
269
case matchRegex ghc1_re l of {
270
Just (allocs:_:_:_:_:init:_:mut:_:gc:_) ->
274
time = (read init + read_mut + read_gc) :: Float
276
[(prog,emptyResults{run_time = Just time,
277
mut_time = Just read_mut,
278
gc_time = Just read_gc,
279
allocs = Just (read allocs),
280
run_status = Success })];
283
case matchRegex ghc2_re l of {
284
Just (allocs:_:_:_:_:_:init:_:mut:_:gc:_) ->
288
time = (read init + read_mut + read_gc) :: Float
290
[(prog,emptyResults{run_time = Just time,
291
mut_time = Just read_mut,
292
gc_time = Just read_gc,
293
allocs = Just (read allocs),
294
run_status = Success })];
297
case matchRegex ghc3_re l of {
298
Just (allocs:_:_:_:_:gc_work:_:init:_:mut:_:gc:_) ->
302
read_gc_work = read gc_work
303
time = (read init + read_mut + read_gc) :: Float
305
[(prog,emptyResults{run_time = Just time,
306
mut_time = Just read_mut,
307
gc_work = Just read_gc_work,
308
gc_time = Just read_gc,
309
allocs = Just (read allocs),
310
run_status = Success })];
313
case matchRegex ghc4_re l of {
314
Just (allocs:_:_:_:_:gc_work:_:init:_:mut:_:gc:_:is:mem_rs:mem_ws:cache_misses:_) ->
318
read_gc_work = read gc_work
319
time = (read init + read_mut + read_gc) :: Float
321
[(prog,emptyResults{run_time = Just time,
322
mut_time = Just read_mut,
323
gc_work = Just read_gc_work,
324
gc_time = Just read_gc,
325
instrs = Just (read is),
326
mem_reads = Just (read mem_rs),
327
mem_writes = Just (read mem_ws),
328
cache_misses = Just (read cache_misses),
329
allocs = Just (read allocs),
330
run_status = Success })];
333
case matchRegex wrong_output l of {
335
parse_run_time prog ls (combineRunResult WrongStdout ex);
337
parse_run_time prog ls (combineRunResult WrongStderr ex);
340
case matchRegex wrong_exit_status l of {
341
Just (wanted:got:_) ->
342
parse_run_time prog ls (combineRunResult (Exit (read got)) ex);
345
case matchRegex out_of_heap l of {
347
parse_run_time prog ls (combineRunResult OutOfHeap ex);
350
case matchRegex out_of_stack l of {
352
parse_run_time prog ls (combineRunResult OutOfStack ex);
354
parse_run_time prog ls ex;
358
combineRunResult OutOfHeap _ = OutOfHeap
359
combineRunResult _ OutOfHeap = OutOfHeap
360
combineRunResult OutOfStack _ = OutOfStack
361
combineRunResult _ OutOfStack = OutOfStack
362
combineRunResult (Exit e) _ = Exit e
363
combineRunResult _ (Exit e) = Exit e
364
combineRunResult exit _ = exit
366
parse_size prog mod [] = []
367
parse_size prog mod (l:ls) =
368
case matchRegex size_re l of
369
Nothing -> parse_size prog mod ls
370
Just (text:datas:bss:_)
372
[(prog,emptyResults{binary_size =
373
Just (read text + read datas),
374
compile_status = Success})]
376
let ms = addToFM emptyFM mod (read text + read datas)
378
[(prog,emptyResults{module_size = ms})]