;;; -*- Mode:LISP; Base:10; Readtable:CL -*- ;;; dependencies: dj:jrm;custom ;;; Tools for benchmarking. (defun measure-statistic (statistic-getter thunk statistics-receiver) (let ((temp (funcall statistic-getter))) (funcall thunk) (funcall statistics-receiver temp (funcall statistic-getter)))) (defstruct (tester (:conc-name "TESTER-") (:constructor make-tester (init-control run-control init-test run-test report-test))) init-control run-control init-test run-test report-test) (defun elapsed-time-tester (time-gatherer) (let ((control-time 0) (test-time 0)) (labels ( (run-timer (thunk receiver) (measure-statistic time-gatherer thunk receiver)) (run-control (thunk) (run-timer thunk #'(lambda (start end) (setq control-time (- end start))))) (run-test (thunk) (run-timer thunk #'(lambda (start end) (setq test-time (- end start))))) (report (stream) (format stream "~&Control took ~5,2F seconds. Run took ~5,2F seconds." (/ control-time 1000000.0) (/ test-time 1000000.0)))) (make-tester #'values #'run-control #'values #'run-test #'report)))) (defun make-total-time-tester (elapsed-time-tester #'time:microsecond-time)) (defun make-disk-time-tester (elapsed-time-tester #'(lambda () (read-meter si:%disk-wait-time)))) (defun compare-tests (init-thunk control-thunk test-environment-setup test-thunk test-list iterations) (labels ( (do-test (thunk) #'(lambda () (dotimes (count iterations) (funcall thunk)))) (initialize-testers (tester-init) (dolist (tester test-list) (funcall (funcall tester-init tester)))) (run-testers (tester-to-run tester-list thunk) (check-split-list tester-list thunk #'(lambda (tester more-testers) (funcall (funcall tester-to-run tester) #'(lambda () (run-testers tester-to-run more-testers thunk)))))) (report () (dolist (tester test-list) (funcall (tester-report-test tester) terminal-io))) ) (funcall init-thunk) ;;; First, run the control thunk to get a reasonable paging environment. (funcall (do-test control-thunk)) ;;; Now, actually test it. (initialize-testers #'tester-init-control) (run-testers #'tester-run-control test-list (do-test control-thunk)) (funcall test-environment-setup #'(lambda () (funcall init-thunk) ;; Again, one go through to minimize effects of paging. (funcall (do-test test-thunk)) ;; The actual test (initialize-testers #'tester-init-test) (run-testers #'tester-run-test test-list (do-test test-thunk)))) (report))) (defun thunkify-application (function arglist) #'(lambda () (apply function arglist)))