This repository was archived by the owner on Dec 11, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy paththreads.lisp
120 lines (94 loc) · 3.46 KB
/
threads.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
(in-package :cl-user)
(defpackage :cl-waffe2/threads
(:use :cl :lparallel)
(:export
#:*num-cores*
#:*multithread-threshold*
#:with-num-cores
#:multithread-p
#:maybe-with-lparallel
#:maybe-pfuncall
#:maybe-pdotimes
#:maybe-ploop))
;; How to enable multi-threading in cl-waffe2?
;;
;; (cl-waffe2:with-num-cores (4)
;; (let ((*multithread-threshold* 80000))
;; ...)))
;;
;; lparallel is enabled only after call-with-view is used with lparallel option=t.
(in-package :cl-waffe2/threads)
;; MultiThreading configs
(deftype index () `(unsigned-byte 32))
(defvar *cl-waffe2-kernel* nil)
(defparameter *num-cores* 1 "
## [parameter] *num-cores*
Indicates the number of cpu cores. Set 1 to disable all multithreading in cl-waffe2.")
(defparameter *multithread-threshold* 80000)
(declaim (type index *num-cores* *multithread-threshold*))
(defparameter *under-multi-thread* nil)
(defmacro with-num-cores ((num-core) &body body)
"
## [macro] with-num-cores
```lisp
(with-num-cores (num-core) &body body)
```
Set *num-core*=num-core under the body execution.
"
`(let ((*num-cores* ,num-core)
(*under-multi-thread* (or *under-multi-thread* (= ,num-core 1))))
(maybe-with-lparallel ,@body)))
(defun multithread-p ()
(not (<= (the fixnum *num-cores*) 1)))
(defmacro maybe-with-lparallel (&body body)
`(let* ((*cl-waffe2-kernel* (or *cl-waffe2-kernel* (if (multithread-p)
(make-kernel *num-cores*)
nil)))
(*kernel* *cl-waffe2-kernel*))
,@body))
(defmacro maybe-pfuncall (function &rest args)
`(if (multithread-p)
(pfuncall ,function ,@args)
(funcall ,function ,@args)))
;; kaettara test
;; optimize compared to pure dotimes.
;; gemm ... (with-num-cores (1) ...) is must.
(defmacro maybe-pdotimes ((var count &key (thread-safe-vars nil) (disable-p nil) (threshold *multithread-threshold*)) &body body &aux (thread-idx (gensym)))
"
## [macro] maybe-pdotimes
"
(let ((*under-multi-thread* t))
(alexandria:with-gensyms (multi-thread-subject count-per-thread multi-thread-part from to)
`(let ((*multithread-threshold* ,threshold))
(flet ((,multi-thread-subject (,from ,to)
(declare (type index ,from ,to))
(loop with *under-multi-thread* = t
for ,var of-type index upfrom ,from below ,to
do (let (,@(loop for var in thread-safe-vars
collect `(,var ,var)))
,@body))))
(if (or *under-multi-thread*
(= (the fixnum *num-cores*) 1)
,(if disable-p
`,disable-p
`(< (the index ,count) *multithread-threshold*))
;; [todo] benchmark
(< (the index ,count) *num-cores*))
;; If *num-cores* = 1 or count is enough small. ignore parallelize.
(,multi-thread-subject 0 (the index ,count))
(maybe-with-lparallel
(let* ((,count-per-thread (the index (floor (the index ,count) (the index *num-cores*))))
(,multi-thread-part (* (the index *num-cores*) ,count-per-thread)))
(declare (type index ,count-per-thread ,multi-thread-part))
(pdotimes (,thread-idx *num-cores*)
(locally (declare (type index ,thread-idx))
(,multi-thread-subject
(the index (* ,thread-idx ,count-per-thread))
(the index (* (1+ ,thread-idx) ,count-per-thread)))))
(,multi-thread-subject
,multi-thread-part
(the index ,count))))))))))
(defmacro maybe-ploop ((var &key (upfrom 0) (below 0) (by 1)) &body body)
`(maybe-pdotimes (,var (- (the index ,below) (the index ,upfrom)))
(let ((,var (* ,by (+ ,below ,var))))
,@body)))