mpipe 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|