benchmark-log.ss
#lang scheme/base

(require
   (planet williams/science:3/science))

(provide
 run-name
 run-times
   
 read-benchmark-log
 add-run
 find-most-recent-run)
  
;; A benchmark log is a (listof run)

;; A run is (vector name description seconds (vectorof time) mean std-dev)

;; name is a string, the name of the test-case the timing is for

;; description is a string, describing the changes implemented in this run

;; seconds is an integer, the value of current-seconds at
;; the time the data was first written

;; time is an integer, the runtime of the test

;; mean is a number, the mean of the times

;; std-dev is a number, the standard deviation of the times

;; run-name : run -> string
(define (run-name run)
  (vector-ref run 0))

;; run-times : run -> (vectorof time)
(define (run-times run)
  (vector-ref run 3))

(define (read-benchmark-log file-name)
  (if (file-exists? file-name)
      (with-input-from-file file-name
        (lambda ()
          (read (current-input-port))))
      (begin
        (with-output-to-file file-name
          (lambda () (write null)))
        null)))

;; add-run : (U string path) (vectorof time) -> void
(define (add-run file-name name times)
  (let ([data (read-benchmark-log file-name)])
    (with-output-to-file file-name
      (lambda ()
        (write
         (cons
          (vector name "" (current-seconds) times (mean times) (standard-deviation times))
          data)))
      #:exists 'replace)))

;; find-most-recent-run : (U string path) string -> (U run #f)
(define (find-most-recent-run file-name name)
  (let ([log (read-benchmark-log file-name)])
    (findf
     (lambda (run)
       (string=? (run-name run) name))
     log)))