2 (asdf:oos
'asdf
:load-op
'#:cl-glfw
)
4 ;; have to rename this class to thread-signal because it's a built-in typename in lisp
5 (defclass thread-signal
()
6 ((cond :initform
(glfw:create-cond
) :reader signal-cond
) ; have to rename this reader to signal-cond because it's a built-in macro
7 (mutex :initform
(glfw:create-mutex
) :reader mutex
)
8 (flag :initform nil
:accessor flag
)))
10 (defmethod initialize-instance :after
((s thread-signal
) &key
)
11 (format t
"Created thread-signal with cond ~a and mutex ~a~%" (signal-cond s
) (mutex s
)))
13 (defun kill-signal (s)
14 (declare (type thread-signal s
))
15 (glfw:destroy-mutex
(mutex s
))
16 (glfw:destroy-cond
(signal-cond s
))
19 (defun wait-signal (s)
20 (declare (type thread-signal s
))
21 (glfw:with-lock-mutex
(mutex s
)
22 (loop while
(not (flag s
)) do
23 (glfw:wait-cond
(signal-cond s
) (mutex s
) glfw
:+infinity
+))
27 (declare (type thread-signal s
))
28 (glfw:with-lock-mutex
(mutex s
)
30 (glfw:signal-cond
(signal-cond s
)))
34 (error "Could not glfw:init"))
36 (format t
"Multithreading benchmarking program
37 -----------------------------------
39 This program consists of two tests. In the first test two threads are created,
40 which continously signal/wait each other. This forces the execution to
41 alternate between the two threads, and gives a measure of the thread
42 synchronization granularity. In the second test, the main thread is repeatedly
43 put to sleep for a very short interval using glfwSleep. The average sleep time
44 is measured, which tells the minimum supported sleep interval.
51 (format t
"Number of CPUs: ~d~%~%" (glfw:get-number-of-processors
))
53 (defparameter *done-mutex
* nil
)
54 (defparameter *thread-done
* nil
)
55 (defparameter *goto-a
* nil
)
56 (defparameter *goto-b
* nil
)
57 (defparameter *goto-a-count
* 0)
58 (defparameter *goto-b-count
* 0)
59 (defparameter *done-count
* 0)
60 (defparameter *max-count
* 10000)
63 (declare (optimize (debug 3) (safety 3) (speed 0) (compilation-speed 0)))
64 (setf *done-mutex
* (glfw:create-mutex
)
65 *thread-done
* (glfw:create-cond
)
66 *goto-a
* (make-instance 'thread-signal
)
67 *goto-b
* (make-instance 'thread-signal
)
73 (declare (optimize (debug 3) (safety 3) (speed 0) (compilation-speed 0)))
74 (glfw:destroy-mutex
*done-mutex
*)
75 (glfw:destroy-cond
*thread-done
*)
76 (kill-signal *goto-a
*)
77 (kill-signal *goto-b
*))
80 (defmacro make-thread-callback
(name signal-var other-signal-var count-var
)
81 `(cffi:defcallback
,name
:void
((arg :pointer
))
82 (declare (ignore arg
))
84 ((>= ,count-var
*max-count
*))
86 (set-signal ,other-signal-var
)
87 (wait-signal ,signal-var
))
88 (set-signal ,other-signal-var
)
89 (glfw:with-lock-mutex
*done-mutex
*
91 (glfw:signal-cond
*thread-done
*)))
93 (make-thread-callback thread-a-fun
*goto-a
* *goto-b
* *goto-a-count
*)
94 (make-thread-callback thread-b-fun
*goto-b
* *goto-a
* *goto-b-count
*)
97 (declare (optimize (debug 3) (safety 3) (speed 0) (compilation-speed 0)))
98 (sb-ext::without-gcing
99 (let ((thread-a (glfw:create-thread
(cffi:callback thread-a-fun
) (cffi:null-pointer
)))
100 (thread-b (glfw:create-thread
(cffi:callback thread-b-fun
) (cffi:null-pointer
))))
102 (when (or (minusp thread-a
) (minusp thread-b
))
103 (format t
"One of the threads failed~%")
104 (glfw:with-lock-mutex
*done-mutex
*
105 (setf *done-count
* 2)))
107 (let ((t1 (glfw:get-time
)))
108 (glfw:with-lock-mutex
*done-mutex
*
109 (loop until
(= *done-count
* 2)
110 do
(glfw:wait-cond
*thread-done
* *done-mutex
* glfw
:+infinity
+)))
111 (let* ((t2 (glfw:get-time
))
112 (csps (/ (+ *goto-a-count
* *goto-b-count
*)
114 (format t
"Test 1: ~,0f context switches / second (~,3f us/switch)~%" csps
(/ 1000000 csps
))))
116 (format t
"waiting for thread a to finish completely~%")
117 (glfw:wait-thread thread-a glfw
:+wait
+)
118 (format t
"waiting for thread b to finish completely~%")
119 (glfw:wait-thread thread-b glfw
:+wait
+)
120 (format t
"finished waiting~%"))))
123 (let ((t1 (glfw:get-time
))
127 (setf count
(/ 1.0 (/ (- (glfw:get-time
) t1
)
129 (setf t1
(glfw:get-time
))
132 (format t
"Test 2: ~,3f ms / sleep (mean)~%~%"
133 (/ (* 1000.0 (- (glfw:get-time
) t1
))