mpipe 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +14 -3
- data/ext/mpipe/mpipe.c +121 -70
- data/samples/t1.rb +5 -5
- data/samples/t2.rb +7 -5
- data/samples/t3.rb +1 -1
- data/samples/t4.rb +4 -5
- data/samples/t5.rb +4 -4
- data/samples/t6.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4f0bec53a0a6940093b513532384491708117c9
|
4
|
+
data.tar.gz: 9f15045ca9c5e95c21cb60903d95f3fb16191525
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50908b6ec00bc10bcef427998eb7f2941bbc1d6d2aadd33cb928e6a1aa37770bdf31663ca027fd8690ba259a4429d6f2336b3fa124e139c123ff4bb4c5ddcdd4
|
7
|
+
data.tar.gz: 3a06ab215c22444df2914fd583aeebb4aab9138ad68affb090c5949119a41063b006c5d76fdd7b82d5f5704fb7ba31236b0f3264cee41feb67ca66384f5c0e07
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
Ruby's IO.pipe emulation over MPI
|
4
4
|
|
5
|
+
[GitHub](https://github.com/masa16/mpipe) | [RubyGems](https://rubygems.org/gems/mpipe)
|
6
|
+
|
7
|
+
## Requirement
|
8
|
+
|
9
|
+
Message Passing Interface (MPI) framework such as
|
10
|
+
[OpenMPI](https://www.open-mpi.org/), [MPICH](https://www.mpich.org/), etc.
|
11
|
+
|
12
|
+
Commands:
|
13
|
+
* mpicc - Compiler for MPI programs.
|
14
|
+
* mpirun - Command to run MPI program.
|
15
|
+
|
5
16
|
## Installation
|
6
17
|
|
7
18
|
Add this line to your application's Gemfile:
|
@@ -66,11 +77,11 @@ MPipe::Comm.size -- calls MPI_Comm_size(), return the size of this environment.
|
|
66
77
|
|
67
78
|
mp = MPipe.new(rank) -- returns pipe to MPI process with rank.
|
68
79
|
mp.write(str) -- emulate IO#write.
|
69
|
-
mp.read(
|
70
|
-
mp.read_nonblock(maxlen,outbuf) -- emulate IO#read_nonblock.
|
80
|
+
mp.read(length,outbuf=nil) -- emulate IO#read.
|
81
|
+
mp.read_nonblock(maxlen,outbuf=nil,excepton:true) -- emulate IO#read_nonblock.
|
71
82
|
MPipe.select(array_of_mpipe) -- emulate IO.select
|
72
83
|
```
|
73
84
|
|
74
85
|
## Contributing
|
75
86
|
|
76
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
87
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/masa16/mpipe.
|
data/ext/mpipe/mpipe.c
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
//#include "ruby/encoding.h"
|
4
4
|
#include "mpi.h"
|
5
5
|
|
6
|
-
#define MPIPE_VERSION "0.
|
6
|
+
#define MPIPE_VERSION "0.2.0"
|
7
7
|
|
8
8
|
static int mp_buffer_size = 4098;
|
9
9
|
static int mp_initialized = 0;
|
@@ -207,7 +207,13 @@ mp_s_allocate(VALUE klass)
|
|
207
207
|
static VALUE
|
208
208
|
mp_init(struct MPipe *ptr, VALUE self, VALUE rank)
|
209
209
|
{
|
210
|
+
int size;
|
211
|
+
|
212
|
+
MPI_Comm_size(MPI_COMM_WORLD, &size);
|
210
213
|
ptr->rank = NUM2INT(rank);
|
214
|
+
if (ptr->rank < 0 || ptr->rank >= size) {
|
215
|
+
rb_raise(rb_eArgError,"Invalid rank has value %d but must be nonnegative and less than %d\n",ptr->rank,size);
|
216
|
+
}
|
211
217
|
ptr->send_buffer = malloc(mp_buffer_size);
|
212
218
|
ptr->recv_buffer = malloc(mp_buffer_size);
|
213
219
|
return self;
|
@@ -345,79 +351,104 @@ mp_write(VALUE self, VALUE str)
|
|
345
351
|
}
|
346
352
|
|
347
353
|
|
348
|
-
|
349
|
-
|
350
|
-
mp_outbuf(char *buf, int len, VALUE outbuf)
|
354
|
+
static int
|
355
|
+
copy_substr(struct MPipe *ptr, int max_len, VALUE outbuf, int outbuf_pos)
|
351
356
|
{
|
352
|
-
|
353
|
-
return rb_str_new(buf, len);
|
354
|
-
} else {
|
355
|
-
rb_str_resize(outbuf, len);
|
356
|
-
MEMCPY(RSTRING_PTR(outbuf), buf, char, len);
|
357
|
-
return outbuf;
|
358
|
-
}
|
359
|
-
}
|
360
|
-
|
361
|
-
static VALUE
|
362
|
-
mp_substr(struct MPipe *ptr, VALUE maxlen, VALUE outbuf)
|
363
|
-
{
|
364
|
-
int max_len;
|
365
|
-
int count = ptr->recv_count;
|
357
|
+
int len;
|
366
358
|
char *recv_buf = ptr->recv_buffer + ptr->recv_begin;
|
367
359
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
return mp_outbuf(recv_buf, max_len, outbuf);
|
377
|
-
}
|
360
|
+
len = max_len - outbuf_pos;
|
361
|
+
if (len < ptr->recv_count) {
|
362
|
+
ptr->recv_begin += len;
|
363
|
+
ptr->recv_count -= len;
|
364
|
+
} else {
|
365
|
+
len = ptr->recv_count;
|
366
|
+
ptr->recv_begin = 0;
|
367
|
+
ptr->recv_count = 0;
|
378
368
|
}
|
379
|
-
|
380
|
-
|
381
|
-
return mp_outbuf(recv_buf, count, outbuf);
|
369
|
+
MEMCPY(RSTRING_PTR(outbuf)+outbuf_pos, recv_buf, char, len);
|
370
|
+
return len;
|
382
371
|
}
|
383
372
|
|
384
|
-
|
373
|
+
/*
|
374
|
+
* call-seq:
|
375
|
+
* ios.read(length [, outbuf]) -> string, outbuf, or nil
|
376
|
+
*
|
377
|
+
* Reads <i>length</i> bytes from the I/O stream.
|
378
|
+
*
|
379
|
+
* <i>length</i> must be a non-negative integer.
|
380
|
+
*/
|
385
381
|
static VALUE
|
386
382
|
mp_read(int argc, VALUE *argv, VALUE self)
|
387
383
|
{
|
388
384
|
struct MPipe *ptr = MPipe(self);
|
389
385
|
MPI_Status status;
|
390
386
|
int istat;
|
391
|
-
int
|
387
|
+
int outbuf_pos = 0;
|
388
|
+
int max_len;
|
392
389
|
VALUE maxlen = Qnil;
|
393
390
|
VALUE outbuf = Qnil;
|
394
391
|
|
395
|
-
rb_scan_args(argc, argv, "
|
392
|
+
rb_scan_args(argc, argv, "11", &maxlen, &outbuf);
|
393
|
+
|
394
|
+
max_len = NUM2INT(maxlen);
|
395
|
+
if (max_len < 0) {
|
396
|
+
rb_raise(rb_eArgError, "negative length %d given", max_len);
|
397
|
+
}
|
398
|
+
|
399
|
+
if (NIL_P(outbuf)) {
|
400
|
+
outbuf = rb_str_new(0, 0);
|
401
|
+
}
|
402
|
+
rb_str_resize(outbuf, max_len);
|
403
|
+
|
404
|
+
if (ptr->recv_count == -1) { // requesting
|
405
|
+
istat = MPI_Wait(&ptr->recv_request, &status);
|
406
|
+
if (istat != MPI_SUCCESS) {
|
407
|
+
rb_raise(rb_eStandardError,"MPI_Wait failed with status=%d",istat);
|
408
|
+
}
|
409
|
+
MPI_Get_count(&status, MPI_CHAR, &ptr->recv_count);
|
410
|
+
}
|
396
411
|
|
397
412
|
if (ptr->recv_count > 0) {
|
398
|
-
|
413
|
+
outbuf_pos += copy_substr(ptr, max_len, outbuf, outbuf_pos);
|
399
414
|
}
|
400
|
-
|
415
|
+
|
416
|
+
while (outbuf_pos < max_len) {
|
401
417
|
istat = MPI_Recv(ptr->recv_buffer, mp_buffer_size, MPI_CHAR, ptr->rank,
|
402
418
|
0, MPI_COMM_WORLD, &status);
|
403
419
|
if (istat != MPI_SUCCESS) {
|
404
420
|
rb_raise(rb_eStandardError,"MPI_recv failed with status=%d\n",istat);
|
405
421
|
}
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
rb_raise(rb_eStandardError,"MPI_Wait failed with status=%d",istat);
|
410
|
-
}
|
422
|
+
MPI_Get_count(&status, MPI_CHAR, &ptr->recv_count);
|
423
|
+
|
424
|
+
outbuf_pos += copy_substr(ptr, max_len, outbuf, outbuf_pos);
|
411
425
|
}
|
412
|
-
|
413
|
-
|
414
|
-
return mp_substr(ptr, maxlen, outbuf);
|
426
|
+
|
427
|
+
return outbuf;
|
415
428
|
}
|
416
429
|
|
417
430
|
|
431
|
+
static int
|
432
|
+
call_test(struct MPipe *ptr)
|
433
|
+
{
|
434
|
+
MPI_Status status;
|
435
|
+
int complete = 0;
|
436
|
+
int istat;
|
437
|
+
|
438
|
+
// if (ptr->recv_count == -1)
|
439
|
+
istat = MPI_Test(&ptr->recv_request, &complete, &status);
|
440
|
+
if (istat != MPI_SUCCESS) {
|
441
|
+
rb_raise(rb_eStandardError,"MPI_Test failed with status=%d",istat);
|
442
|
+
}
|
443
|
+
if (complete) {
|
444
|
+
MPI_Get_count(&status, MPI_CHAR, &ptr->recv_count);
|
445
|
+
return ptr->recv_count;
|
446
|
+
}
|
447
|
+
return 0;
|
448
|
+
}
|
418
449
|
|
419
450
|
static void
|
420
|
-
|
451
|
+
call_irecv(struct MPipe *ptr)
|
421
452
|
{
|
422
453
|
int istat;
|
423
454
|
|
@@ -439,7 +470,7 @@ buffered: recv_count=n
|
|
439
470
|
|
440
471
|
/*
|
441
472
|
* call-seq:
|
442
|
-
* mpipe.read_nonblock(
|
473
|
+
* mpipe.read_nonblock(maxlen[, outbuf [, opts]]) -> string
|
443
474
|
*
|
444
475
|
* Similar to #read, but raises +EOFError+ at end of string unless the
|
445
476
|
* +exception: false+ option is passed in.
|
@@ -448,40 +479,60 @@ static VALUE
|
|
448
479
|
mp_read_nonblock(int argc, VALUE *argv, VALUE self)
|
449
480
|
{
|
450
481
|
struct MPipe *ptr = MPipe(self);
|
451
|
-
|
452
|
-
int
|
453
|
-
int count;
|
454
|
-
int complete = 0;
|
482
|
+
int outbuf_pos = 0;
|
483
|
+
int max_len;
|
455
484
|
VALUE maxlen = Qnil;
|
456
485
|
VALUE outbuf = Qnil;
|
457
486
|
VALUE opts = Qnil;
|
458
|
-
VALUE val;
|
459
487
|
|
460
|
-
rb_scan_args(argc, argv, "
|
488
|
+
rb_scan_args(argc, argv, "11:", &maxlen, &outbuf, &opts);
|
461
489
|
|
462
|
-
|
463
|
-
|
490
|
+
max_len = NUM2INT(maxlen);
|
491
|
+
if (max_len < 0) {
|
492
|
+
rb_raise(rb_eArgError, "negative length %d given", max_len);
|
464
493
|
}
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
rb_raise(rb_eStandardError,"MPI_Test failed with status=%d",istat);
|
494
|
+
|
495
|
+
if (NIL_P(outbuf)) {
|
496
|
+
outbuf = rb_str_new(0, 0);
|
469
497
|
}
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
}
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
498
|
+
rb_str_resize(outbuf, max_len);
|
499
|
+
|
500
|
+
if (maxlen == 0) {
|
501
|
+
return outbuf;
|
502
|
+
}
|
503
|
+
|
504
|
+
if (ptr->recv_count == -1) { // requesting
|
505
|
+
if (call_test(ptr) == 0) {
|
506
|
+
if (!NIL_P(opts) && rb_hash_lookup2(opts, sym_exception, Qundef) == Qfalse) {
|
507
|
+
return Qnil;
|
508
|
+
} else {
|
509
|
+
rb_raise(eEAGAINWaitReadable,"MPI_Irecv would block");
|
510
|
+
}
|
511
|
+
}
|
512
|
+
}
|
513
|
+
if (ptr->recv_count > 0) {
|
514
|
+
outbuf_pos += copy_substr(ptr, max_len, outbuf, outbuf_pos);
|
515
|
+
}
|
516
|
+
|
517
|
+
while (outbuf_pos < max_len) {
|
518
|
+
call_irecv(ptr);
|
519
|
+
if (call_test(ptr) == 0) {
|
520
|
+
if (outbuf_pos > 0) {
|
521
|
+
rb_str_resize(outbuf, outbuf_pos);
|
522
|
+
return outbuf;
|
523
|
+
} else
|
524
|
+
if (!NIL_P(opts) && rb_hash_lookup2(opts, sym_exception, Qundef) == Qfalse) {
|
525
|
+
return Qnil;
|
526
|
+
} else {
|
527
|
+
rb_raise(eEAGAINWaitReadable,"MPI_Irecv would block");
|
528
|
+
}
|
480
529
|
}
|
530
|
+
outbuf_pos += copy_substr(ptr, max_len, outbuf, outbuf_pos);
|
481
531
|
}
|
482
|
-
return
|
532
|
+
return outbuf;
|
483
533
|
}
|
484
534
|
|
535
|
+
|
485
536
|
static VALUE
|
486
537
|
mp_s_select(int argc, VALUE *argv, VALUE mod)
|
487
538
|
{
|
@@ -519,7 +570,7 @@ mp_s_select(int argc, VALUE *argv, VALUE mod)
|
|
519
570
|
for (i=0; i < incount; i++) {
|
520
571
|
item = RARRAY_AREF(argv[0], i);
|
521
572
|
ptr = MPipe(item);
|
522
|
-
|
573
|
+
call_irecv(ptr);
|
523
574
|
ary_of_requests[i] = ptr->recv_request;
|
524
575
|
}
|
525
576
|
|
data/samples/t1.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
|
-
|
1
|
+
require "mpipe"
|
2
2
|
|
3
|
-
puts "buffer_size = %d" % MPipe.buffer_size
|
4
3
|
MPipe.buffer_size = 2**10
|
5
|
-
puts "buffer_size = %d" % MPipe.buffer_size
|
6
4
|
|
7
5
|
MPipe.init
|
8
6
|
rank = MPipe::Comm.rank
|
9
7
|
size = MPipe::Comm.size
|
10
8
|
puts "size=%d rank=%d pid=%d" % [size, rank, Process.pid]
|
11
9
|
|
12
|
-
# MPipe.buffer_size = 2**13
|
13
10
|
p MPipe.new(0).object_id == MPipe.new(0).object_id
|
14
11
|
|
15
12
|
if rank == 0
|
16
13
|
|
14
|
+
puts "buffer_size = %d" % MPipe.buffer_size
|
15
|
+
|
16
|
+
len = "Hello from 0".size
|
17
17
|
(1..size-1).each do |i|
|
18
|
-
p MPipe.new(i).read
|
18
|
+
p MPipe.new(i).read(len)
|
19
19
|
end
|
20
20
|
|
21
21
|
else
|
data/samples/t2.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require "mpipe"
|
2
2
|
|
3
3
|
MPipe.init
|
4
4
|
|
@@ -14,7 +14,7 @@ if rank == 0
|
|
14
14
|
while !pipes.empty?
|
15
15
|
rsel, = MPipe.select(pipes)
|
16
16
|
rsel.each do |r|
|
17
|
-
p s=r.read_nonblock
|
17
|
+
p s=r.read_nonblock(12, exception:false)
|
18
18
|
if /end/ =~ s
|
19
19
|
pipes.delete(r)
|
20
20
|
end
|
@@ -23,9 +23,11 @@ if rank == 0
|
|
23
23
|
|
24
24
|
else
|
25
25
|
|
26
|
+
mp = MPipe.new(0)
|
26
27
|
sleep size-rank
|
27
|
-
|
28
|
-
|
29
|
-
MPipe.new(0).write("end")
|
28
|
+
mp.write("Hello from #{rank}")
|
29
|
+
mp.write("end")
|
30
30
|
|
31
31
|
end
|
32
|
+
|
33
|
+
MPipe.finalize
|
data/samples/t3.rb
CHANGED
data/samples/t4.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
|
1
|
+
require "mpipe"
|
2
2
|
|
3
3
|
MPipe.init
|
4
4
|
rank = MPipe::Comm.rank
|
5
5
|
size = MPipe::Comm.size
|
6
6
|
puts "size=%d rank=%d pid=%d" % [size,rank,Process.pid]
|
7
7
|
|
8
|
-
def _read(io)
|
9
|
-
io.read_nonblock
|
8
|
+
def _read(io,n)
|
9
|
+
io.read_nonblock(n)
|
10
10
|
rescue IO::WaitReadable
|
11
11
|
MPipe.select([io])
|
12
12
|
retry
|
@@ -17,9 +17,8 @@ if rank == 0
|
|
17
17
|
pipes = (1..size-1).map{|rank| MPipe.new(rank)}
|
18
18
|
|
19
19
|
pipes.each do |x|
|
20
|
-
while !(s = _read(x))
|
20
|
+
while !(s = _read(x,12))
|
21
21
|
puts "waiting"
|
22
|
-
$stdout.flush
|
23
22
|
end
|
24
23
|
p s
|
25
24
|
end
|
data/samples/t5.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require "mpipe"
|
2
2
|
|
3
3
|
MPipe.init
|
4
4
|
rank = MPipe::Comm.rank
|
@@ -14,7 +14,7 @@ if rank == 0
|
|
14
14
|
rsel, = MPipe.select(pipes)
|
15
15
|
rsel.each do |r|
|
16
16
|
#p r.read_nonblock(6,"")
|
17
|
-
p s = r.read_nonblock()
|
17
|
+
p s = r.read_nonblock(74,exception:false)
|
18
18
|
pipes.delete(r) if /end/ =~ s
|
19
19
|
end
|
20
20
|
end
|
@@ -22,7 +22,7 @@ if rank == 0
|
|
22
22
|
else
|
23
23
|
|
24
24
|
sleep size-rank
|
25
|
-
message = "Hello from #{rank} - "*500+"end"
|
26
|
-
MPipe.new(0).
|
25
|
+
message = "Hello from #{rank} - "*500+"hello end"
|
26
|
+
MPipe.new(0).write(message)
|
27
27
|
|
28
28
|
end
|
data/samples/t6.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mpipe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masahiro TANAKA
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|