use defsubst
[bpt/guile.git] / gc-benchmarks / run-benchmark.scm
CommitLineData
69ecc0ba
LC
1#!/bin/sh
2# -*- Scheme -*-
3exec ${GUILE-guile} -q -l "$0" \
4 -c '(apply main (cdr (command-line)))' \
5 --benchmark-dir="$(dirname $0)" "$@"
6!#
b529eb57 7;;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
69ecc0ba 8;;;
53befeb7
NJ
9;;; This program is free software; you can redistribute it and/or
10;;; modify it under the terms of the GNU Lesser General Public License
11;;; as published by the Free Software Foundation; either version 3, or
12;;; (at your option) any later version.
69ecc0ba
LC
13;;;
14;;; This program is distributed in the hope that it will be useful,
15;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53befeb7 17;;; GNU Lesser General Public License for more details.
69ecc0ba 18;;;
53befeb7
NJ
19;;; You should have received a copy of the GNU Lesser General Public
20;;; License along with this software; see the file COPYING.LESSER. If
21;;; not, write to the Free Software Foundation, Inc., 51 Franklin
22;;; Street, Fifth Floor, Boston, MA 02110-1301 USA
69ecc0ba
LC
23
24(use-modules (ice-9 rdelim)
25 (ice-9 popen)
26 (ice-9 regex)
27 (ice-9 format)
b529eb57 28 (ice-9 pretty-print)
69ecc0ba
LC
29 (srfi srfi-1)
30 (srfi srfi-37))
31
32\f
33;;;
34;;; Running Guile.
35;;;
36
37(define (run-reference-guile env bench-dir profile-opts bench)
38 "Run the ``mainstream'' Guile, i.e., Guile 1.9 with its own GC."
39 (open-input-pipe (string-append
40 env " "
41 bench-dir "/gc-profile.scm " profile-opts
42 " \"" bench "\"")))
43
44(define (run-bdwgc-guile env bench-dir profile-opts options bench)
45 "Run the Guile port to the Boehm-Demers-Weiser GC (BDW-GC)."
46 (let ((fsd (assoc-ref options 'free-space-divisor)))
47 (open-input-pipe (string-append env " "
48 "GC_FREE_SPACE_DIVISOR="
49 (number->string fsd)
50
51 (if (or (assoc-ref options 'incremental?)
52 (assoc-ref options 'generational?))
53 " GC_ENABLE_INCREMENTAL=yes"
54 "")
55 (if (assoc-ref options 'generational?)
56 " GC_PAUSE_TIME_TARGET=999999"
57 "")
58 (if (assoc-ref options 'parallel?)
59 "" ;; let it choose the number of procs
60 " GC_MARKERS=1")
61 " "
62 bench-dir "/gc-profile.scm " profile-opts
63 " \"" bench "\""))))
64
65\f
66;;;
67;;; Extracting performance results.
68;;;
69
70(define (grep regexp input)
71 "Read line by line from the @var{input} port and return all matches for
72@var{regexp}."
73 (let ((regexp (if (string? regexp) (make-regexp regexp) regexp)))
74 (with-input-from-port input
75 (lambda ()
76 (let loop ((line (read-line))
77 (result '()))
78 (format #t "> ~A~%" line)
79 (if (eof-object? line)
80 (reverse result)
81 (cond ((regexp-exec regexp line)
82 =>
83 (lambda (match)
84 (loop (read-line)
85 (cons match result))))
86 (else
87 (loop (read-line) result)))))))))
88
89(define (parse-result benchmark-output)
90 (let ((result (grep "^(execution time|heap size):[[:blank:]]+([0-9.]+)"
91 benchmark-output)))
92 (fold (lambda (match result)
93 (cond ((equal? (match:substring match 1) "execution time")
94 (cons (cons 'execution-time
95 (string->number (match:substring match 2)))
96 result))
97 ((equal? (match:substring match 1) "heap size")
98 (cons (cons 'heap-size
99 (string->number (match:substring match 2)))
100 result))
101 (else
102 result)))
103 '()
104 result)))
105
106(define (pretty-print-result benchmark reference bdwgc)
b529eb57
LC
107 (define ref-heap (assoc-ref reference 'heap-size))
108 (define ref-time (assoc-ref reference 'execution-time))
109
110 (define (distance x1 y1 x2 y2)
0588379a
LC
111 ;; Return the distance between (X1,Y1) and (X2,Y2). Y is the heap size,
112 ;; in MiB and X is the execution time in seconds.
b529eb57
LC
113 (let ((y1 (/ y1 (expt 2 20)))
114 (y2 (/ y2 (expt 2 20))))
115 (sqrt (+ (expt (- y1 y2) 2)
116 (expt (- x1 x2) 2)))))
117
118 (define (score time heap)
0588379a 119 ;; Return a score lower than +1.0. The score is positive if the
b529eb57
LC
120 ;; distance to the origin of (TIME,HEAP) is smaller than that of
121 ;; (REF-TIME,REF-HEAP), negative otherwise.
122
123 ;; heap ^ .
124 ;; size | . worse
125 ;; | . [-]
126 ;; | .
0588379a 127 ;; | . . . .ref. . . .
b529eb57
LC
128 ;; | .
129 ;; | [+] .
130 ;; | better .
131 ;; 0 +-------------------->
0588379a 132 ;; exec. time
b529eb57
LC
133
134 (let ((ref-dist (distance ref-time ref-heap 0 0))
135 (dist (distance time heap 0 0)))
136 (/ (- ref-dist dist) ref-dist)))
137
138 (define (score-string time heap)
139 ;; Return a string denoting a bar to illustrate the score of (TIME,HEAP)
140 ;; relative to (REF-TIME,REF-HEAP).
141 (define %max-width 15)
142
143 (let ((s (score time heap)))
144 (make-string (inexact->exact (round (* (if (< s 0.0) (- s) s)
145 %max-width)))
146 (if (< s 0.0)
147 #\-
148 #\+))))
149
69ecc0ba 150 (define (print-line name result ref?)
b529eb57
LC
151 (let ((name (string-pad-right name 23))
152 (time (assoc-ref result 'execution-time))
153 (heap (assoc-ref result 'heap-size)))
154 (format #t "~a ~6,2f (~,2fx) ~7,3f (~,2fx)~A~%"
69ecc0ba 155 name
b529eb57 156 (/ heap (expt 2.0 20)) (/ heap ref-heap 1.0)
69ecc0ba 157 time (/ time ref-time 1.0)
b529eb57
LC
158 (if (not ref?)
159 (string-append " "
160 (score-string time heap))
69ecc0ba
LC
161 ""))))
162
163 (format #t "benchmark: `~a'~%" benchmark)
b529eb57 164 (format #t " heap size (MiB) execution time (s.)~%")
69ecc0ba
LC
165 (print-line "Guile" reference #t)
166 (for-each (lambda (bdwgc)
167 (let ((name (format #f "BDW-GC, FSD=~a~a"
168 (assoc-ref bdwgc 'free-space-divisor)
169 (cond ((assoc-ref bdwgc 'incremental?)
170 " incr.")
171 ((assoc-ref bdwgc 'generational?)
172 " gene.")
173 ((assoc-ref bdwgc 'parallel?)
174 " paral.")
175 (else "")))))
176 (print-line name bdwgc #f)))
177 bdwgc))
178
b529eb57
LC
179(define (print-raw-result benchmark reference bdwgc)
180 (pretty-print `(,benchmark
181 (reference . ,reference)
182 (bdw-gc . ,bdwgc))))
183
184
69ecc0ba
LC
185\f
186;;;
187;;; Option processing.
188;;;
189
190(define %options
191 (list (option '(#\h "help") #f #f
192 (lambda args
193 (show-help)
194 (exit 0)))
195 (option '(#\r "reference") #t #f
196 (lambda (opt name arg result)
197 (alist-cons 'reference-environment arg
198 (alist-delete 'reference-environment result
199 eq?))))
200 (option '(#\b "bdw-gc") #t #f
201 (lambda (opt name arg result)
202 (alist-cons 'bdwgc-environment arg
203 (alist-delete 'bdwgc-environment result
204 eq?))))
205 (option '(#\d "benchmark-dir") #t #f
206 (lambda (opt name arg result)
207 (alist-cons 'benchmark-directory arg
208 (alist-delete 'benchmark-directory result
209 eq?))))
210 (option '(#\p "profile-options") #t #f
211 (lambda (opt name arg result)
212 (let ((opts (assoc-ref result 'profile-options)))
213 (alist-cons 'profile-options
214 (string-append opts " " arg)
215 (alist-delete 'profile-options result
216 eq?)))))
217 (option '(#\l "log-file") #t #f
218 (lambda (opt name arg result)
219 (alist-cons 'log-port (open-output-file arg)
220 (alist-delete 'log-port result
b529eb57
LC
221 eq?))))
222 (option '("raw") #f #f
223 (lambda (opt name arg result)
224 (alist-cons 'printer print-raw-result
225 (alist-delete 'printer result eq?))))
226 (option '("load-results") #f #f
227 (lambda (opt name arg result)
228 (alist-cons 'load-results? #t result)))))
69ecc0ba
LC
229
230(define %default-options
231 `((reference-environment . "GUILE=guile")
232 (benchmark-directory . "./gc-benchmarks")
233 (log-port . ,(current-output-port))
bf4200ca 234 (profile-options . "")
b529eb57
LC
235 (input . ())
236 (printer . ,pretty-print-result)))
69ecc0ba
LC
237
238(define (show-help)
239 (format #t "Usage: run-benchmark [OPTIONS] BENCHMARKS...
240Run BENCHMARKS (a list of Scheme files) and display a performance
241comparison of standard Guile (1.9) and the BDW-GC-based Guile.
242
243 -h, --help Show this help message
244
245 -r, --reference=ENV
246 -b, --bdw-gc=ENV
247 Use ENV as the environment necessary to run the
248 \"reference\" Guile (1.9) or the BDW-GC-based Guile,
249 respectively. At a minimum, ENV should define the
250 `GUILE' environment variable. For example:
251
252 --reference='GUILE=/foo/bar/guile LD_LIBRARY_PATH=/foo'
253
254 -p, --profile-options=OPTS
255 Pass OPTS as additional options for `gc-profile.scm'.
256 -l, --log-file=FILE
257 Save output to FILE instead of the standard output.
b529eb57
LC
258
259 --raw Write benchmark results in raw (s-exp) format.
260 --load-results
261 Load raw (s-exp) results instead of actually running
262 the benchmarks.
263
69ecc0ba
LC
264 -d, --benchmark-dir=DIR
265 Use DIR as the GC benchmark directory where `gc-profile.scm'
266 lives (it is automatically determined by default).
267
268Report bugs to <bug-guile@gnu.org>.~%"))
269
270(define (parse-args args)
271 (define (leave fmt . args)
272 (apply format (current-error-port) (string-append fmt "~%") args)
273 (exit 1))
274
275 (args-fold args %options
276 (lambda (opt name arg result)
277 (leave "~A: unrecognized option" opt))
278 (lambda (file result)
279 (let ((files (or (assoc-ref result 'input) '())))
280 (alist-cons 'input (cons file files)
281 (alist-delete 'input result eq?))))
282 %default-options))
283
284\f
285;;;
286;;; The main program.
287;;;
288
289(define (main . args)
290 (let* ((args (parse-args args))
291 (benchmark-files (assoc-ref args 'input)))
292
293 (let* ((log (assoc-ref args 'log-port))
294 (bench-dir (assoc-ref args 'benchmark-directory))
295 (ref-env (assoc-ref args 'reference-environment))
296 (bdwgc-env (or (assoc-ref args 'bdwgc-environment)
297 (string-append "GUILE=" bench-dir
0b6d8fdc 298 "/../meta/guile")))
b529eb57
LC
299 (prof-opts (assoc-ref args 'profile-options))
300 (print (assoc-ref args 'printer)))
301 (define (run benchmark)
302 (let ((ref (parse-result (run-reference-guile ref-env
303 bench-dir
304 prof-opts
305 benchmark)))
306 (bdwgc (map (lambda (fsd incremental?
307 generational? parallel?)
308 (let ((opts
309 (list
310 (cons 'free-space-divisor fsd)
311 (cons 'incremental? incremental?)
312 (cons 'generational? generational?)
313 (cons 'parallel? parallel?))))
314 (append opts
315 (parse-result
316 (run-bdwgc-guile bdwgc-env
317 bench-dir
318 prof-opts
319 opts
320 benchmark)))))
321 '( 3 6 9 3 3)
322 '(#f #f #f #t #f) ;; incremental
323 '(#f #f #f #f #t) ;; generational
324 '(#f #f #f #f #f)))) ;; parallel
325 `(,benchmark
326 (reference . ,ref)
327 (bdw-gc . ,bdwgc))))
328
329 (define (load-results file)
330 (with-input-from-file file
331 (lambda ()
332 (let loop ((results '()) (o (read)))
333 (if (eof-object? o)
334 (reverse results)
335 (loop (cons o results)
336 (read)))))))
337
338 (for-each (lambda (result)
339 (let ((benchmark (car result))
340 (ref (assoc-ref (cdr result) 'reference))
341 (bdwgc (assoc-ref (cdr result) 'bdw-gc)))
69ecc0ba
LC
342 (with-output-to-port log
343 (lambda ()
b529eb57 344 (print benchmark ref bdwgc)
69ecc0ba
LC
345 (newline)
346 (force-output)))))
b529eb57
LC
347 (if (assoc-ref args 'load-results?)
348 (append-map load-results benchmark-files)
349 (map run benchmark-files))))))