Skip to content

Commit 93b3ba3

Browse files
David, Mark Hstylewarning
David, Mark H
authored andcommitted
add cl-quil-benchmarking system quilc-perf for perf. benchmarking
This is part of issue "Investigate performance at 72-150 qubits #565". new modules: benchmarking/quilc-perf.lisp - primarily exports benchmark-nq function to get timings as nQ increases for various chip and program types. This also introduces a "chip preparation" step before running any benchmarks. This removes any overhead from running the first compile on a chip out of the first benchmark run. Currently, there is significant but not tremendous amount of initial overhead, but a PR under consideration might add significant additional preparation overhead, and these should not be be charged to the first run. benchmarking/quilc-mon-prof.lisp - builds on quilc-perf.lisp and is for monitoring and profiling, as opposed to simple benchmarks, and is a WIP of sorts in that, while it's been useful to run for probing and experimenting in a REPL, we ;; so far lack really good theory of operation and associated modes of ;; running. We hope with time to get there. Also, note that some of this is SBCL-only. Makefile - add targets to run benchmark-nq a couple of ways: `make benchmark-nq` calls benchmark-nq one time, and `make benchmark-nq-2x` calls it twice. The idea is to capture the sometimes significant jump in performance observed between a first and second run within the same Lisp environment, due to the effects of "warming", caching, and the like. cl-quil-benchmarking.asd - add new module quilc-perf and depend on 3 additional systems: metering, qvm-app, sb-sprof
1 parent b9a0eb0 commit 93b3ba3

File tree

5 files changed

+539
-24
lines changed

5 files changed

+539
-24
lines changed

Makefile

+12-1
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,24 @@ test-ccl:
147147
###############################################################################
148148
# BENCHMARKS
149149
###############################################################################
150-
.PHONY: benchmark-qasm
150+
.PHONY: benchmark-qasm benchmark-nq benchmark-nq-2x
151151

152152
benchmark-qasm:
153153
$(QUICKLISP) \
154154
--eval "(ql:quickload :cl-quil-benchmarking)" \
155155
--eval "(cl-quil-benchmarking::benchmark-qasm-suite)"
156156

157+
benchmark-nq:
158+
$(QUICKLISP) \
159+
--eval "(ql:quickload :cl-quil-benchmarking)" \
160+
--eval "(cl-quil-benchmarking::benchmark-nq)"
161+
162+
benchmark-nq-2x:
163+
$(QUICKLISP) \
164+
--eval "(ql:quickload :cl-quil-benchmarking)" \
165+
--eval "(cl-quil-benchmarking::benchmark-nq)" \
166+
--eval "(cl-quil-benchmarking::benchmark-nq)"
167+
157168
###############################################################################
158169
# CLEAN
159170
###############################################################################

benchmarking/qasm-benchmarks.lisp

+29-23
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@
6060
:do (quil::append-instruction-to-lschedule lschedule instr)
6161
:finally (return (quil::lscheduler-calculate-depth lschedule)))))
6262

63-
(defun benchmark-qasm-suite (&key (timeout 30))
63+
(defun benchmark-qasm-suite (&key (timeout 30) named)
64+
"Run benchmarks from qasm suite. If NAMED is not nil, the specified test(s) will be the ONLY one(s) run; otherwise, all the tests are run. NAMED should be a short name (as shown in the output) of a test, either as a symbol or string, or a list thereof (i.e., matching mutiple tests), to be compared using string-equal. TIMEOUT specifies a timeout in seconds, defaulting to 30 seconds."
6465
(let ((timed-out nil))
6566
(flet ((print-rule ()
6667
(format t "+------------------+----------+-------+----------+~%")))
@@ -73,28 +74,33 @@
7374
(quil::*addresser-use-1q-queues* t)
7475
(quil::*safe-include-directory* (asdf:system-relative-pathname :cl-quil "tests/qasm-files/")))
7576
(dolist (file (qasm-test-files))
76-
(format t "| ~Va " 16 (trim-long-string (pathname-name file) 16))
77-
(finish-output)
78-
(handler-case
79-
(let ((text (alexandria:read-file-into-string file)))
80-
(tg:gc :full t)
81-
(bordeaux-threads:with-timeout (timeout)
82-
(with-stopwatch elapsed-time
83-
(multiple-value-bind (cpp swaps)
84-
(quil::compiler-hook (quil::parse text
85-
:originating-file file)
86-
chip
87-
:protoquil t
88-
:destructive t)
89-
(format t "| ~Vf | ~Vd | ~Vd |~%"
90-
8 (/ elapsed-time 1000)
91-
5 swaps
92-
8 (calculate-multiqubit-gate-depth (parsed-program-executable-code cpp)))))))
93-
(bt:timeout ()
94-
(format t "| ~8,'>d | ????? | ???????? |~%"
95-
timeout)
96-
(push (pathname-name file) timed-out)))
97-
(finish-output)))
77+
(let ((short-name (trim-long-string (pathname-name file) 16)))
78+
(when (or (null named)
79+
(if (atom named)
80+
(string-equal named short-name)
81+
(member short-name named :test 'string-equal)))
82+
(format t "| ~Va " 16 short-name)
83+
(finish-output)
84+
(handler-case
85+
(let ((text (alexandria:read-file-into-string file)))
86+
(tg:gc :full t)
87+
(bordeaux-threads:with-timeout (timeout)
88+
(with-stopwatch elapsed-time
89+
(multiple-value-bind (cpp swaps)
90+
(quil::compiler-hook (quil::parse text
91+
:originating-file file)
92+
chip
93+
:protoquil t
94+
:destructive t)
95+
(format t "| ~Vf | ~Vd | ~Vd |~%"
96+
8 (/ elapsed-time 1000)
97+
5 swaps
98+
8 (calculate-multiqubit-gate-depth (parsed-program-executable-code cpp)))))))
99+
(bt:timeout ()
100+
(format t "| ~8,'>d | ????? | ???????? |~%"
101+
timeout)
102+
(push (pathname-name file) timed-out)))
103+
(finish-output)))))
98104
(print-rule)
99105
(terpri)
100106
(when timed-out

benchmarking/quilc-mon-prof.lisp

+186
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
;;;; quilc-mon-prof.lisp
2+
;;;;
3+
;;;; Author: Mark David
4+
5+
(in-package #:cl-quil-benchmarking)
6+
7+
8+
9+
;;;; Monitoring and Profiling
10+
11+
;; This builds on quilc-perf.lisp and is for monitoring and profiling,
12+
;; as opposed to simple benchmarks, and is a WIP in that we have not
13+
;; established a makefile entry to run this. That is because, while
14+
;; it's been useful to run for probing and experimenting in a REPL, we
15+
;; so far lack really good theory of operation and associated modes of
16+
;; running. We hope with time to get there.
17+
18+
19+
(defparameter *monitor-types*
20+
'(:mon #+sbcl :sb-sprof))
21+
22+
(defun monitor-run (program-type chip-type nq repeats monitor
23+
&optional report-type sample-interval)
24+
"Do REPEATS perf runs for PROGRAM-TYPE and CHIP-TYPE (as documented
25+
at the top of QUILC-PERF module) using the specified MONITOR, which
26+
must be one of those in the list *monitor-types*. Optional args
27+
REPORT-TYPE and SAMPLE-INTERVAL are only relevant when MONITOR is
28+
:SB-SPROF in which case REPORT-TYPE is passed as the same-named arg
29+
to SB-SPROF:REPORT, and SAMPLE-INTERVAL is passed as the same-named
30+
arg to SB-SPROF:START-PROFILING. Note as well that for :SB-SPROF
31+
monitor, only the current thread is profiled. This returns no
32+
useful value. It's just run in order to get output from the
33+
monitor."
34+
(when (not (member monitor *monitor-types*))
35+
(unless (null monitor) ; if so, just silently default with no warning
36+
(warn "unrecognized monitor, should be one of ~s; using ~s"
37+
*monitor-types* (first *monitor-types*)))
38+
(setq monitor (first *monitor-types*)))
39+
(let (program chip)
40+
(format t "~2%****~%Building ~a program (nQ = ~d)... " program-type nq)
41+
(setq program (get-or-build-benchmark-program nq program-type))
42+
(format t "DONE (~a).~%" program)
43+
(format t "Building ~a chip (nQ = ~d)... " chip-type nq)
44+
(setq chip (get-or-build-benchmark-chip nq chip-type))
45+
(format t "DONE (~a).~%" chip)
46+
(format t "** Doing ~d run~p... **~%" repeats repeats)
47+
(let* ((*package* (find-package :cl-quil))
48+
(thunk
49+
#'(lambda ()
50+
(dotimes (i repeats)
51+
(prepare-environment-for-perf-run)
52+
(format t "#~d: Compiling program/chip ... " i)
53+
(let* ((t1 (get-internal-run-time))
54+
(t2 (progn (do-one-quilc-perf-run program chip)
55+
(get-internal-run-time)))
56+
(elapsed-time (- t2 t1)))
57+
(format
58+
t
59+
"DONE (~,2f sec compiler, ~2df sec real time w/overhead).~%"
60+
;; -- 2nd timing is real time, as opposed to
61+
;; internal run time. 'Overhead' is primarily GC +
62+
;; warming.
63+
(internal-time-to-seconds elapsed-time)
64+
(internal-time-to-seconds (- t2 t1))))))))
65+
(ecase monitor
66+
(:mon (mon:monitor-form (funcall thunk)))
67+
#+sbcl
68+
(:sb-sprof
69+
(progn
70+
(sb-sprof:reset)
71+
(sb-sprof:start-profiling
72+
:sample-interval (or sample-interval 0.005) ; default = 0.01
73+
:threads (list sb-thread:*current-thread*))
74+
(funcall thunk)
75+
(sb-sprof:report
76+
:min-percent 3
77+
:type (ecase report-type
78+
((nil :flat) :flat)
79+
(:graph :graph)))))))
80+
(format t "** DONE with ~d runs. **~%" repeats)))
81+
82+
(defun do-monitor-runs (&key start step end
83+
repeats monitor
84+
report-type sam sample-interval)
85+
(or repeats (setq repeats 3))
86+
(loop :for nq := (or start 10)
87+
:then (+ nq (or step 10))
88+
:when (> nq (or end start))
89+
:do (return)
90+
:do (format t "~%**** NQ: ~d ****~%" nq)
91+
(loop :for program-type :in *benchmark-program-types*
92+
:do (loop :for chip-type :in *benchmark-chip-connectedness-types*
93+
:do (monitor-run
94+
program-type chip-type nq repeats monitor
95+
report-type sample-interval)))))
96+
97+
;; Try this on SBCL: (do-monitor-runs :monitor ':sb-sprof)
98+
99+
100+
101+
102+
(defun do-one (nq)
103+
(do-one-nq-program-chip nq :hadamard :fully-connected))
104+
105+
(defparameter *min-sb-sprof-perf-pct* 1)
106+
107+
(defun do-one-nq-program-chip (nq program-type chip-type)
108+
(let ((program (build-benchmark-program nq :hadamard))
109+
(chip (build-benchmark-chip nq :fully-connected)))
110+
(sb-sprof:reset)
111+
(tg:gc :full t)
112+
(sb-sprof:start-profiling :threads (list sb-thread:*current-thread*))
113+
(time (benchmark-one-quilc-perf-run program chip))
114+
(sb-sprof:stop-profiling)
115+
(sb-sprof:report :type :graph :min-percent *min-sb-sprof-perf-pct*)
116+
(sb-sprof:report :type :flat :min-percent *min-sb-sprof-perf-pct*)))
117+
118+
(defun do-one-mon (nq &optional program-type)
119+
(let ((program (build-benchmark-program nq (or program-type :hadamard)))
120+
(chip (build-benchmark-chip nq :fully-connected)))
121+
(tg:gc :full t)
122+
(sb-sprof:with-profiling (:max-samples 1000
123+
:report :flat
124+
:loop nil
125+
126+
:reset t
127+
:sample-interval 0.01) ; default .01
128+
(benchmark-one-quilc-perf-run program chip))))
129+
130+
131+
132+
;;;; SB-SPROF Runs of Various Flavors
133+
134+
(defparameter *default-sb-sprof-run-nqs*
135+
'(20 50 80 110)
136+
"Default list of nQ values for running various SB-SPROF calls below.")
137+
138+
(defun sb-sprof-run ()
139+
(loop :for nq :in *default-sb-sprof-run-nqs*
140+
:do (do-monitor-runs
141+
:start nq
142+
:monitor :sb-sprof
143+
:repeats 1
144+
:report-type :flat)))
145+
146+
(defun sb-sprof-graph ()
147+
(loop :for nq :in *default-sb-sprof-run-nqs*
148+
:do (do-monitor-runs
149+
:start nq
150+
:monitor :sb-sprof
151+
:repeats 1
152+
:report-type :flat)))
153+
154+
(defun sb-sprof-run-high-sample ()
155+
(loop :for nq :in *default-sb-sprof-run-nqs*
156+
:do (do-monitor-runs
157+
:start nq
158+
:monitor :sb-sprof
159+
:repeats 1
160+
161+
:sample-interval 0.001 ; our default: 0.005
162+
:report-type :flat)))
163+
164+
(defun sb-sprof-run-high-sample-plus-graph ()
165+
(loop :for nq :in *default-sb-sprof-run-nqs*
166+
:do (do-monitor-runs
167+
:start nq
168+
:monitor :sb-sprof
169+
:repeats 1
170+
171+
:sample-interval 0.001 ; our default: 0.005
172+
:report-type :graph))) ; our default: :flat
173+
174+
(defun sb-sprof-run-mon ()
175+
(loop :for nq :in *default-sb-sprof-run-nqs*
176+
:do (do-monitor-runs
177+
:start nq
178+
:monitor :mon
179+
:repeats 1
180+
181+
:sample-interval 0.001 ; our default: 0.005
182+
:report-type :graph))) ; our default: :flat
183+
184+
(defun one-monitor-run-bill-linear (nq)
185+
(monitor-run :bell :linear nq 1 :mon :flat .0001))
186+

0 commit comments

Comments
 (0)