[project @ 2002-01-09 10:29:32 by simonmar]
[ghc-hetmet.git] / glafp-utils / nofib-analyse / Slurp.hs
1 -----------------------------------------------------------------------------
2 -- $Id: Slurp.hs,v 1.2 2000/02/18 10:25:53 simonmar Exp $
3
4 -- (c) Simon Marlow 1997-1999
5 -----------------------------------------------------------------------------
6
7 module Slurp (Status(..), Results(..), ResultTable(..), parse_log) where
8
9 import CmdLine
10 import FiniteMap
11 import RegexString
12 import Maybe
13
14 -----------------------------------------------------------------------------
15 -- This is the structure into which we collect our results:
16
17 type ResultTable = FiniteMap String Results
18
19 data Status
20         = NotDone
21         | Success
22         | OutOfHeap
23         | OutOfStack
24         | Exit Int
25         | WrongStdout
26         | WrongStderr 
27
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         gc_work         :: Maybe Integer,
39         gc_time         :: Maybe Float,
40         allocs          :: Maybe Integer,
41         run_status      :: Status,
42         compile_status  :: Status
43         }
44
45 emptyResults = Results { 
46         compile_time    = emptyFM,
47         module_size     = emptyFM,
48         binary_size     = Nothing,
49         link_time       = Nothing,
50         run_time        = Nothing,
51         mut_time        = Nothing,
52         instrs          = Nothing,
53         mem_reads       = Nothing,
54         mem_writes      = Nothing,
55         gc_time         = Nothing,
56         gc_work         = Nothing,
57         allocs          = Nothing,
58         compile_status  = NotDone,
59         run_status      = NotDone
60         }
61
62 -----------------------------------------------------------------------------
63 -- Parse the log file
64
65 {-
66 Various banner lines:
67
68 ==nofib== awards: size of QSort.o follows...
69 ==nofib== banner: size of banner follows...
70 ==nofib== awards: time to link awards follows...
71 ==nofib== awards: time to run awards follows...
72 ==nofib== boyer2: time to compile Checker follows...
73 -}
74
75 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"
76
77 {-
78 This regexp for the output of "time" works on FreeBSD, other versions
79 of "time" will need different regexps.
80 -}
81
82 time_re = mkRegex "^[ \t]*([0-9.]+)[ \t]+real[ \t]+([0-9.]+)[ \t]+user[ \t]+([0-9.]+)[ \t]+sys[ \t]*$"
83
84 size_re = mkRegex "^[ \t]*([0-9]+)[ \t]+([0-9]+)[ \t]+([0-9]+)"
85
86 {-
87 <<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>>
88
89         = (bytes, gcs, avg_resid, max_resid, samples, gc_work,
90            init, init_elapsed, mut, mut_elapsed, gc, gc_elapsed)
91
92 ghc1_re = pre GHC 4.02
93 ghc2_re = GHC 4.02 (includes "xxM in use")
94 ghc3_re = GHC 4.03 (includes "xxxx bytes GC work")
95 -}
96
97 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>>"
98
99 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>>"
100
101 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>>"
102
103 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 :ghc-instrs>>"
104
105 wrong_exit_status = mkRegex "^\\**[ \t]*expected exit status ([0-9]+) not seen ; got ([0-9]+)"
106
107 wrong_output = mkRegex "^expected (stdout|stderr) not matched by reality$"
108
109 out_of_heap = mkRegex "^\\+ Heap exhausted;$"
110
111 out_of_stack = mkRegex "^\\+ Stack space overflow:"
112
113 parse_log :: String -> ResultTable
114 parse_log
115         = combine_results               -- collate information
116         . concat
117         . map process_chunk             -- get information from each chunk
118         . tail                          -- first chunk is junk
119         . chunk_log [] []               -- break at banner lines
120         . lines
121
122 combine_results :: [(String,Results)] -> FiniteMap String Results
123 combine_results = foldr f emptyFM
124  where
125         f (prog,results) fm = addToFM_C comb fm prog results
126         comb Results{ compile_time = ct1, link_time = lt1, 
127                       module_size = ms1,
128                       run_time = rt1, mut_time = mt1, 
129                       instrs = is1, mem_reads = mr1, mem_writes = mw1,
130                       gc_time = gt1, gc_work = gw1,
131                       binary_size = bs1, allocs = al1, 
132                       run_status = rs1, compile_status = cs1 }
133              Results{ compile_time = ct2, link_time = lt2, 
134                       module_size = ms2,
135                       run_time = rt2, mut_time = mt2,
136                       instrs = is2, mem_reads = mr2, mem_writes = mw2,
137                       gc_time = gt2, gc_work = gw2,
138                       binary_size = bs2, allocs = al2, 
139                       run_status = rs2, compile_status = cs2 }
140           =  Results{ compile_time   = plusFM_C const ct1 ct2,
141                       module_size    = plusFM_C const ms1 ms2,
142                       link_time      = combMaybes lt1 lt2,
143                       run_time       = combMaybes rt1 rt2,
144                       mut_time       = combMaybes mt1 mt2,
145                       instrs         = combMaybes is1 is2,
146                       mem_reads      = combMaybes mr1 mr2,
147                       mem_writes     = combMaybes mw1 mw2,
148                       gc_time        = combMaybes gt1 gt2,
149                       gc_work        = combMaybes gw1 gw2,
150                       binary_size    = combMaybes bs1 bs2,
151                       allocs         = combMaybes al1 al2,
152                       run_status     = combStatus rs1 rs2,
153                       compile_status = combStatus cs1 cs2 }
154
155 combMaybes m1 m2 = case maybeToList m1 ++ maybeToList m2 of
156                         [] -> Nothing
157                         (x:_) -> Just x
158
159 combStatus NotDone x = x
160 combStatus x NotDone = x
161 combStatus x y = x
162
163 chunk_log :: [String] -> [String] -> [String] -> [([String],[String])]
164 chunk_log header chunk [] = [(header,chunk)]
165 chunk_log header chunk (l:ls) =
166         case matchRegex banner_re l of
167                 Nothing -> chunk_log header (l:chunk) ls
168                 Just stuff -> (header,chunk) : chunk_log stuff [] ls
169
170 process_chunk :: ([String],[String]) -> [(String,Results)]
171 process_chunk (prog : what : mod : _, chk) =
172  case what of
173         "time to compile" -> parse_compile_time prog mod chk
174         "time to run"     -> parse_run_time prog (reverse chk) NotDone
175         "time to link"    -> parse_link_time prog chk
176         "size of"         -> parse_size prog mod chk
177         _                 -> error ("process_chunk: "++what)
178
179 parse_compile_time prog mod [] = []
180 parse_compile_time prog mod (l:ls) =
181         case matchRegex time_re l of {
182              Just (real:user:system:_) ->
183                 let ct  = addToFM emptyFM mod (read user)
184                 in 
185                 [(prog,emptyResults{compile_time = ct})];
186              Nothing -> 
187
188         case matchRegex ghc1_re l of {
189             Just (allocs:_:_:_:_:init:_:mut:_:gc:_) ->
190               let 
191                   read_mut = read mut
192                   read_gc  = read gc
193                   time = (read init + read_mut + read_gc) :: Float 
194                   ct  = addToFM emptyFM mod time
195               in
196                 [(prog,emptyResults{compile_time = ct})];
197             Nothing ->
198
199         case matchRegex ghc2_re l of {
200            Just (allocs:_:_:_:_:_:init:_:mut:_:gc:_) ->
201               let 
202                   read_mut = read mut
203                   read_gc  = read gc
204                   time = (read init + read_mut + read_gc) :: Float 
205                   ct  = addToFM emptyFM mod time
206               in
207                 [(prog,emptyResults{compile_time = ct})];
208             Nothing ->
209
210         case matchRegex ghc3_re l of {
211            Just (allocs:_:_:_:_:_:_:init:_:mut:_:gc:_) ->
212               let 
213                   read_mut = read mut
214                   read_gc  = read gc
215                   time = (read init + read_mut + read_gc) :: Float 
216                   ct  = addToFM emptyFM mod time
217               in
218                 [(prog,emptyResults{compile_time = ct})];
219             Nothing ->
220
221         case matchRegex ghc4_re l of {
222            Just (allocs:_:_:_:_:_:_:init:_:mut:_:gc:_:_:_:_) ->
223               let 
224                   read_mut = read mut
225                   read_gc  = read gc
226                   time = (read init + read_mut + read_gc) :: Float 
227                   ct  = addToFM emptyFM mod time
228               in
229                 [(prog,emptyResults{compile_time = ct})];
230             Nothing ->
231
232                 parse_compile_time prog mod ls
233         }}}}}
234
235 parse_link_time prog [] = []
236 parse_link_time prog (l:ls) =
237           case matchRegex time_re l of
238              Nothing -> parse_link_time prog ls
239              Just (real:user:system:_) ->
240                 [(prog,emptyResults{link_time = Just (read user)})]
241
242 parse_run_time prog [] NotDone = []
243 parse_run_time prog [] ex =[(prog,emptyResults{run_status=ex})]
244 parse_run_time prog (l:ls) ex =
245         case matchRegex ghc1_re l of {
246            Just (allocs:_:_:_:_:init:_:mut:_:gc:_) ->
247               let 
248                   read_mut = read mut
249                   read_gc  = read gc
250                   time = (read init + read_mut + read_gc) :: Float 
251               in
252               [(prog,emptyResults{run_time   = Just time,
253                                   mut_time   = Just read_mut,
254                                   gc_time    = Just read_gc,
255                                   allocs     = Just (read allocs),
256                                   run_status = Success })];
257            Nothing -> 
258
259         case matchRegex ghc2_re l of {
260            Just (allocs:_:_:_:_:_:init:_:mut:_:gc:_) ->
261               let 
262                   read_mut = read mut
263                   read_gc  = read gc
264                   time = (read init + read_mut + read_gc) :: Float 
265               in
266               [(prog,emptyResults{run_time   = Just time,
267                                   mut_time   = Just read_mut,
268                                   gc_time    = Just read_gc,
269                                   allocs     = Just (read allocs),
270                                   run_status = Success })];
271             Nothing ->
272         
273         case matchRegex ghc3_re l of {
274            Just (allocs:_:_:_:_:gc_work:_:init:_:mut:_:gc:_) ->
275               let 
276                   read_mut = read mut
277                   read_gc  = read gc
278                   read_gc_work = read gc_work
279                   time = (read init + read_mut + read_gc) :: Float 
280               in
281               [(prog,emptyResults{run_time   = Just time,
282                                   mut_time   = Just read_mut,
283                                   gc_work    = Just read_gc_work,
284                                   gc_time    = Just read_gc,
285                                   allocs     = Just (read allocs),
286                                   run_status = Success })];
287             Nothing ->
288         
289         case matchRegex ghc4_re l of {
290            Just (allocs:_:_:_:_:gc_work:_:init:_:mut:_:gc:_:is:mem_rs:mem_ws:_) ->
291               let 
292                   read_mut = read mut
293                   read_gc  = read gc
294                   read_gc_work = read gc_work
295                   time = (read init + read_mut + read_gc) :: Float 
296               in
297               [(prog,emptyResults{run_time   = Just time,
298                                   mut_time   = Just read_mut,
299                                   gc_work    = Just read_gc_work,
300                                   gc_time    = Just read_gc,
301                                   instrs     = Just (read is),
302                                   mem_writes = Just (read mem_ws),
303                                   mem_reads  = Just (read mem_rs),
304                                   allocs     = Just (read allocs),
305                                   run_status = Success })];
306             Nothing ->
307         
308         case matchRegex wrong_output l of {
309             Just ("stdout":_) -> 
310                 parse_run_time prog ls (combineRunResult WrongStdout ex);
311             Just ("stderr":_) -> 
312                 parse_run_time prog ls (combineRunResult WrongStderr ex);
313             Nothing ->
314                         
315         case matchRegex wrong_exit_status l of {
316             Just (wanted:got:_) -> 
317                 parse_run_time prog ls (combineRunResult (Exit (read got)) ex);
318             Nothing -> 
319
320         case matchRegex out_of_heap l of {
321             Just _ -> 
322                 parse_run_time prog ls (combineRunResult OutOfHeap ex);
323             Nothing -> 
324
325         case matchRegex out_of_stack l of {
326             Just _ -> 
327                 parse_run_time prog ls (combineRunResult OutOfStack ex);
328             Nothing -> 
329                 parse_run_time prog ls ex;
330
331         }}}}}}}}
332
333 combineRunResult OutOfHeap  _           = OutOfHeap
334 combineRunResult _          OutOfHeap   = OutOfHeap
335 combineRunResult OutOfStack _           = OutOfStack
336 combineRunResult _          OutOfStack  = OutOfStack
337 combineRunResult (Exit e)   _           = Exit e
338 combineRunResult _          (Exit e)    = Exit e
339 combineRunResult exit       _            = exit
340
341 parse_size prog mod [] = []
342 parse_size prog mod (l:ls) =
343         case matchRegex size_re l of
344             Nothing -> parse_size prog mod ls
345             Just (text:datas:bss:_) 
346                  | prog == mod ->
347                         [(prog,emptyResults{binary_size = 
348                                               Just (read text + read datas),
349                                     compile_status = Success})]
350                  | otherwise ->
351                         let ms  = addToFM emptyFM mod (read text + read datas)
352                         in
353                         [(prog,emptyResults{module_size = ms})]
354