MPIは並列コンピュータを利用するための標準規格で、これをOCamlで実現しているサイトに興味を持ちました。
参考: http://www.ueda.info.waseda.ac.jp/~sakai/ocaml/ocamlmemo.html#doc1_1485
Cで書かれたものよりもシンプルに実現できており、こういう関数型言語のメリットを感じてみようと試してみました。
環境: Ubuntu 16.04 / VirtualBox
設定:
sudo apt-get install opam
opam init
evalopam config env
. /home/n/.opam/opam-init/init.sh > /dev/null 2> /dev/null || true
sudo apt-get install m4
sudo apt-get install mpich
sudo apt-get install libopenmpi-dev
opam install mpi
まずはC言語でMPIの動きを試してみます。
参考: https://ja.wikipedia.org/wiki/Message_Passing_Interface
hello.c
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 |
#include <mpi.h> #include <stdio.h> #include <string.h> #define BUFSIZE 128 #define TAG 0 int main(int argc, char *argv[]) { char idstr[32]; char buff[BUFSIZE]; int num; int rank; int i; MPI_Status stat; printf("-s-\n"); MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD,&num); MPI_Comm_rank(MPI_COMM_WORLD,&rank); if(rank == 0){ printf("%d: We have %d processors\n", rank, num); for(i=1 ; i<num ; i++){ sprintf(buff, "Hello %d TAG0 ! -> ", i); MPI_Send(buff, BUFSIZE, MPI_CHAR, i, 0, MPI_COMM_WORLD); sprintf(buff, "Hello %d TAG1 ! -> ", i); MPI_Send(buff, BUFSIZE, MPI_CHAR, i, 1, MPI_COMM_WORLD); } for(i=1 ; i<num ; i++){ MPI_Recv(buff, BUFSIZE, MPI_CHAR, i, 0, MPI_COMM_WORLD, &stat); printf("%d: %s\n", rank, buff); MPI_Recv(buff, BUFSIZE, MPI_CHAR, i, 1, MPI_COMM_WORLD, &stat); printf("%d: %s\n", rank, buff); } } else{ MPI_Recv(buff, BUFSIZE, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &stat); sprintf(idstr, "Processor %d TAG0", rank); strncat(buff, idstr, BUFSIZE-1); MPI_Send(buff, BUFSIZE, MPI_CHAR, 0, 0, MPI_COMM_WORLD); MPI_Recv(buff, BUFSIZE, MPI_CHAR, 0, 1, MPI_COMM_WORLD, &stat); sprintf(idstr, "Processor %d TAG1", rank); strncat(buff, idstr, BUFSIZE-1); MPI_Send(buff, BUFSIZE, MPI_CHAR, 0, 1, MPI_COMM_WORLD); } MPI_Finalize(); printf("-e-\n"); return 0; } |
コンパイル:
cc -o hello hello.c -I /usr/lib/openmpi/include -L /usr/lib/open/lib -lmpi
rankとtagで識別して通信しているのがわかります。
この動きが把握できたところで、次はOcaml。
mpi_test.ml
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 |
open Mpi let size = comm_size comm_world let rank = comm_rank comm_world let _ = if rank=0 then begin send "data01" 3 0 comm_world; send "data02" 2 1 comm_world; end; if rank=1 then begin send "data03" 3 2 comm_world; send "data04" 2 3 comm_world; end; if rank=2 then begin let a,b,c = receive_status any_source 1 comm_world and d,e,f = receive_status any_source 3 comm_world in Printf.printf "rank:%d, tag:%d, %s\n" b c a; Printf.printf "rank:%d, tag:%d, %s\n" e f d; end; if rank=3 then begin let a,b,c = receive_status any_source 0 comm_world and d,e,f = receive_status any_source 2 comm_world in Printf.printf "rank:%d, tag:%d, %s\n" b c a; Printf.printf "rank:%d, tag:%d, %s\n" e f d; end |
コンパイル:
ocamlc -I ~/.opam/system/lib/mpi mpi.cma mpi_test.ml -o mpi_test
実行結果
ターゲットとするランク、タグにメッセージを送信しています。
参考にした’OCaml備忘録’というサイトですが、他にもソケット通信、Cとのインターフェイスなど詳しく書かれており、とても興味深い内容ばかりです。ここにあるものでCのLinuxプログラムでよく使うケースがありますが、Cだとわずわらしく感じる部分をOCamlで実装しても面白いと思いました。