1 : |
monnier |
219 |
(* Copyright 1996 by Yale FLINT Project *)
|
2 : |
|
|
(* util/timeStd.sml *)
|
3 : |
|
|
|
4 : |
|
|
(* a signature template for all std benchmarks *)
|
5 : |
|
|
signature BMARK =
|
6 : |
|
|
sig
|
7 : |
|
|
val doit : unit -> unit
|
8 : |
|
|
val testit : TextIO.outstream -> unit
|
9 : |
|
|
end
|
10 : |
|
|
|
11 : |
|
|
signature TIMING =
|
12 : |
|
|
sig
|
13 : |
|
|
type filename = string
|
14 : |
|
|
type hint = string
|
15 : |
|
|
type outstream = TextIO.outstream
|
16 : |
|
|
|
17 : |
|
|
val timeComp : filename -> unit
|
18 : |
|
|
val timeRun : (unit -> unit) -> unit (* run three times *)
|
19 : |
|
|
val timeIt : (unit -> unit) -> unit (* run once *)
|
20 : |
|
|
|
21 : |
|
|
val timeRunF : outstream * (unit -> unit) -> unit
|
22 : |
|
|
val timeCompF : outstream * filename -> unit
|
23 : |
|
|
|
24 : |
|
|
(*
|
25 : |
|
|
* Timing the compilation of a particular benchmark;
|
26 : |
|
|
* Arg #1 is the output file.
|
27 : |
|
|
* Arg #2 is the "hint" field, used by the Latex option only.
|
28 : |
|
|
* It is not pretty; the data processing to build latex table
|
29 : |
|
|
* should simply be separated out from this script in the long run.
|
30 : |
|
|
*
|
31 : |
|
|
* Arg #3 for timeRun is the number of times each bench should be run.
|
32 : |
|
|
* Notice each run already consists of three repetitions.
|
33 : |
|
|
* Arg #4 for timeRun is the actual loader for the benchmark.
|
34 : |
|
|
*
|
35 : |
|
|
* Arg #3 for timeComp is just the benchmark filename.
|
36 : |
|
|
*)
|
37 : |
|
|
|
38 : |
|
|
val timeRunK : outstream * hint * int * (unit -> unit) -> unit
|
39 : |
|
|
val timeRunKJgraph : outstream * hint * int * (unit -> unit) -> unit
|
40 : |
|
|
val timeRunKLatex : outstream * hint * int * (unit -> unit) -> unit
|
41 : |
|
|
|
42 : |
|
|
val timeCompK : outstream * hint * filename -> unit
|
43 : |
|
|
val timeCompKJgraph : outstream * hint * filename -> unit
|
44 : |
|
|
val timeCompKLatex : outstream * hint * filename -> unit
|
45 : |
|
|
|
46 : |
|
|
end (* end of signature TIMING *)
|
47 : |
|
|
|
48 : |
|
|
|
49 : |
|
|
(***************************************************************************
|
50 : |
|
|
* The Timing Structure *
|
51 : |
|
|
***************************************************************************)
|
52 : |
|
|
structure Timing : TIMING =
|
53 : |
|
|
struct
|
54 : |
|
|
|
55 : |
|
|
local structure T = Time
|
56 : |
|
|
structure Tm = Timer
|
57 : |
|
|
in
|
58 : |
|
|
|
59 : |
|
|
type filename = string
|
60 : |
|
|
type hint = string
|
61 : |
|
|
type outstream = TextIO.outstream
|
62 : |
|
|
type time = T.time
|
63 : |
|
|
type timing = {usr:time, gc:time, sys:time, real:time, alloc:int}
|
64 : |
|
|
|
65 : |
|
|
val timeofday : unit -> T.time = T.now
|
66 : |
|
|
val start_timer = Tm.startCPUTimer
|
67 : |
|
|
val check_timer = Tm.checkCPUTimer
|
68 : |
|
|
|
69 : |
|
|
val gcCtl : ((string * int ref) list -> unit) =
|
70 : |
|
|
Unsafe.CInterface.c_function "SMLNJ-RunT" "gcControl"
|
71 : |
|
|
fun doGC n = gcCtl [("DoGC", ref n)]
|
72 : |
|
|
|
73 : |
|
|
(* convert a time value to a integer *)
|
74 : |
|
|
fun timeToInt t = LargeInt.toInt (T.toMilliseconds t)
|
75 : |
|
|
|
76 : |
|
|
val pad10 = " "
|
77 : |
|
|
fun pad (s, n) =
|
78 : |
|
|
let val l = size s
|
79 : |
|
|
in if (n <= l) then s
|
80 : |
|
|
else if ((n-l) >= 10)
|
81 : |
|
|
then pad (pad10^s, n)
|
82 : |
|
|
else substring(pad10, 0, n-l) ^ s
|
83 : |
|
|
end
|
84 : |
|
|
|
85 : |
|
|
fun start () = (doGC 2;
|
86 : |
|
|
(* System.Runtime.gc 2;
|
87 : |
|
|
System.Runtime.allocsize := 0;
|
88 : |
|
|
System.Runtime.spaceusage := 0;
|
89 : |
|
|
*)
|
90 : |
|
|
{realt = timeofday(), timer = start_timer()})
|
91 : |
|
|
|
92 : |
|
|
fun stop {realt=rt, timer=t} =
|
93 : |
|
|
let val t' = check_timer t
|
94 : |
|
|
val tc = #usr t'
|
95 : |
|
|
val ts = #sys t'
|
96 : |
|
|
val tg = #gc t'
|
97 : |
|
|
val rt' = T.-(timeofday(),rt)
|
98 : |
|
|
val _ = doGC 2
|
99 : |
|
|
(* val _ = System.Runtime.gc 2 *)
|
100 : |
|
|
val alloc = 0 (* !allocsize *)
|
101 : |
|
|
val spaceuse = 0 (* !spaceusage *)
|
102 : |
|
|
in (timeToInt tc, timeToInt tg, timeToInt ts,
|
103 : |
|
|
timeToInt rt', alloc, spaceuse)
|
104 : |
|
|
end
|
105 : |
|
|
|
106 : |
|
|
(** this function requires clean-up *)
|
107 : |
|
|
fun getCodeSize(s) =
|
108 : |
|
|
let fun h(x::r,s) =
|
109 : |
|
|
if (Char.>=(x,#"0") andalso Char.<=(x,#"9")) then
|
110 : |
|
|
(let val k = Char.ord(x) - Char.ord(#"0")
|
111 : |
|
|
in h(r, k+(s*10))
|
112 : |
|
|
end)
|
113 : |
|
|
else h(r,s)
|
114 : |
|
|
| h([],s) = s
|
115 : |
|
|
in h((explode s),0)
|
116 : |
|
|
end
|
117 : |
|
|
|
118 : |
|
|
(* Time one compilation of the benchmark *)
|
119 : |
|
|
(* TODO: add breakdown summary figures to the compile time list *)
|
120 : |
|
|
fun compileIt (fname) =
|
121 : |
|
|
let (* val _ = OS.FileSys.chDir fname *)
|
122 : |
|
|
val spfile = "/tmp/.codesize3"
|
123 : |
|
|
val tmpstream = TextIO.openOut(spfile)
|
124 : |
|
|
val _ = Compiler.Stats.reset()
|
125 : |
|
|
val t0 = start()
|
126 : |
|
|
val _ = use fname
|
127 : |
|
|
val res = stop t0
|
128 : |
|
|
|
129 : |
|
|
val sss = fn s => TextIO.output(tmpstream, s)
|
130 : |
|
|
val fff = fn () => TextIO.flushOut(tmpstream)
|
131 : |
|
|
val tmp = !Compiler.Control.Print.out
|
132 : |
|
|
val _ = (Compiler.Control.Print.out := {flush=fff, say=sss})
|
133 : |
|
|
val _ = Compiler.Stats.summary()
|
134 : |
|
|
val _ = (Compiler.Control.Print.out := tmp)
|
135 : |
|
|
val _ = (fff(); TextIO.closeOut tmpstream)
|
136 : |
|
|
|
137 : |
|
|
val tmpstream = TextIO.openIn(spfile)
|
138 : |
|
|
val line = TextIO.inputLine(tmpstream)
|
139 : |
|
|
val sz = getCodeSize(line)
|
140 : |
|
|
val _ = TextIO.closeIn(tmpstream)
|
141 : |
|
|
val _ = OS.FileSys.remove spfile
|
142 : |
|
|
(*
|
143 : |
|
|
val _ = print ("** " ^ line)
|
144 : |
|
|
val _ = print ("**, " ^ (Int.toString sz) ^ " ** \n")
|
145 : |
|
|
*)
|
146 : |
|
|
in (#1 res, #2 res, #3 res, #4 res, #5 res, sz)
|
147 : |
|
|
end
|
148 : |
|
|
|
149 : |
|
|
val maxConst = 536870912
|
150 : |
|
|
|
151 : |
|
|
fun loop(b : int,n,s,f) =
|
152 : |
|
|
if b > n then ()
|
153 : |
|
|
else (f(b); loop(b+s,n,s,f))
|
154 : |
|
|
|
155 : |
|
|
fun accum(b : int, n, s, init, merge, f) =
|
156 : |
|
|
if b > n then init
|
157 : |
|
|
else (merge(f(b),accum(b+s,n,s,init,merge,f)))
|
158 : |
|
|
|
159 : |
|
|
fun runItOnce doit =
|
160 : |
|
|
let val t0 = start()
|
161 : |
|
|
in doit(); stop t0
|
162 : |
|
|
end
|
163 : |
|
|
|
164 : |
|
|
(* run it k times, get the average *)
|
165 : |
|
|
fun runIt (doit, k) =
|
166 : |
|
|
let val result = Array.array(k+1,(0,0,0,0,0,0))
|
167 : |
|
|
val _ = loop(1,k,1,fn j => (Array.update(result,j,runItOnce doit)))
|
168 : |
|
|
val init = (0,0,0,0,0,0)
|
169 : |
|
|
fun merge((x1,x2,x3,x4,x5,x6),(y1,y2,y3,y4,y5,y6)) =
|
170 : |
|
|
(x1+y1+0,x2+y2+0,x3+y3+0,x4+y4+0,x5+y5+0,x6+y6+0)
|
171 : |
|
|
fun f(j) = Array.sub(result,j)
|
172 : |
|
|
val (x1,x2,x3,x4,x5,x6) = accum(1,k,1,init,merge,f)
|
173 : |
|
|
val h = Int.div
|
174 : |
|
|
in (h(x1,k), h(x2,k), h(x3,k), h(x4,k), h(x5,k), h(x6,k))
|
175 : |
|
|
end
|
176 : |
|
|
|
177 : |
|
|
val numRep = 3
|
178 : |
|
|
|
179 : |
|
|
(* run it k times, pick the best run *)
|
180 : |
|
|
fun runItK (k, doit) =
|
181 : |
|
|
let val result = Array.array(k+1,(0,0,0,0,0,0))
|
182 : |
|
|
val _ = loop(1,k,1,fn j => (Array.update(result,j,runIt(doit, numRep))))
|
183 : |
|
|
val init = (maxConst,0,0,maxConst,0,0)
|
184 : |
|
|
fun merge(xx as (x1,x2,x3,x4 : int,x5,x6), yy as (y1,y2,y3,y4,y5,y6)) =
|
185 : |
|
|
if (x4 > y4) then yy else xx
|
186 : |
|
|
(* if (x1 > y1) then yy else xx *)
|
187 : |
|
|
fun f(j) = Array.sub(result,j)
|
188 : |
|
|
in accum(1,k,1,init,merge,f)
|
189 : |
|
|
end
|
190 : |
|
|
|
191 : |
|
|
(***************************************************************************
|
192 : |
|
|
* OUTPUT AND FORMATTING FUNCTIONS *
|
193 : |
|
|
***************************************************************************)
|
194 : |
|
|
(* convert a time value to a string, padded on the left to 8 characters *)
|
195 : |
|
|
(*
|
196 : |
|
|
fun timeToStr (TIME{sec, usec}) =
|
197 : |
|
|
let val tenMS = (usec + 5000) quot 10000
|
198 : |
|
|
val str = let val s = makestring tenMS
|
199 : |
|
|
in if (tenMS < 10) then ".0"^s else "."^s
|
200 : |
|
|
end
|
201 : |
|
|
val s = (makestring sec) ^ str
|
202 : |
|
|
in pad (s, 6)
|
203 : |
|
|
end
|
204 : |
|
|
*)
|
205 : |
|
|
val timeToStr = T.toString
|
206 : |
|
|
|
207 : |
|
|
(* convert an integer number of Kilobytes to a string *)
|
208 : |
|
|
fun allocStr n =
|
209 : |
|
|
let val n = if n > 10000 then n + 512 else n
|
210 : |
|
|
val tenth = Int.quot((10*(Int.rem(n,1024))),1024)
|
211 : |
|
|
val mb = Int.div(n,1024)
|
212 : |
|
|
in pad (concat[Int.toString mb, ".", Int.toString tenth],7)
|
213 : |
|
|
end
|
214 : |
|
|
|
215 : |
|
|
(* convert a integer to a time string, padded on the left to 8 characters *)
|
216 : |
|
|
fun IntToStr i =
|
217 : |
|
|
let val tenMS = Int.quot((i mod 1000),10)
|
218 : |
|
|
val sec = Int.quot(i, 1000)
|
219 : |
|
|
val str = let val s = Int.toString tenMS
|
220 : |
|
|
in if (tenMS < 10) then ".0"^s else "."^s
|
221 : |
|
|
end
|
222 : |
|
|
val s = (Int.toString sec) ^ str
|
223 : |
|
|
in pad (s, 6)
|
224 : |
|
|
end
|
225 : |
|
|
|
226 : |
|
|
(* output the performance data *)
|
227 : |
|
|
fun output (strm, (x1,x2,x3,x4,x5,x6)) =
|
228 : |
|
|
TextIO.output (strm, concat[" usr= ", IntToStr x1,
|
229 : |
|
|
", sys= ", IntToStr x2,
|
230 : |
|
|
", gc= ", IntToStr x3,
|
231 : |
|
|
", real= ", IntToStr x4,
|
232 : |
|
|
", alloc= ", allocStr x5,
|
233 : |
|
|
", space= ", allocStr x6,
|
234 : |
|
|
" \n"])
|
235 : |
|
|
|
236 : |
|
|
(* output the performance data for future latex use *)
|
237 : |
|
|
fun outputLatex(strm, fname, (x1,x2,x3,x4,x5,x6)) =
|
238 : |
|
|
TextIO.output (strm, concat[fname,
|
239 : |
|
|
"\t&",IntToStr x1,
|
240 : |
|
|
"\t&",IntToStr x2,
|
241 : |
|
|
"\t&",IntToStr x3,
|
242 : |
|
|
"\t&",IntToStr x4,
|
243 : |
|
|
"\t&",allocStr x5,
|
244 : |
|
|
"\t&",allocStr x6,
|
245 : |
|
|
"\t\\\\ \\hline \n"])
|
246 : |
|
|
|
247 : |
|
|
(* output the performance data for future jgraph use *)
|
248 : |
|
|
fun outputJgraph(strm, fname, (x1,x2,x3,x4,x5,x6)) =
|
249 : |
|
|
TextIO.output (strm, concat[fname,
|
250 : |
|
|
"\t",IntToStr x1,
|
251 : |
|
|
"\t",IntToStr x2,
|
252 : |
|
|
"\t",IntToStr x3,
|
253 : |
|
|
"\t",IntToStr x4,
|
254 : |
|
|
"\t",allocStr x5,
|
255 : |
|
|
"\t",allocStr x6,
|
256 : |
|
|
"\n"])
|
257 : |
|
|
|
258 : |
|
|
|
259 : |
|
|
(***************************************************************************
|
260 : |
|
|
* MAIN FUNCTIONS *
|
261 : |
|
|
***************************************************************************)
|
262 : |
|
|
fun timeComp fname = output(TextIO.stdOut, compileIt fname)
|
263 : |
|
|
fun timeRun doit = output(TextIO.stdOut, runIt(doit, numRep))
|
264 : |
|
|
fun timeIt doit = output(TextIO.stdOut, runIt(doit, 1))
|
265 : |
|
|
|
266 : |
|
|
fun timeCompF (outstrm, fname) = output(outstrm, compileIt fname)
|
267 : |
|
|
fun timeRunF (outstrm, doit) = output(outstrm, runIt(doit, numRep))
|
268 : |
|
|
|
269 : |
|
|
|
270 : |
|
|
fun timeCompK(outstrm, prop, fname) =
|
271 : |
|
|
output(outstrm, compileIt(fname))
|
272 : |
|
|
fun timeCompKLatex(outstrm, prop, fname) =
|
273 : |
|
|
outputLatex(outstrm, prop, compileIt(fname))
|
274 : |
|
|
fun timeCompKJgraph(outstrm, prop, fname) =
|
275 : |
|
|
outputJgraph(outstrm, prop, compileIt(fname))
|
276 : |
|
|
|
277 : |
|
|
fun timeRunK(outstrm, fname, k, doit) =
|
278 : |
|
|
output(outstrm, runItK(k,doit))
|
279 : |
|
|
fun timeRunKLatex(outstrm, fname, k, doit) =
|
280 : |
|
|
outputLatex(outstrm, fname, runItK(k,doit))
|
281 : |
|
|
fun timeRunKJgraph(outstrm, fname, k, doit) =
|
282 : |
|
|
outputJgraph(outstrm, fname, runItK(k,doit))
|
283 : |
|
|
|
284 : |
|
|
end (* toplevel local *)
|
285 : |
|
|
end (* structure Timing *)
|
286 : |
|
|
|