; Graphical display of benchmark results. ; ; FIXME: This is awful code. ; Given a list of summaries in the representation ; produced by decode-summary, and a filename or ; output port, writes ASCII bar graphs to the file ; or port. (define (graph-benchmarks summaries out) (define (bad-arguments) (error "Bad arguments to graph-benchmarks" in)) (cond ((string? out) (call-with-output-file out (lambda (out) (graph-benchmarks summaries out)))) ((output-port? out) (graph-benchmarks-to-port summaries out)) (else (bad-arguments)))) (define (graph-benchmarks-to-port summaries out) (let* ((results (map summary:timings summaries)) (benchmark-names (map timing:benchmark (car results)))) (for-each (lambda (name) (graph-benchmark-to-port name summaries out)) benchmark-names))) (define width:system 8) (define width:timing 8) (define width:gap 2) (define width:bar 60) (define width:total (+ width:system width:timing width:gap width:bar)) (define anchor1 "") (define anchor3 "") (define (graph-benchmark-to-port name summaries out) ; Strips -r6rs-fixflo and similar suffixes from system names. (define (short-name system) (let* ((rchars (reverse (string->list system))) (probe (memv #\- rchars))) (if probe (short-name (list->string (reverse (cdr probe)))) system))) (display (make-string (- width:total (string-length (symbol->string name))) #\space) out) (display anchor1 out) (display name out) (display anchor2 out) (display name out) (display anchor3 out) (newline out) (let* ((systems (map summary:system summaries)) (systems (map short-name systems)) (results (map summary:timings summaries)) (timings (map (lambda (x) (assq name x)) results)) (best (apply min (map timing:real (filter (lambda (x) x) timings))))) (for-each (lambda (system timing) (if (list? timing) (graph-system system (timing:real timing) best out) (graph-system system 0 best out))) systems timings))) (define graph-system:args '()) (define graph-system:bar1 "") (define graph-system:bar3 "") (define graph-system:colors '(("Larceny" "800000") ("Bigloo" "000080") ("Chez" "004040") ("Chicken" "a06000") ("Gambit" "400060") ("MIT" "2000c0") ("MzScheme" "008020") ("Petite" "004080") ("Scheme48" "600040"))) ; Returns a nice color for certain popular systems, ; or returns black. (define (system-color system) (let ((probe (assoc system graph-system:colors))) (if probe (cadr probe) "000000"))) (define (graph-system system timing best out) (if (and (number? timing) (positive? timing)) (let* ((relative (/ best timing)) (color (system-color system))) (left-justify system width:system out) (right-justify (msec->seconds timing) width:timing out) (left-justify "" width:gap out) (display graph-system:bar1 out) (display color out) (display graph-system:bar2 out) (display (make-string (inexact->exact (round (* relative width:bar))) #\space) out) (display graph-system:bar3 out) (newline out)) (begin (left-justify system width:system out) (newline out)))) ; Given a timing in milliseconds, ; returns the timing in seconds, ; as a string rounded to two decimal places. (define (msec->seconds t) (let* ((hundredths (inexact->exact (round (/ t 10.0)))) (s (number->string hundredths)) (n (string-length s))) (cond ((>= n 2) (string-append (substring s 0 (- n 2)) "." (substring s (- n 2) n))) (else (string-append ".0" s))))) ; Given a summary and a list of summaries, ; returns a list of relative performance (0.0 to 1.0) ; for every benchmark in the summary. (define (relative-performance summary summaries) (let* ((timings (summary:timings summary)) (timings (filter (lambda (t) (let ((realtime (timing:real t))) (and (number? realtime) (positive? realtime)))) timings)) (other-results (map summary:timings summaries))) (map (lambda (t) (let* ((name (timing:benchmark t)) (timings (map (lambda (x) (assq name x)) other-results)) (best (apply min (map timing:real (filter (lambda (x) x) timings))))) (/ best (timing:real t)))) timings))) ; Given a list of positive numbers, ; returns its geometric mean. (define (geometric-mean xs) (expt (apply * xs) (/ 1 (length xs)))) ; Given a list of summaries, returns a list of summaries ; augmented by the geometric mean over all benchmarks. (define (summaries-with-geometric-means summaries) (define name (string->symbol "geometricMean")) (map (lambda (summary) (define mean (* 1000 (/ (geometric-mean (relative-performance summary summaries))))) (make-summary (summary:system summary) (summary:hostetc summary) (cons (make-timing name mean mean 0) (summary:timings summary)))) summaries))