ruby-mpi 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +4 -4
- data/LICENSE.txt +1 -1
- data/README.rdoc +6 -1
- data/Rakefile +2 -1
- data/VERSION +1 -1
- data/ext/mpi/extconf.rb +11 -3
- data/ext/mpi/mpi.c +139 -73
- data/lib/mpi/utils.rb +17 -0
- data/samples/hello.rb +7 -1
- data/samples/narray.rb +6 -0
- data/samples/narray_offset.rb +29 -0
- data/spec/ruby-mpi_spec.rb +2 -6
- data/test/test_utils.rb +21 -0
- metadata +83 -76
- data/Gemfile.lock +0 -30
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 20fe1ffeb2cd83c63f27589552a8578a5890de22
|
4
|
+
data.tar.gz: fa319f8be8c7ce5b9287a1c58f9fd848f1f364fe
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bff7b2110e2c36af4507a8664cce6251ed2f8e890a9d56afbc960ff83b8904ac76273885e0ed5a327fb13593bdfa119b0b9232c8b3157f3523ffea3f2c73885e
|
7
|
+
data.tar.gz: c42acd7ec6937987e394610ce94bf1e31ba648e0c544710767e7472ae86d3fcd2ff2d7507928052fa46d208b4450540ec1d65c3913f27ed3f57d3de0a85d6fca
|
data/Gemfile
CHANGED
@@ -6,9 +6,9 @@ source "http://rubygems.org"
|
|
6
6
|
# Add dependencies to develop your gem here.
|
7
7
|
# Include everything needed to run rake, tests, features, etc.
|
8
8
|
group :development do
|
9
|
-
gem "rspec", "
|
10
|
-
gem "bundler", "
|
11
|
-
gem "jeweler", "
|
12
|
-
gem "
|
9
|
+
gem "rspec", ">= 2.3.0"
|
10
|
+
gem "bundler", ">= 1.0.0"
|
11
|
+
gem "jeweler", ">= 1.5.2"
|
12
|
+
gem "simplecov", ">= 0"
|
13
13
|
gem "narray", ">= 0"
|
14
14
|
end
|
data/LICENSE.txt
CHANGED
data/README.rdoc
CHANGED
@@ -5,6 +5,11 @@ Ruby-MPI is a ruby binding of Message Passing Interface (MPI), which is an API s
|
|
5
5
|
== Install
|
6
6
|
|
7
7
|
# gem install ruby-mpi
|
8
|
+
|
9
|
+
== How to run
|
10
|
+
Use mpirun or mpiexec to run a script
|
11
|
+
e.g. (run with 4 processes)
|
12
|
+
# mpirun -np 4 ruby hello.rb
|
8
13
|
|
9
14
|
== Contributing to Ruby-MPI
|
10
15
|
|
@@ -18,6 +23,6 @@ Ruby-MPI is a ruby binding of Message Passing Interface (MPI), which is an API s
|
|
18
23
|
|
19
24
|
== Copyright
|
20
25
|
|
21
|
-
Copyright (c) 2011 Seiya Nishizawa. See LICENSE.txt for
|
26
|
+
Copyright (c) 2011-2012 Seiya Nishizawa. See LICENSE.txt for
|
22
27
|
further details.
|
23
28
|
|
data/Rakefile
CHANGED
@@ -40,7 +40,7 @@ end
|
|
40
40
|
|
41
41
|
task :default => :spec
|
42
42
|
|
43
|
-
require '
|
43
|
+
require 'rdoc/task'
|
44
44
|
Rake::RDocTask.new do |rdoc|
|
45
45
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
46
|
|
@@ -48,6 +48,7 @@ Rake::RDocTask.new do |rdoc|
|
|
48
48
|
rdoc.title = "ruby-mpi #{version}"
|
49
49
|
rdoc.rdoc_files.include('README*')
|
50
50
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
rdoc.rdoc_files.include('samples/*.rb')
|
51
52
|
end
|
52
53
|
|
53
54
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/ext/mpi/extconf.rb
CHANGED
@@ -4,12 +4,20 @@ CONFIG['CC'] = "mpicc"
|
|
4
4
|
gem_path = nil
|
5
5
|
begin
|
6
6
|
require "rubygems"
|
7
|
-
if
|
8
|
-
|
7
|
+
if Gem::Specification.respond_to?(:find_by_name)
|
8
|
+
if spec = Gem::Specification.find_by_name("narray")
|
9
|
+
gem_path = spec.full_gem_path
|
10
|
+
end
|
11
|
+
else
|
12
|
+
if (spec = Gem.source_index.find_name("narray")).any?
|
13
|
+
gem_path = spec.full_gem_path
|
14
|
+
end
|
9
15
|
end
|
10
16
|
rescue LoadError
|
11
17
|
dir_config("narray", Config::CONFIG["sitearchdir"])
|
12
18
|
end
|
13
|
-
find_header("narray.h", gem_path)
|
19
|
+
unless find_header("narray.h", gem_path)
|
20
|
+
find_header("narray.h", File.join(gem_path,"src"))
|
21
|
+
end
|
14
22
|
|
15
23
|
create_makefile("mpi")
|
data/ext/mpi/mpi.c
CHANGED
@@ -6,38 +6,45 @@
|
|
6
6
|
#include "mpi.h"
|
7
7
|
|
8
8
|
|
9
|
-
#define OBJ2C(rb_obj, len, buffer, typ) \
|
9
|
+
#define OBJ2C(rb_obj, len, buffer, typ, off) \
|
10
10
|
{\
|
11
11
|
if (TYPE(rb_obj) == T_STRING) {\
|
12
|
-
len = RSTRING_LEN(rb_obj);\
|
13
|
-
buffer = (void*)StringValuePtr(rb_obj);\
|
14
|
-
typ =
|
15
|
-
} else if (IsNArray(rb_obj)) {
|
12
|
+
if (len==0) len = RSTRING_LEN(rb_obj);\
|
13
|
+
buffer = (void*)(StringValuePtr(rb_obj) + off);\
|
14
|
+
typ = MPI_BYTE;\
|
15
|
+
} else if (IsNArray(rb_obj)) {\
|
16
16
|
struct NARRAY *a;\
|
17
17
|
GetNArray(rb_obj, a);\
|
18
18
|
buffer = (void*)(a->ptr);\
|
19
|
-
len = a->total;\
|
19
|
+
if (len==0) len = a->total;\
|
20
20
|
switch (a->type) {\
|
21
21
|
case NA_BYTE:\
|
22
22
|
typ = MPI_BYTE;\
|
23
|
+
buffer = (void*)((char*)buffer + off);\
|
23
24
|
break;\
|
24
25
|
case NA_SINT:\
|
25
26
|
typ = MPI_SHORT;\
|
27
|
+
buffer = (void*)((char*)buffer + off*4);\
|
26
28
|
break;\
|
27
29
|
case NA_LINT:\
|
28
30
|
typ = MPI_LONG;\
|
31
|
+
buffer = (void*)((char*)buffer + off*8);\
|
29
32
|
break;\
|
30
33
|
case NA_SFLOAT:\
|
31
34
|
typ = MPI_FLOAT;\
|
35
|
+
buffer = (void*)((char*)buffer + off*4);\
|
32
36
|
break;\
|
33
37
|
case NA_DFLOAT:\
|
34
38
|
typ = MPI_DOUBLE;\
|
39
|
+
buffer = (void*)((char*)buffer + off*8);\
|
35
40
|
break;\
|
36
41
|
case NA_SCOMPLEX:\
|
37
42
|
typ = MPI_2COMPLEX;\
|
43
|
+
buffer = (void*)((char*)buffer + off*8);\
|
38
44
|
break;\
|
39
45
|
case NA_DCOMPLEX:\
|
40
46
|
typ = MPI_2DOUBLE_COMPLEX;\
|
47
|
+
buffer = (void*)((char*)buffer + off*16);\
|
41
48
|
break;\
|
42
49
|
default:\
|
43
50
|
rb_raise(rb_eArgError, "narray type is invalid");\
|
@@ -54,48 +61,36 @@ static VALUE eBUFFER, eCOUNT, eTYPE, eTAG, eCOMM, eRANK, eREQUEST, eROOT, eGROUP
|
|
54
61
|
|
55
62
|
struct _Comm {
|
56
63
|
MPI_Comm Comm;
|
64
|
+
bool free;
|
57
65
|
};
|
58
66
|
struct _Request {
|
59
67
|
MPI_Request Request;
|
68
|
+
bool free;
|
60
69
|
};
|
61
70
|
struct _Op {
|
62
71
|
MPI_Op Op;
|
72
|
+
bool free;
|
63
73
|
};
|
64
74
|
struct _Errhandler {
|
65
75
|
MPI_Errhandler Errhandler;
|
76
|
+
bool free;
|
66
77
|
};
|
67
78
|
|
68
79
|
static bool _initialized = false;
|
69
80
|
static bool _finalized = false;
|
70
81
|
|
71
82
|
|
72
|
-
#define
|
73
|
-
static void \
|
74
|
-
name ## _free(void *ptr)\
|
75
|
-
{\
|
76
|
-
struct _ ## name *obj;\
|
77
|
-
obj = (struct _ ## name*) ptr;\
|
78
|
-
if (!_finalized)\
|
79
|
-
MPI_ ## name ## _free(&(obj->name)); \
|
80
|
-
free(obj);\
|
81
|
-
}
|
82
|
-
DEF_FREE(Comm)
|
83
|
-
DEF_FREE(Request)
|
84
|
-
DEF_FREE(Op)
|
85
|
-
DEF_FREE(Errhandler)
|
86
|
-
static void
|
87
|
-
Status_free(void *ptr)
|
88
|
-
{
|
89
|
-
free((MPI_Status*) ptr);
|
90
|
-
}
|
91
|
-
|
92
|
-
|
93
|
-
#define CAE_ERR(type) case MPI_ERR_ ## type: rb_raise(e ## type,""); break
|
83
|
+
#define CAE_ERR(type) case MPI_ERR_ ## type: rb_raise(e ## type,"%s",str); break
|
94
84
|
static void
|
95
85
|
check_error(int error)
|
96
86
|
{
|
97
|
-
|
98
|
-
|
87
|
+
if (error == MPI_SUCCESS) return;
|
88
|
+
int code, len;
|
89
|
+
char str[MPI_MAX_ERROR_STRING];
|
90
|
+
if (MPI_Error_class(error, &code)!=MPI_SUCCESS || MPI_Error_string(error, str, &len)!=MPI_SUCCESS)
|
91
|
+
rb_raise(rb_eRuntimeError, "unknown error occuerd in MPI call");
|
92
|
+
|
93
|
+
switch (code) {
|
99
94
|
CAE_ERR(BUFFER);
|
100
95
|
CAE_ERR(COUNT);
|
101
96
|
CAE_ERR(TYPE);
|
@@ -154,15 +149,48 @@ check_error(int error)
|
|
154
149
|
CAE_ERR(SYSRESOURCE);
|
155
150
|
#endif
|
156
151
|
default:
|
157
|
-
rb_raise(rb_eRuntimeError, "unknown error");
|
152
|
+
rb_raise(rb_eRuntimeError, "unknown error: %d", code);
|
158
153
|
}
|
159
154
|
}
|
160
155
|
|
156
|
+
#define DEF_FREE(name, capit) \
|
157
|
+
static void \
|
158
|
+
name ## _free(void *ptr)\
|
159
|
+
{\
|
160
|
+
struct _ ## name *obj;\
|
161
|
+
obj = (struct _ ## name*) ptr;\
|
162
|
+
if (!_finalized && obj->free && obj->name!=MPI_ ## capit ##_NULL)\
|
163
|
+
check_error(MPI_ ## name ## _free(&(obj->name))); \
|
164
|
+
free(obj);\
|
165
|
+
}
|
166
|
+
#define DEF_FREE2(name, capit) \
|
167
|
+
static void \
|
168
|
+
name ## _free2(void *ptr)\
|
169
|
+
{\
|
170
|
+
struct _ ## name *obj;\
|
171
|
+
obj = (struct _ ## name*) ptr;\
|
172
|
+
free(obj);\
|
173
|
+
}
|
174
|
+
DEF_FREE(Comm, COMM)
|
175
|
+
DEF_FREE(Request, REQUEST)
|
176
|
+
DEF_FREE(Op, OP)
|
177
|
+
DEF_FREE(Errhandler, ERRHANDLER)
|
178
|
+
DEF_FREE2(Comm, COMM)
|
179
|
+
DEF_FREE2(Op, OP)
|
180
|
+
DEF_FREE2(Errhandler, ERRHANDLER)
|
181
|
+
static void
|
182
|
+
Status_free(void *ptr)
|
183
|
+
{
|
184
|
+
free((MPI_Status*) ptr);
|
185
|
+
}
|
186
|
+
|
187
|
+
|
161
188
|
#define DEF_CONST(v, const, name) \
|
162
189
|
{\
|
163
190
|
v = ALLOC(struct _ ## v);\
|
164
191
|
v->v = const;\
|
165
|
-
|
192
|
+
v->free = false;\
|
193
|
+
rb_define_const(c ## v, #name, Data_Wrap_Struct(c ## v, NULL, v ## _free2, v)); \
|
166
194
|
}
|
167
195
|
|
168
196
|
static void
|
@@ -216,7 +244,7 @@ rb_m_init(int argc, VALUE *argv, VALUE self)
|
|
216
244
|
// define MPI::Comm::WORLD
|
217
245
|
struct _Comm *Comm;
|
218
246
|
DEF_CONST(Comm, MPI_COMM_WORLD, WORLD);
|
219
|
-
MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
|
247
|
+
check_error(MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN));
|
220
248
|
|
221
249
|
// define MPI::Op::???
|
222
250
|
struct _Op *Op;
|
@@ -249,6 +277,16 @@ rb_m_finalize(VALUE self)
|
|
249
277
|
return self;
|
250
278
|
}
|
251
279
|
|
280
|
+
static VALUE
|
281
|
+
rb_m_abort(VALUE self, VALUE rcomm, VALUE rerror)
|
282
|
+
{
|
283
|
+
struct _Comm *comm;
|
284
|
+
int ierror;
|
285
|
+
Data_Get_Struct(rcomm, struct _Comm, comm);
|
286
|
+
ierror = MPI_Abort(comm->Comm, NUM2INT(rerror));
|
287
|
+
return INT2NUM(ierror);
|
288
|
+
}
|
289
|
+
|
252
290
|
|
253
291
|
// MPI::Comm
|
254
292
|
static VALUE
|
@@ -262,6 +300,7 @@ rb_comm_initialize(VALUE self)
|
|
262
300
|
{
|
263
301
|
rb_raise(rb_eRuntimeError, "not developed yet");
|
264
302
|
// MPI_Comm_create()
|
303
|
+
// comm->free = true;
|
265
304
|
}
|
266
305
|
static VALUE
|
267
306
|
rb_comm_size(VALUE self)
|
@@ -285,11 +324,11 @@ static VALUE
|
|
285
324
|
rb_comm_send(VALUE self, VALUE rb_obj, VALUE rb_dest, VALUE rb_tag)
|
286
325
|
{
|
287
326
|
void* buffer;
|
288
|
-
int len, dest, tag;
|
327
|
+
int len=0, dest, tag;
|
289
328
|
MPI_Datatype type;
|
290
329
|
struct _Comm *comm;
|
291
330
|
|
292
|
-
OBJ2C(rb_obj, len, buffer, type);
|
331
|
+
OBJ2C(rb_obj, len, buffer, type, 0);
|
293
332
|
dest = NUM2INT(rb_dest);
|
294
333
|
tag = NUM2INT(rb_tag);
|
295
334
|
Data_Get_Struct(self, struct _Comm, comm);
|
@@ -301,31 +340,43 @@ static VALUE
|
|
301
340
|
rb_comm_isend(VALUE self, VALUE rb_obj, VALUE rb_dest, VALUE rb_tag)
|
302
341
|
{
|
303
342
|
void* buffer;
|
304
|
-
int len, dest, tag;
|
343
|
+
int len=0, dest, tag;
|
305
344
|
MPI_Datatype type;
|
306
345
|
struct _Comm *comm;
|
307
346
|
struct _Request *request;
|
308
347
|
VALUE rb_request;
|
309
348
|
|
310
|
-
OBJ2C(rb_obj, len, buffer, type);
|
349
|
+
OBJ2C(rb_obj, len, buffer, type, 0);
|
311
350
|
dest = NUM2INT(rb_dest);
|
312
351
|
tag = NUM2INT(rb_tag);
|
313
352
|
Data_Get_Struct(self, struct _Comm, comm);
|
314
353
|
rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request);
|
354
|
+
request->free = true;
|
315
355
|
check_error(MPI_Isend(buffer, len, type, dest, tag, comm->Comm, &(request->Request)));
|
316
356
|
|
317
357
|
return rb_request;
|
318
358
|
}
|
319
359
|
static VALUE
|
320
|
-
rb_comm_recv(
|
360
|
+
rb_comm_recv(int argc, VALUE *argv, VALUE self)
|
321
361
|
{
|
362
|
+
VALUE rb_obj, rb_source, rb_tag;
|
363
|
+
VALUE rb_len, rb_offset; // option
|
322
364
|
void* buffer;
|
323
|
-
int
|
365
|
+
int source, tag, len = 0, offset = 0;
|
324
366
|
MPI_Datatype type;
|
325
367
|
MPI_Status *status;
|
326
368
|
struct _Comm *comm;
|
327
369
|
|
328
|
-
|
370
|
+
rb_scan_args(argc, argv, "32", &rb_obj, &rb_source, &rb_tag, &rb_len, &rb_offset);
|
371
|
+
|
372
|
+
if (rb_len != Qnil) {
|
373
|
+
len = NUM2INT(rb_len);
|
374
|
+
}
|
375
|
+
if (rb_offset != Qnil) {
|
376
|
+
offset = NUM2INT(rb_offset);
|
377
|
+
}
|
378
|
+
|
379
|
+
OBJ2C(rb_obj, len, buffer, type, offset);
|
329
380
|
source = NUM2INT(rb_source);
|
330
381
|
tag = NUM2INT(rb_tag);
|
331
382
|
|
@@ -336,20 +387,33 @@ rb_comm_recv(VALUE self, VALUE rb_obj, VALUE rb_source, VALUE rb_tag)
|
|
336
387
|
return Data_Wrap_Struct(cStatus, NULL, Status_free, status);
|
337
388
|
}
|
338
389
|
static VALUE
|
339
|
-
rb_comm_irecv(
|
390
|
+
rb_comm_irecv(int argc, VALUE *argv, VALUE self)
|
340
391
|
{
|
392
|
+
VALUE rb_obj, rb_source, rb_tag;
|
393
|
+
VALUE rb_len, rb_offset; // option
|
341
394
|
void* buffer;
|
342
|
-
int
|
395
|
+
int source, tag, len = 0, offset = 0;
|
343
396
|
MPI_Datatype type;
|
344
397
|
struct _Comm *comm;
|
345
398
|
struct _Request *request;
|
346
399
|
VALUE rb_request;
|
347
400
|
|
348
|
-
|
401
|
+
rb_scan_args(argc, argv, "32", &rb_obj, &rb_source, &rb_tag, &rb_len, &rb_offset);
|
402
|
+
|
403
|
+
if (rb_len != Qnil) {
|
404
|
+
len = NUM2INT(rb_len);
|
405
|
+
}
|
406
|
+
if (rb_offset != Qnil) {
|
407
|
+
offset = NUM2INT(rb_offset);
|
408
|
+
}
|
409
|
+
|
410
|
+
OBJ2C(rb_obj, len, buffer, type, offset);
|
349
411
|
source = NUM2INT(rb_source);
|
350
412
|
tag = NUM2INT(rb_tag);
|
413
|
+
|
351
414
|
Data_Get_Struct(self, struct _Comm, comm);
|
352
415
|
rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request);
|
416
|
+
request->free = true;
|
353
417
|
check_error(MPI_Irecv(buffer, len, type, source, tag, comm->Comm, &(request->Request)));
|
354
418
|
|
355
419
|
return rb_request;
|
@@ -358,17 +422,17 @@ static VALUE
|
|
358
422
|
rb_comm_gather(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_root)
|
359
423
|
{
|
360
424
|
void *sendbuf, *recvbuf = NULL;
|
361
|
-
int sendcount, recvcount = 0;
|
362
|
-
MPI_Datatype sendtype, recvtype =
|
425
|
+
int sendcount=0, recvcount = 0;
|
426
|
+
MPI_Datatype sendtype, recvtype = 0;
|
363
427
|
int root, rank, size;
|
364
428
|
struct _Comm *comm;
|
365
|
-
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype);
|
429
|
+
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0);
|
366
430
|
root = NUM2INT(rb_root);
|
367
431
|
Data_Get_Struct(self, struct _Comm, comm);
|
368
432
|
check_error(MPI_Comm_rank(comm->Comm, &rank));
|
369
433
|
check_error(MPI_Comm_size(comm->Comm, &size));
|
370
434
|
if (rank == root) {
|
371
|
-
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype);
|
435
|
+
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0);
|
372
436
|
if (recvcount < sendcount*size)
|
373
437
|
rb_raise(rb_eArgError, "recvbuf is too small");
|
374
438
|
recvcount = sendcount;
|
@@ -380,15 +444,15 @@ static VALUE
|
|
380
444
|
rb_comm_allgather(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf)
|
381
445
|
{
|
382
446
|
void *sendbuf, *recvbuf;
|
383
|
-
int sendcount, recvcount;
|
447
|
+
int sendcount=0, recvcount=0;
|
384
448
|
MPI_Datatype sendtype, recvtype;
|
385
449
|
int rank, size;
|
386
450
|
struct _Comm *comm;
|
387
|
-
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype);
|
451
|
+
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0);
|
388
452
|
Data_Get_Struct(self, struct _Comm, comm);
|
389
453
|
check_error(MPI_Comm_rank(comm->Comm, &rank));
|
390
454
|
check_error(MPI_Comm_size(comm->Comm, &size));
|
391
|
-
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype);
|
455
|
+
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0);
|
392
456
|
if (recvcount < sendcount*size)
|
393
457
|
rb_raise(rb_eArgError, "recvbuf is too small");
|
394
458
|
recvcount = sendcount;
|
@@ -399,11 +463,11 @@ static VALUE
|
|
399
463
|
rb_comm_bcast(VALUE self, VALUE rb_buffer, VALUE rb_root)
|
400
464
|
{
|
401
465
|
void *buffer;
|
402
|
-
int count;
|
466
|
+
int count=0;
|
403
467
|
MPI_Datatype type;
|
404
468
|
int root;
|
405
469
|
struct _Comm *comm;
|
406
|
-
OBJ2C(rb_buffer, count, buffer, type);
|
470
|
+
OBJ2C(rb_buffer, count, buffer, type, 0);
|
407
471
|
root = NUM2INT(rb_root);
|
408
472
|
Data_Get_Struct(self, struct _Comm, comm);
|
409
473
|
check_error(MPI_Bcast(buffer, count, type, root, comm->Comm));
|
@@ -413,17 +477,17 @@ static VALUE
|
|
413
477
|
rb_comm_scatter(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_root)
|
414
478
|
{
|
415
479
|
void *sendbuf = NULL, *recvbuf;
|
416
|
-
int sendcount = 0, recvcount;
|
417
|
-
MPI_Datatype sendtype =
|
480
|
+
int sendcount = 0, recvcount=0;
|
481
|
+
MPI_Datatype sendtype = 0, recvtype;
|
418
482
|
int root, rank, size;
|
419
483
|
struct _Comm *comm;
|
420
|
-
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype);
|
484
|
+
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0);
|
421
485
|
root = NUM2INT(rb_root);
|
422
486
|
Data_Get_Struct(self, struct _Comm, comm);
|
423
487
|
check_error(MPI_Comm_rank(comm->Comm, &rank));
|
424
488
|
check_error(MPI_Comm_size(comm->Comm, &size));
|
425
489
|
if (rank == root) {
|
426
|
-
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype);
|
490
|
+
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0);
|
427
491
|
if (sendcount > recvcount*size)
|
428
492
|
rb_raise(rb_eArgError, "recvbuf is too small");
|
429
493
|
sendcount = recvcount;
|
@@ -435,17 +499,17 @@ static VALUE
|
|
435
499
|
rb_comm_sendrecv(VALUE self, VALUE rb_sendbuf, VALUE rb_dest, VALUE rb_sendtag, VALUE rb_recvbuf, VALUE rb_source, VALUE rb_recvtag)
|
436
500
|
{
|
437
501
|
void *sendbuf, *recvbuf;
|
438
|
-
int sendcount, recvcount;
|
502
|
+
int sendcount=0, recvcount=0;
|
439
503
|
MPI_Datatype sendtype, recvtype;
|
440
504
|
int dest, source;
|
441
505
|
int sendtag, recvtag;
|
442
506
|
int size;
|
443
507
|
struct _Comm *comm;
|
444
508
|
MPI_Status *status;
|
445
|
-
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype);
|
509
|
+
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0);
|
446
510
|
Data_Get_Struct(self, struct _Comm, comm);
|
447
511
|
check_error(MPI_Comm_size(comm->Comm, &size));
|
448
|
-
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype);
|
512
|
+
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0);
|
449
513
|
dest = NUM2INT(rb_dest);
|
450
514
|
source = NUM2INT(rb_source);
|
451
515
|
sendtag = NUM2INT(rb_sendtag);
|
@@ -458,14 +522,14 @@ static VALUE
|
|
458
522
|
rb_comm_alltoall(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf)
|
459
523
|
{
|
460
524
|
void *sendbuf, *recvbuf;
|
461
|
-
int sendcount, recvcount;
|
525
|
+
int sendcount=0, recvcount=0;
|
462
526
|
MPI_Datatype sendtype, recvtype;
|
463
527
|
int size;
|
464
528
|
struct _Comm *comm;
|
465
|
-
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype);
|
529
|
+
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0);
|
466
530
|
Data_Get_Struct(self, struct _Comm, comm);
|
467
531
|
check_error(MPI_Comm_size(comm->Comm, &size));
|
468
|
-
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype);
|
532
|
+
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0);
|
469
533
|
if (recvcount < sendcount)
|
470
534
|
rb_raise(rb_eArgError, "recvbuf is too small");
|
471
535
|
recvcount = recvcount/size;
|
@@ -477,18 +541,18 @@ static VALUE
|
|
477
541
|
rb_comm_reduce(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op, VALUE rb_root)
|
478
542
|
{
|
479
543
|
void *sendbuf, *recvbuf = NULL;
|
480
|
-
int sendcount, recvcount = 0;
|
481
|
-
MPI_Datatype sendtype, recvtype =
|
544
|
+
int sendcount=0, recvcount = 0;
|
545
|
+
MPI_Datatype sendtype, recvtype = 0;
|
482
546
|
int root, rank, size;
|
483
547
|
struct _Comm *comm;
|
484
548
|
struct _Op *op;
|
485
|
-
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype);
|
549
|
+
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0);
|
486
550
|
root = NUM2INT(rb_root);
|
487
551
|
Data_Get_Struct(self, struct _Comm, comm);
|
488
552
|
check_error(MPI_Comm_rank(comm->Comm, &rank));
|
489
553
|
check_error(MPI_Comm_size(comm->Comm, &size));
|
490
554
|
if (rank == root) {
|
491
|
-
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype);
|
555
|
+
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0);
|
492
556
|
if (recvcount != sendcount)
|
493
557
|
rb_raise(rb_eArgError, "sendbuf and recvbuf has the same length");
|
494
558
|
if (recvtype != sendtype)
|
@@ -502,16 +566,16 @@ static VALUE
|
|
502
566
|
rb_comm_allreduce(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op)
|
503
567
|
{
|
504
568
|
void *sendbuf, *recvbuf;
|
505
|
-
int sendcount, recvcount;
|
569
|
+
int sendcount=0, recvcount=0;
|
506
570
|
MPI_Datatype sendtype, recvtype;
|
507
571
|
int rank, size;
|
508
572
|
struct _Comm *comm;
|
509
573
|
struct _Op *op;
|
510
|
-
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype);
|
574
|
+
OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0);
|
511
575
|
Data_Get_Struct(self, struct _Comm, comm);
|
512
576
|
check_error(MPI_Comm_rank(comm->Comm, &rank));
|
513
577
|
check_error(MPI_Comm_size(comm->Comm, &size));
|
514
|
-
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype);
|
578
|
+
OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0);
|
515
579
|
if (recvcount != sendcount)
|
516
580
|
rb_raise(rb_eArgError, "sendbuf and recvbuf has the same length");
|
517
581
|
if (recvtype != sendtype)
|
@@ -529,7 +593,8 @@ rb_comm_get_Errhandler(VALUE self)
|
|
529
593
|
|
530
594
|
Data_Get_Struct(self, struct _Comm, comm);
|
531
595
|
rb_errhandler = Data_Make_Struct(cErrhandler, struct _Errhandler, NULL, Errhandler_free, errhandler);
|
532
|
-
|
596
|
+
errhandler->free = false;
|
597
|
+
check_error(MPI_Comm_get_errhandler(comm->Comm, &(errhandler->Errhandler)));
|
533
598
|
return rb_errhandler;
|
534
599
|
}
|
535
600
|
static VALUE
|
@@ -540,7 +605,7 @@ rb_comm_set_Errhandler(VALUE self, VALUE rb_errhandler)
|
|
540
605
|
|
541
606
|
Data_Get_Struct(self, struct _Comm, comm);
|
542
607
|
Data_Get_Struct(rb_errhandler, struct _Errhandler, errhandler);
|
543
|
-
MPI_Comm_set_errhandler(comm->Comm, errhandler->Errhandler);
|
608
|
+
check_error(MPI_Comm_set_errhandler(comm->Comm, errhandler->Errhandler));
|
544
609
|
return self;
|
545
610
|
}
|
546
611
|
static VALUE
|
@@ -607,6 +672,7 @@ void Init_mpi()
|
|
607
672
|
mMPI = rb_define_module("MPI");
|
608
673
|
rb_define_module_function(mMPI, "Init", rb_m_init, -1);
|
609
674
|
rb_define_module_function(mMPI, "Finalize", rb_m_finalize, -1);
|
675
|
+
rb_define_module_function(mMPI, "Abort", rb_m_abort, 2);
|
610
676
|
rb_define_const(mMPI, "VERSION", INT2NUM(MPI_VERSION));
|
611
677
|
rb_define_const(mMPI, "SUBVERSION", INT2NUM(MPI_SUBVERSION));
|
612
678
|
rb_define_const(mMPI, "SUCCESS", INT2NUM(MPI_SUCCESS));
|
@@ -620,8 +686,8 @@ void Init_mpi()
|
|
620
686
|
rb_define_method(cComm, "size", rb_comm_size, 0);
|
621
687
|
rb_define_method(cComm, "Send", rb_comm_send, 3);
|
622
688
|
rb_define_method(cComm, "Isend", rb_comm_isend, 3);
|
623
|
-
rb_define_method(cComm, "Recv", rb_comm_recv,
|
624
|
-
rb_define_method(cComm, "Irecv", rb_comm_irecv,
|
689
|
+
rb_define_method(cComm, "Recv", rb_comm_recv, -1);
|
690
|
+
rb_define_method(cComm, "Irecv", rb_comm_irecv, -1);
|
625
691
|
rb_define_method(cComm, "Gather", rb_comm_gather, 3);
|
626
692
|
rb_define_method(cComm, "Allgather", rb_comm_allgather, 2);
|
627
693
|
rb_define_method(cComm, "Bcast", rb_comm_bcast, 2);
|
data/lib/mpi/utils.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module MPI
|
2
|
+
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def task_divide(m, size)
|
6
|
+
dm = m.to_f/size
|
7
|
+
ary = Array.new(size)
|
8
|
+
ary[0] = dm.round
|
9
|
+
sum = ary[0]
|
10
|
+
(size-1).times do|i|
|
11
|
+
ary[i+1] = (dm*(i+2)).round - sum
|
12
|
+
sum += ary[i+1]
|
13
|
+
end
|
14
|
+
ary
|
15
|
+
end
|
16
|
+
|
17
|
+
end # module MPI
|
data/samples/hello.rb
CHANGED
@@ -4,13 +4,19 @@ MPI.Init
|
|
4
4
|
|
5
5
|
|
6
6
|
world = MPI::Comm::WORLD
|
7
|
+
|
8
|
+
if world.size == 1
|
9
|
+
print "Size is one, so do nothing\n"
|
10
|
+
exit
|
11
|
+
end
|
12
|
+
|
7
13
|
rank = world.rank
|
8
14
|
|
9
15
|
if rank == 0
|
10
16
|
(world.size-1).times do |i|
|
11
17
|
str ="\x00"*100
|
12
18
|
world.Recv(str, i+1, 0)
|
13
|
-
p str
|
19
|
+
p str.gsub(/\000/,"")
|
14
20
|
end
|
15
21
|
else
|
16
22
|
message = "Hello from #{rank}"
|
data/samples/narray.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "mpi"
|
2
|
+
|
3
|
+
MPI.Init
|
4
|
+
|
5
|
+
|
6
|
+
world = MPI::Comm::WORLD
|
7
|
+
|
8
|
+
if world.size == 1
|
9
|
+
print "Size is one, so do nothing\n"
|
10
|
+
exit
|
11
|
+
end
|
12
|
+
|
13
|
+
rank = world.rank
|
14
|
+
size = world.size
|
15
|
+
|
16
|
+
length = 2
|
17
|
+
if rank == 0
|
18
|
+
a = NArray.float(length,size-1)
|
19
|
+
(size-1).times do |i|
|
20
|
+
world.Recv(a, i+1, 1, length, i*length)
|
21
|
+
end
|
22
|
+
p a
|
23
|
+
else
|
24
|
+
a = NArray.float(length).indgen + rank*10
|
25
|
+
world.Send(a, 0, 1)
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
MPI.Finalize
|
data/spec/ruby-mpi_spec.rb
CHANGED
@@ -34,14 +34,13 @@ describe "MPI" do
|
|
34
34
|
status = @world.Recv(str, i+1, tag)
|
35
35
|
status.source.should eql(i+1)
|
36
36
|
status.tag.should eql(tag)
|
37
|
-
status.error.should eq(MPI::SUCCESS)
|
38
37
|
str.should match(/\AHello from #{i+1}/)
|
39
38
|
end
|
40
39
|
end
|
41
40
|
end
|
42
41
|
|
43
42
|
it "should send and receive NArray" do
|
44
|
-
tag =
|
43
|
+
tag = 1
|
45
44
|
rank = @world.rank
|
46
45
|
[NArray[1,2,3], NArray[3.0,2.0,1.0]].each do |ary0|
|
47
46
|
ary0 = NArray[1,2,3]
|
@@ -52,7 +51,6 @@ describe "MPI" do
|
|
52
51
|
status = @world.Recv(ary1, i+1, tag)
|
53
52
|
status.source.should eql(i+1)
|
54
53
|
status.tag.should eql(tag)
|
55
|
-
status.error.should eq(MPI::SUCCESS)
|
56
54
|
ary1.should == ary0
|
57
55
|
end
|
58
56
|
end
|
@@ -60,14 +58,12 @@ describe "MPI" do
|
|
60
58
|
end
|
61
59
|
|
62
60
|
it "should send and receive without blocking" do
|
63
|
-
tag =
|
61
|
+
tag = 2
|
64
62
|
rank = @world.rank
|
65
63
|
message = "Hello from #{rank}"
|
66
64
|
if rank != 0
|
67
65
|
request = @world.Isend(message, 0, tag)
|
68
66
|
status = request.Wait
|
69
|
-
# status.source.should eql(rank)
|
70
|
-
status.tag.should eql(tag)
|
71
67
|
end
|
72
68
|
if rank == 0
|
73
69
|
(@world.size-1).times do |i|
|
data/test/test_utils.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
4
|
+
require "mpi/utils"
|
5
|
+
|
6
|
+
class TestMPIUtils < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_task_divide
|
15
|
+
[[4,1], [6,3], [7,3], [15,4], [3, 7]].each do |m, size|
|
16
|
+
ary = MPI.task_divide(m, size)
|
17
|
+
assert ary.max-ary.min <= 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
metadata
CHANGED
@@ -1,86 +1,98 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-mpi
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.2.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
6
5
|
platform: ruby
|
7
|
-
authors:
|
6
|
+
authors:
|
8
7
|
- Seiya Nishizawa
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2014-05-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
16
14
|
name: rspec
|
17
|
-
requirement:
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
- !ruby/object:Gem::Version
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
22
19
|
version: 2.3.0
|
23
20
|
type: :development
|
24
21
|
prerelease: false
|
25
|
-
version_requirements:
|
26
|
-
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.3.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
27
28
|
name: bundler
|
28
|
-
requirement:
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
- !ruby/object:Gem::Version
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
33
|
version: 1.0.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements:
|
37
|
-
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
38
42
|
name: jeweler
|
39
|
-
requirement:
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
- !ruby/object:Gem::Version
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
44
47
|
version: 1.5.2
|
45
48
|
type: :development
|
46
49
|
prerelease: false
|
47
|
-
version_requirements:
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.5.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
56
62
|
type: :development
|
57
63
|
prerelease: false
|
58
|
-
version_requirements:
|
59
|
-
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
60
70
|
name: narray
|
61
|
-
requirement:
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
version: "0"
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
67
76
|
type: :development
|
68
77
|
prerelease: false
|
69
|
-
version_requirements:
|
70
|
-
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: A ruby binding of Message Passing Interface (MPI), which is an API specification
|
84
|
+
that allows processes to communicate with one another by sending and receiving messages.
|
71
85
|
email: seiya@gfd-dennou.org
|
72
86
|
executables: []
|
73
|
-
|
74
|
-
extensions:
|
87
|
+
extensions:
|
75
88
|
- ext/mpi/extconf.rb
|
76
|
-
extra_rdoc_files:
|
89
|
+
extra_rdoc_files:
|
77
90
|
- LICENSE.txt
|
78
91
|
- README.rdoc
|
79
|
-
files:
|
92
|
+
files:
|
80
93
|
- .document
|
81
94
|
- .rspec
|
82
95
|
- Gemfile
|
83
|
-
- Gemfile.lock
|
84
96
|
- LICENSE.txt
|
85
97
|
- README.rdoc
|
86
98
|
- Rakefile
|
@@ -88,41 +100,36 @@ files:
|
|
88
100
|
- ext/mpi/extconf.rb
|
89
101
|
- ext/mpi/mpi.c
|
90
102
|
- lib/mpi.rb
|
103
|
+
- lib/mpi/utils.rb
|
91
104
|
- ruby-mpi.gemspec
|
92
105
|
- samples/hello.rb
|
93
106
|
- samples/narray.rb
|
107
|
+
- samples/narray_offset.rb
|
94
108
|
- spec/ruby-mpi_spec.rb
|
95
109
|
- spec/spec_helper.rb
|
110
|
+
- test/test_utils.rb
|
96
111
|
homepage: http://github.com/seiya/ruby-mpi
|
97
|
-
licenses:
|
112
|
+
licenses:
|
98
113
|
- MIT
|
114
|
+
metadata: {}
|
99
115
|
post_install_message:
|
100
116
|
rdoc_options: []
|
101
|
-
|
102
|
-
require_paths:
|
117
|
+
require_paths:
|
103
118
|
- lib
|
104
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
none: false
|
115
|
-
requirements:
|
116
|
-
- - ">="
|
117
|
-
- !ruby/object:Gem::Version
|
118
|
-
version: "0"
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
119
129
|
requirements: []
|
120
|
-
|
121
130
|
rubyforge_project:
|
122
|
-
rubygems_version: 1.
|
131
|
+
rubygems_version: 2.1.11
|
123
132
|
signing_key:
|
124
|
-
specification_version:
|
133
|
+
specification_version: 4
|
125
134
|
summary: A ruby binding of MPI
|
126
|
-
test_files:
|
127
|
-
- spec/ruby-mpi_spec.rb
|
128
|
-
- spec/spec_helper.rb
|
135
|
+
test_files: []
|
data/Gemfile.lock
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
GEM
|
2
|
-
remote: http://rubygems.org/
|
3
|
-
specs:
|
4
|
-
diff-lcs (1.1.2)
|
5
|
-
git (1.2.5)
|
6
|
-
jeweler (1.5.2)
|
7
|
-
bundler (~> 1.0.0)
|
8
|
-
git (>= 1.2.5)
|
9
|
-
rake
|
10
|
-
narray (0.5.9.9)
|
11
|
-
rake (0.8.7)
|
12
|
-
rcov (0.9.9)
|
13
|
-
rspec (2.3.0)
|
14
|
-
rspec-core (~> 2.3.0)
|
15
|
-
rspec-expectations (~> 2.3.0)
|
16
|
-
rspec-mocks (~> 2.3.0)
|
17
|
-
rspec-core (2.3.1)
|
18
|
-
rspec-expectations (2.3.0)
|
19
|
-
diff-lcs (~> 1.1.2)
|
20
|
-
rspec-mocks (2.3.0)
|
21
|
-
|
22
|
-
PLATFORMS
|
23
|
-
ruby
|
24
|
-
|
25
|
-
DEPENDENCIES
|
26
|
-
bundler (~> 1.0.0)
|
27
|
-
jeweler (~> 1.5.2)
|
28
|
-
narray
|
29
|
-
rcov
|
30
|
-
rspec (~> 2.3.0)
|