-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
parallelization.lisp
117 lines (107 loc) · 4.45 KB
/
parallelization.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
(in-package #:org.shirakumo.fraf.convex-covering)
;;; `with-thread-pool' macro
(deftype thread-pool-designator ()
'(or (eql NIL)
(integer 1)
#+convex-covering-with-lparallel lparallel:kernel
(eql T)))
(defun call-with-thread-pool (thread-pool-designator continuation)
#+convex-covering-with-lparallel
(flet ((call-with-new-kernel (thread-count)
(let ((kernel (lparallel:make-kernel thread-count)))
(unwind-protect
(let ((lparallel:*kernel* kernel))
(funcall continuation))
(let ((lparallel:*kernel* kernel))
(lparallel:end-kernel))))))
(etypecase thread-pool-designator
((member NIL 1)
(let ((lparallel:*kernel* nil))
(funcall continuation)))
((integer 2)
(call-with-new-kernel thread-pool-designator))
(lparallel:kernel
(let ((lparallel:*kernel* thread-pool-designator))
(funcall continuation)))
((eql T)
(call-with-new-kernel (org.shirakumo.machine-state:machine-cores)))))
#-convex-covering-with-lparallel
(progn
(check-type thread-pool-designator thread-pool-designator)
(unless (typep thread-pool-designator '(member NIL 1))
(warn "~@<Parallel execution with ~A requested but parallelization has ~
not been enabled at compile time.~@:>"
thread-pool-designator))
(funcall continuation)))
(defmacro with-thread-pool ((thread-pool-designator) &body body)
`(call-with-thread-pool ,thread-pool-designator (lambda () ,@body)))
;;; `maybe-plet' macro
;;; Does not support declarations.
(defmacro maybe-plet ((&rest bindings) &body body)
(labels ((emit (remaining)
(if remaining
(destructuring-bind (first &rest rest) remaining
(destructuring-bind (name-or-names value) first
`(multiple-value-bind ,(if (listp name-or-names)
name-or-names
(list name-or-names))
,value
,(emit rest))))
`(progn ,@body))))
#+convex-covering-with-lparallel
`(if lparallel:*kernel*
(lparallel:plet ,bindings ,@body)
,(emit bindings))
#-convex-covering-with-lparallel
(emit bindings)))
;;; `with-tasks' macro
#+convex-covering-with-lparallel
(defun expand-task (ordered channel task-count body)
(let ((nid (gensym "ID")))
`(let (,@(when ordered `((,nid ,task-count))))
(lparallel:submit-task
,channel (lambda ()
,@(if ordered
`((cons ,nid (progn ,@body)))
body)))
(incf ,task-count))))
#+convex-covering-with-lparallel
(defun expand-do-results (ordered channel task-count variable body)
(if ordered
(let ((nresults (gensym "RESULTS")))
`(let* ((,nresults (loop repeat ,task-count
collect (lparallel:receive-result ,channel)))
(,nresults (sort ,nresults #'< :key #'car)))
(mapc (lambda (,variable)
(let ((,variable (cdr ,variable)))
,@body))
,nresults)))
`(loop repeat ,task-count
for ,variable = (lparallel:receive-result ,channel)
do (progn ,@body))))
(defmacro with-tasks ((&key ordered) &body body)
#-convex-covering-with-lparallel
(declare (ignore ordered))
(let* ((nresults (gensym "RESULTS"))
(serial-expansion
`(let ((,nresults '()))
(macrolet ((task (&body body)
`(push (progn ,@body) ,',nresults))
(do-results ((result) &body body)
`(dolist (,result (nreverse ,',nresults))
,@body)))
,@body))))
#+convex-covering-with-lparallel
(let ((nchannel (gensym "CHANNEL"))
(ntask-count (gensym "TASK-COUNT")))
`(if lparallel:*kernel*
(let ((,nchannel (lparallel:make-channel))
(,ntask-count 0))
(macrolet ((task (&body body)
(expand-task ',ordered ',nchannel ',ntask-count body))
(do-results ((result) &body body)
(expand-do-results ',ordered ',nchannel ',ntask-count result body)))
,@body))
,serial-expansion))
#-convex-covering-with-lparallel
serial-expansion))