1 ;;; Copyright (C) 2020 Ahmet Artu Yildirim
3 ;;; orca is free software: you can redistribute it and/or modify
4 ;;; it under the terms of the GNU Lesser General Public License as
5 ;;; published by the Free Software Foundation, either version 3 of
6 ;;; the License, or (at your option) any later version.
8 ;;; orca is distributed in the hope that it will be useful,
9 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ;;; GNU Lesser General Public License for more details.
13 ;;; You should have received a copy of the GNU Lesser General Public License
14 ;;; along with orca. If not, see <https://www.gnu.org/licenses/>.
16 (define-module (orca internal)
17 #:use-module (orca config)
18 #:use-module (system foreign)
19 #:use-module (rnrs bytevectors)
20 #:use-module (ice-9 q)
21 #:use-module (ice-9 iconv)
22 #:use-module (ice-9 eval-string)
23 #:use-module (srfi srfi-9)
24 #:use-module (ice-9 exceptions))
26 ;;------------------------------------------------------------------------------
30 ;;------------------------------------------------------------------------------
33 (define MPI_COMM_WORLD #x44000000)
34 (define MPI_SUCCESS 0)
35 (define MPI_BYTE #x4c00010d)
36 (define MPI_STATUS_IGNORE (make-pointer 1))
37 (define MPI_STATUSES_IGNORE (make-pointer 1))
39 ;;; Internal Constants
40 (define DEFAULT_ENCODING "utf-8")
41 (define MPI_OP_SEND 1)
42 (define MPI_OP_RECV 2)
44 ;;------------------------------------------------------------------------------
46 ;;; Object properties used internally
48 ;;------------------------------------------------------------------------------
50 (define %mpi-request-buffer% (make-object-property))
51 (define %mpi-request-origin% (make-object-property))
52 (define %mpi-request-op% (make-object-property))
53 (define %mpi-receive-source% (make-object-property))
55 ;;------------------------------------------------------------------------------
59 ;;------------------------------------------------------------------------------
62 (lambda* (return-type function-name arg-types)
63 (pointer->procedure return-type
64 (dynamic-func function-name *libmpi*)
67 (define-syntax-rule (define-mpi-foreign
68 name return-type func-name arg-types)
70 (mpi-func return-type func-name arg-types)))
72 (define (boolean->c-bool b)
73 "Convert the boolean to a c boolean."
76 (define (c-bool->boolean b)
77 "Convert the c boolean to boolean."
80 (define (bytevector->int bv)
81 (bytevector-sint-ref bv
86 (define (bvlist->pointer lst size)
88 ((null? lst) %null-pointer)
89 ((not (pair? lst)) (error "input is not a list"))
90 (else (let* ((lst-length (length lst))
91 (bv-target (make-bytevector (* size lst-length))))
95 (bytevector-copy! (list-ref lst i) 0 bv-target
98 (bytevector->pointer bv-target)))))
100 ;;; MPI_Status structure
102 (define-record-type <mpi-status>
103 (%make-mpi-status count cancelled mpi-source mpi-tag mpi-error)
105 (count mpi-status-count set-mpi-status-count!)
106 (cancelled mpi-status-cancelled set-mpi-status-cancelled!)
107 (mpi-source mpi-status-source set-mpi-status-source!)
108 (mpi-tag mpi-status-tag set-mpi-status-tag!)
109 (mpi-error mpi-status-error set-mpi-status-error!))
111 (define* (make-mpi-status #:key
117 (%make-mpi-status count cancelled mpi-source mpi-tag mpi-error))
119 (define mpi-status-types (list int int int int int))
121 (define (make-mpi-status-pointer)
126 (define (pointer->mpi-status pointer)
127 (let ((lst (parse-c-struct pointer mpi-status-types)))
128 (make-mpi-status #:count (list-ref lst 0)
129 #:cancelled (list-ref lst 1)
130 #:mpi-source (list-ref lst 2)
131 #:mpi-tag (list-ref lst 3)
132 #:mpi-error (list-ref lst 4))))
134 ;;------------------------------------------------------------------------------
138 ;;------------------------------------------------------------------------------
140 (define (make-mpi-request)
141 (bytevector->pointer (make-bytevector (sizeof int))))
143 (define (mpi-request-list->pointer lst)
144 (let ((bv-lst (map (lambda (ptr)
145 (pointer->bytevector ptr (sizeof int))) lst)))
146 (bvlist->pointer lst (sizeof int))))
148 (define (mpi-request-list->buffer-list lst)
154 (when (= (%mpi-request-op% (car rest)) MPI_OP_RECV)
155 (enq! q (bytevector->string
156 (%mpi-request-buffer% (car rest))
160 ;;------------------------------------------------------------------------------
162 (define (exp->string s-exp)
163 (call-with-output-string
164 (lambda (port) (write s-exp port))))
168 ;;------------------------------------------------------------------------------
170 (define (string->exp str)
171 (call-with-input-string str (lambda (port) (read port))))
175 ;;------------------------------------------------------------------------------
177 (define (eval-message message)
178 (exp->string (eval (string->exp message) (interaction-environment))))
180 (export eval-message)
182 ;;------------------------------------------------------------------------------
186 ;;------------------------------------------------------------------------------
188 (define-mpi-foreign %mpi-init
189 int "MPI_Init" (list '* '*))
192 "Initialize the MPI execution environment."
193 (unless (= MPI_SUCCESS (%mpi-init %null-pointer %null-pointer))
194 (error "failed to init mpi")))
198 ;;------------------------------------------------------------------------------
200 (define-mpi-foreign %mpi-finalize
201 int "MPI_Finalize" '())
203 (define (mpi-finalize)
204 "Terminates MPI execution environment."
205 (unless (= MPI_SUCCESS (%mpi-finalize))
206 (error "failed to finalize mpi")))
208 (export mpi-finalize)
210 ;;------------------------------------------------------------------------------
212 (define-mpi-foreign %mpi-barrier
213 int "MPI_Barrier" (list int))
215 (define (mpi-barrier)
216 "Blocks until all processes in the communicator have reached this routine."
217 (unless (= MPI_SUCCESS (%mpi-barrier MPI_COMM_WORLD))
218 (error "failed to block")))
222 ;;------------------------------------------------------------------------------
224 (define-mpi-foreign %mpi-initialized
225 int "MPI_Initialized" (list '*))
227 (define (mpi-initialized)
228 "Check whether MPI has been initialized."
229 (let* ((bv-flag (make-bytevector (sizeof int)))
230 (result (%mpi-initialized (bytevector->pointer bv-flag))))
232 (bytevector->int bv-flag))))
234 (export mpi-initialized)
236 ;;------------------------------------------------------------------------------
238 (define-mpi-foreign %mpi-comm-rank
239 int "MPI_Comm_rank" (list int '*))
242 "Determine the rank of the calling process in the communicator."
243 (let* ((bv-rank (make-bytevector (sizeof int)))
244 (result (%mpi-comm-rank MPI_COMM_WORLD (bytevector->pointer bv-rank))))
245 (if (= MPI_SUCCESS result)
246 (bytevector->int bv-rank)
247 (error "failed to get rank"))))
251 ;;------------------------------------------------------------------------------
253 (define-mpi-foreign %mpi-comm-size
254 int "MPI_Comm_size" (list int '*))
257 "Return the size of the group associated with a communicator."
258 (let* ((bv-size (make-bytevector (sizeof int)))
259 (result (%mpi-comm-size MPI_COMM_WORLD (bytevector->pointer bv-size))))
260 (if (= MPI_SUCCESS result)
261 (bytevector->int bv-size)
262 (error "failed to get size"))))
266 ;;------------------------------------------------------------------------------
268 (define-mpi-foreign %mpi-send
269 int "MPI_Send" (list '* int int int int int))
271 (define (mpi-send-string dest message tag)
272 "Send string message to destination process in a blocking mode."
273 (let* ((bv-message (string->bytevector message DEFAULT_ENCODING))
274 (bv-message-size (bytevector-length bv-message))
275 (result (%mpi-send (bytevector->pointer bv-message)
281 (unless (= MPI_SUCCESS result)
282 (error "failed to send message"))))
284 (export mpi-send-string)
286 ;;------------------------------------------------------------------------------
288 (define-mpi-foreign %mpi-isend
289 int "MPI_Isend" (list '* int int int int int '*))
291 (define (mpi-isend-string dest message tag)
292 "Send string message to destination process in a nonblocking mode."
293 (let* ((bv-message (string->bytevector message DEFAULT_ENCODING))
294 (bv-message-size (bytevector-length bv-message))
295 (mpi-request (make-mpi-request))
296 (result (%mpi-isend (bytevector->pointer bv-message)
303 (if (= MPI_SUCCESS result)
305 ; associate data with the request pointer
306 (set! (%mpi-request-origin% mpi-request) dest)
307 (set! (%mpi-request-op% mpi-request) MPI_OP_SEND)
309 (error "failed to send message"))))
311 (export mpi-isend-string)
313 ;;------------------------------------------------------------------------------
315 (define-mpi-foreign %mpi-probe
316 int "MPI_Probe" (list int int int '*))
318 (define (mpi-probe source tag)
319 "Blocking test for a message."
320 (let* ((status-p (make-mpi-status-pointer))
321 (result (%mpi-probe source
325 (if (= MPI_SUCCESS result)
327 (error "failed to probe for message"))))
329 ;;------------------------------------------------------------------------------
331 (define-mpi-foreign %mpi-get-count
332 int "MPI_Get_count" (list '* int '*))
334 (define (mpi-get-byte-count status-p)
335 "Gets the number of bytes in the status"
336 (let* ((bv-count (make-bytevector (sizeof int)))
337 (result (%mpi-get-count status-p
339 (bytevector->pointer bv-count))))
340 (if (= MPI_SUCCESS result)
341 (bytevector->int bv-count)
342 (error "failed to get byte count"))))
344 ;;------------------------------------------------------------------------------
346 (define-mpi-foreign %mpi-recv
347 int "MPI_Recv" (list '* int int int int int '*))
349 (define (mpi-recv-string source tag)
350 "Receive a string message from source process in a blocking mode."
351 (let* ((status-p (mpi-probe source tag))
352 (buf-count (mpi-get-byte-count status-p))
353 (bv-buf (make-bytevector buf-count))
354 (result (%mpi-recv (bytevector->pointer bv-buf)
361 (if (= MPI_SUCCESS result)
362 (bytevector->string bv-buf DEFAULT_ENCODING)
363 (error "failed to receive message"))))
365 (export mpi-recv-string)
367 ;;------------------------------------------------------------------------------
369 (define-mpi-foreign %mpi-irecv
370 int "MPI_Irecv" (list '* int int int int int '*))
372 (define (mpi-irecv-string source tag)
373 "Begins a nonblocking receive."
374 (let* ((status-p (mpi-probe source tag))
375 (buf-count (mpi-get-byte-count status-p))
376 (bv-buf (make-bytevector buf-count))
377 (mpi-request (make-mpi-request))
378 (result (%mpi-irecv (bytevector->pointer bv-buf)
385 (if (= MPI_SUCCESS result)
387 ; associate data with the request pointer
388 (set! (%mpi-request-buffer% mpi-request) bv-buf)
389 (set! (%mpi-request-origin% mpi-request) source)
390 (set! (%mpi-request-op% mpi-request) MPI_OP_RECV)
392 (error "failed to begin nonblocking receive"))))
394 (export mpi-irecv-string)
396 ;;------------------------------------------------------------------------------
398 (define-mpi-foreign %mpi-wait
399 int "MPI_Wait" (list '* '*))
401 (define (mpi-wait request)
402 "Waits for an MPI request to complete."
403 (let ((result (%mpi-wait request
405 (if (= MPI_SUCCESS result)
406 (when (= (%mpi-request-op% request) MPI_OP_RECV)
407 (bytevector->string (%mpi-request-buffer% request) DEFAULT_ENCODING))
408 (error "failed to wait all"))))
412 ;;------------------------------------------------------------------------------
414 (define-mpi-foreign %mpi-waitall
415 int "MPI_Waitall" (list int '* '*))
417 (define (mpi-waitall requests)
418 "Waits for all given MPI requests to complete."
420 ((null? requests) (error "input list is empty"))
421 ((not (pair? requests)) (error "input is not a list"))
422 (else (let* ((request-length (length requests))
423 (result (%mpi-waitall request-length
424 (mpi-request-list->pointer requests)
425 MPI_STATUSES_IGNORE)))
426 (if (= MPI_SUCCESS result)
427 (mpi-request-list->buffer-list requests)
428 (error "failed to wait all"))))))