├── .rspec ├── VERSION ├── .document ├── lib ├── mpi.rb └── mpi │ └── utils.rb ├── test └── test_utils.rb ├── samples ├── hello.rb ├── narray.rb ├── narray_offset.rb ├── pi.rb └── kmeans.rb ├── Gemfile ├── spec ├── spec_helper.rb └── ruby-mpi_spec.rb ├── .travis.yml ├── ext └── mpi │ ├── extconf.rb │ └── mpi.c ├── .gitignore ├── LICENSE.txt ├── README.rdoc ├── Rakefile └── ruby-mpi.gemspec /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.4.0 2 | -------------------------------------------------------------------------------- /.document: -------------------------------------------------------------------------------- 1 | lib/**/*.rb 2 | bin/* 3 | - 4 | features/**/*.feature 5 | LICENSE.txt 6 | -------------------------------------------------------------------------------- /lib/mpi.rb: -------------------------------------------------------------------------------- 1 | begin 2 | require "rubygems" 3 | rescue LoadError 4 | end 5 | begin 6 | require "numru/narray" 7 | rescue LoadError 8 | err = $! 9 | begin 10 | require "narray" 11 | rescue LoadError 12 | STDERR.puts "You should install numru-narray or narray to use ruby-mpi" 13 | raise err 14 | end 15 | end 16 | require "mpi.so" 17 | -------------------------------------------------------------------------------- /lib/mpi/utils.rb: -------------------------------------------------------------------------------- 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 18 | -------------------------------------------------------------------------------- /test/test_utils.rb: -------------------------------------------------------------------------------- 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 22 | -------------------------------------------------------------------------------- /samples/hello.rb: -------------------------------------------------------------------------------- 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 | 15 | if rank == 0 16 | (world.size-1).times do |i| 17 | str ="\x00"*100 18 | world.Recv(str, i+1, 0) 19 | p str.gsub(/\000/,"") 20 | end 21 | else 22 | message = "Hello from #{rank}" 23 | world.Send(message, 0, 0) 24 | end 25 | 26 | 27 | MPI.Finalize 28 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | # Add dependencies required to use your gem here. 3 | # Example: 4 | # gem "activesupport", ">= 2.3.5" 5 | gem "numru-narray", "~> 1.0" 6 | 7 | # Add dependencies to develop your gem here. 8 | # Include everything needed to run rake, tests, features, etc. 9 | group :development do 10 | gem "rspec", ">= 2.3.0" 11 | gem "bundler", ">= 1.0.0" 12 | gem "jeweler", ">= 1.5.2" 13 | gem "simplecov", ">= 0" 14 | gem "rake-compiler", ">= 0" 15 | end 16 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'ext', 'mpi')) 2 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) 3 | $LOAD_PATH.unshift(File.dirname(__FILE__)) 4 | require 'rspec' 5 | require 'mpi' 6 | 7 | # Requires supporting files with custom matchers and macros, etc, 8 | # in ./support/ and its subdirectories. 9 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f} 10 | 11 | RSpec.configure do |config| 12 | 13 | end 14 | -------------------------------------------------------------------------------- /samples/narray.rb: -------------------------------------------------------------------------------- 1 | require "mpi" 2 | if defined?(NumRu::NArray) 3 | include NumRu 4 | end 5 | 6 | MPI.Init 7 | 8 | 9 | world = MPI::Comm::WORLD 10 | 11 | if world.size == 1 12 | print "Size is one, so do nothing\n" 13 | exit 14 | end 15 | 16 | rank = world.rank 17 | 18 | if rank == 0 19 | (world.size-1).times do |i| 20 | a = NArray.float(2) 21 | world.Recv(a, i+1, 1) 22 | p a 23 | end 24 | else 25 | world.Send(NArray[1.0,2], 0, 1) 26 | end 27 | 28 | 29 | MPI.Finalize 30 | -------------------------------------------------------------------------------- /samples/narray_offset.rb: -------------------------------------------------------------------------------- 1 | require "mpi" 2 | if defined?(NumRu::NArray) 3 | include NumRu 4 | end 5 | 6 | MPI.Init 7 | 8 | 9 | world = MPI::Comm::WORLD 10 | 11 | if world.size == 1 12 | print "Size is one, so do nothing\n" 13 | exit 14 | end 15 | 16 | rank = world.rank 17 | size = world.size 18 | 19 | length = 2 20 | if rank == 0 21 | a = NArray.float(length,size-1) 22 | (size-1).times do |i| 23 | world.Recv(a, i+1, 1, length, i*length) 24 | end 25 | p a 26 | else 27 | a = NArray.float(length).indgen + rank*10 28 | world.Send(a, 0, 1) 29 | end 30 | 31 | 32 | MPI.Finalize 33 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | os: 3 | - linux 4 | - osx 5 | rvm: 6 | - 2.0.0 7 | - 1.9.3 8 | cache: 9 | - bundler 10 | - apt 11 | addons: 12 | apt: 13 | packages: 14 | - libopenmpi-dev 15 | - openmpi-bin 16 | before_install: 17 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi 18 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install open-mpi; fi 19 | before_script: 20 | - bundle exec rake compile 21 | env: 22 | - JRUBY_OPTS=-Xcext.enabled=true 23 | script: 24 | - bundle exec mpirun -n 2 rspec 25 | - bundle exec mpirun -n 2 ruby -Ilib samples/hello.rb 26 | - bundle exec mpirun -n 2 ruby -Ilib samples/narray.rb 27 | - bundle exec mpirun -n 2 ruby -Ilib samples/narray_offset.rb 28 | -------------------------------------------------------------------------------- /ext/mpi/extconf.rb: -------------------------------------------------------------------------------- 1 | require "mkmf" 2 | 3 | CONFIG['CC'] = "mpicc" 4 | gem_path = nil 5 | begin 6 | require "rubygems" 7 | if Gem::Specification.respond_to?(:find_by_name) 8 | if spec = ( Gem::Specification.find_by_name("numru-narray") || 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("numru-narray") || Gem.source_index.find_name("narray")) ).any? 13 | gem_path = spec.full_gem_path 14 | end 15 | end 16 | gem_path = File.join(gem_path, "ext", "numru", "narray") 17 | rescue LoadError 18 | dir_config("narray", RbConfig::CONFIG["sitearchdir"]) 19 | end 20 | 21 | unless find_header("narray.h", gem_path) 22 | find_header("narray.h", File.join(gem_path,"src")) 23 | end 24 | 25 | create_makefile("mpi") 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # rcov generated 2 | coverage 3 | 4 | # rdoc generated 5 | rdoc 6 | 7 | # yard generated 8 | doc 9 | .yardoc 10 | 11 | # bundler 12 | .bundle 13 | Gemfile.lock 14 | vendor 15 | 16 | # jeweler generated 17 | pkg 18 | 19 | # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore: 20 | # 21 | # * Create a file at ~/.gitignore 22 | # * Include files you want ignored 23 | # * Run: git config --global core.excludesfile ~/.gitignore 24 | # 25 | # After doing this, these files will be ignored in all your git projects, 26 | # saving you from having to 'pollute' every project you touch with them 27 | # 28 | # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line) 29 | # 30 | # For MacOS: 31 | # 32 | #.DS_Store 33 | # 34 | # For TextMate 35 | #*.tmproj 36 | #tmtags 37 | # 38 | # For emacs: 39 | #*~ 40 | #\#* 41 | #.\#* 42 | # 43 | # For vim: 44 | #*.swp 45 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2024 Seiya Nishizawa 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = Ruby-MPI 2 | 3 | Ruby-MPI is a ruby binding of Message Passing Interface (MPI), which is an API specification that allows processes to communicate with one another by sending and receiving messages. 4 | 5 | == Install 6 | 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 13 | 14 | == Contributing to Ruby-MPI 15 | 16 | * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet 17 | * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it 18 | * Fork the project 19 | * Start a feature/bugfix branch 20 | * Commit and push until you are happy with your contribution 21 | * Make sure to add tests (rspec) for it. This is important so I don't break it in a future version unintentionally. 22 | * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it. 23 | 24 | == Copyright 25 | 26 | See LICENSE.txt 27 | 28 | -------------------------------------------------------------------------------- /samples/pi.rb: -------------------------------------------------------------------------------- 1 | # Run this program using 2 | # 3 | # mpirun -np 2 ruby pi.rb numpoints 4 | # 5 | # where numpoints is an integer 6 | # 7 | # The program is based on an example from 8 | # https://carpentries-incubator.github.io/hpc-intro/16-parallel/index.html 9 | 10 | require "mpi" 11 | if defined?(NumRu::NArray) 12 | include NumRu 13 | end 14 | 15 | def inside_circle my_count 16 | x = NArray.float(my_count).random 17 | y = NArray.float(my_count).random 18 | a = ((x**2 + y**2) < 1.0) 19 | return a.count_true 20 | end 21 | 22 | MPI.Init 23 | 24 | world = MPI::Comm::WORLD 25 | 26 | size = world.size 27 | rank = world.rank 28 | 29 | def usage(rank) 30 | if rank==0 31 | print < 0 34 | EOF 35 | end 36 | MPI.Finalize 37 | exit -1 38 | end 39 | usage(rank) if ARGV.length != 1 40 | usage(rank) if ( ( /^\d+$/ =~ ARGV[0] ) != 0) 41 | n_samples = ARGV[0].to_i 42 | usage(rank) unless n_samples > 0 43 | 44 | my_samples = n_samples.div(size) 45 | if ( n_samples % size > rank ) 46 | my_samples = my_samples + 1 47 | end 48 | 49 | my_count = NArray[0] 50 | count = NArray[0] 51 | 52 | my_count[0] = inside_circle my_samples 53 | 54 | world.Reduce(my_count,count,MPI::Op::SUM,0) 55 | if ( rank == 0 ) 56 | p "Pi is approximately " + ((count[0]*4.0)/(1.0*n_samples)).to_s 57 | end 58 | 59 | MPI.Finalize 60 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | require "rake/clean" 4 | begin 5 | Bundler.setup(:default, :development) 6 | rescue Bundler::BundlerError => e 7 | $stderr.puts e.message 8 | $stderr.puts "Run `bundle install` to install missing gems" 9 | exit e.status_code 10 | end 11 | require 'rake' 12 | 13 | require 'jeweler' 14 | Jeweler::Tasks.new do |gem| 15 | # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options 16 | gem.name = "ruby-mpi" 17 | gem.homepage = "http://github.com/gfd-dennou-club/ruby-mpi" 18 | gem.license = "MIT" 19 | gem.summary = "A ruby binding of MPI" 20 | gem.description = "A ruby binding of Message Passing Interface (MPI), which is an API specification that allows processes to communicate with one another by sending and receiving messages." 21 | gem.email = "seiya@gfd-dennou.org" 22 | gem.authors = ["Seiya Nishizawa"] 23 | # Include your dependencies below. Runtime dependencies are required when using your gem, 24 | # and development dependencies are only needed for development (ie running rake tasks, tests, etc) 25 | # gem.add_runtime_dependency 'jabber4r', '> 0.1' 26 | # gem.add_development_dependency 'rspec', '> 1.2.3' 27 | end 28 | Jeweler::RubygemsDotOrgTasks.new 29 | 30 | require 'rspec/core' 31 | require 'rspec/core/rake_task' 32 | RSpec::Core::RakeTask.new(:spec) do |spec| 33 | spec.pattern = FileList['spec/**/*_spec.rb'] 34 | end 35 | 36 | RSpec::Core::RakeTask.new(:rcov) do |spec| 37 | spec.pattern = 'spec/**/*_spec.rb' 38 | spec.rcov = true 39 | end 40 | 41 | task :default => :spec 42 | 43 | require 'rdoc/task' 44 | Rake::RDocTask.new do |rdoc| 45 | version = File.exist?('VERSION') ? File.read('VERSION') : "" 46 | 47 | rdoc.rdoc_dir = 'rdoc' 48 | rdoc.title = "ruby-mpi #{version}" 49 | rdoc.rdoc_files.include('README*') 50 | rdoc.rdoc_files.include('lib/**/*.rb') 51 | rdoc.rdoc_files.include('samples/*.rb') 52 | end 53 | 54 | if RUBY_PLATFORM =~ /java/ 55 | require "rake/javaextensiontask" 56 | Rake::JavaExtensionTask.new("mpi") 57 | else 58 | require "rake/extensiontask" 59 | Rake::ExtensionTask.new("mpi") 60 | end 61 | 62 | 63 | CLEAN.include("ext/mpi/*.o") 64 | CLEAN.include("ext/mpi/mkmf.log") 65 | CLOBBER.include("ext/mpi/mpi.so") 66 | CLOBBER.include("ext/mpi/Makefile") 67 | -------------------------------------------------------------------------------- /ruby-mpi.gemspec: -------------------------------------------------------------------------------- 1 | # Generated by jeweler 2 | # DO NOT EDIT THIS FILE DIRECTLY 3 | # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' 4 | # -*- encoding: utf-8 -*- 5 | # stub: ruby-mpi 0.4.0 ruby lib 6 | # stub: ext/mpi/extconf.rb 7 | 8 | Gem::Specification.new do |s| 9 | s.name = "ruby-mpi".freeze 10 | s.version = "0.4.0" 11 | 12 | s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= 13 | s.require_paths = ["lib".freeze] 14 | s.authors = ["Seiya Nishizawa".freeze] 15 | s.date = "2024-11-22" 16 | s.description = "A ruby binding of Message Passing Interface (MPI), which is an API specification that allows processes to communicate with one another by sending and receiving messages.".freeze 17 | s.email = "seiya@gfd-dennou.org".freeze 18 | s.extensions = ["ext/mpi/extconf.rb".freeze] 19 | s.extra_rdoc_files = [ 20 | "LICENSE.txt", 21 | "README.rdoc" 22 | ] 23 | s.files = [ 24 | ".document", 25 | ".rspec", 26 | ".travis.yml", 27 | "Gemfile", 28 | "LICENSE.txt", 29 | "README.rdoc", 30 | "Rakefile", 31 | "VERSION", 32 | "ext/mpi/extconf.rb", 33 | "ext/mpi/mpi.c", 34 | "lib/mpi.rb", 35 | "lib/mpi/utils.rb", 36 | "ruby-mpi.gemspec", 37 | "samples/hello.rb", 38 | "samples/kmeans.rb", 39 | "samples/narray.rb", 40 | "samples/narray_offset.rb", 41 | "samples/pi.rb", 42 | "spec/ruby-mpi_spec.rb", 43 | "spec/spec_helper.rb", 44 | "test/test_utils.rb" 45 | ] 46 | s.homepage = "http://github.com/gfd-dennou-club/ruby-mpi".freeze 47 | s.licenses = ["MIT".freeze] 48 | s.rubygems_version = "3.2.5".freeze 49 | s.summary = "A ruby binding of MPI".freeze 50 | 51 | if s.respond_to? :specification_version then 52 | s.specification_version = 4 53 | end 54 | 55 | if s.respond_to? :add_runtime_dependency then 56 | s.add_runtime_dependency(%q.freeze, ["~> 1.0"]) 57 | s.add_development_dependency(%q.freeze, [">= 2.3.0"]) 58 | s.add_development_dependency(%q.freeze, [">= 1.0.0"]) 59 | s.add_development_dependency(%q.freeze, [">= 1.5.2"]) 60 | s.add_development_dependency(%q.freeze, [">= 0"]) 61 | s.add_development_dependency(%q.freeze, [">= 0"]) 62 | else 63 | s.add_dependency(%q.freeze, ["~> 1.0"]) 64 | s.add_dependency(%q.freeze, [">= 2.3.0"]) 65 | s.add_dependency(%q.freeze, [">= 1.0.0"]) 66 | s.add_dependency(%q.freeze, [">= 1.5.2"]) 67 | s.add_dependency(%q.freeze, [">= 0"]) 68 | s.add_dependency(%q.freeze, [">= 0"]) 69 | end 70 | end 71 | 72 | -------------------------------------------------------------------------------- /samples/kmeans.rb: -------------------------------------------------------------------------------- 1 | # Run this program using 2 | # 3 | # mpirun -np numprocs ruby kmeans.rb numpoints numclusters 4 | # 5 | # where numprocs, numpoints and numclusters are integers 6 | # and numprocs <= numpoints and numclusters <= numpoints 7 | # 8 | # Parallelization assumes that numclusters << numpoints 9 | # and that numprocs << numpoints 10 | # 11 | # The program is based on the description at 12 | # https://en.wikipedia.org/wiki/K-means_clustering 13 | 14 | require "mpi" 15 | if defined?(NumRu::NArray) 16 | include NumRu 17 | end 18 | 19 | def generate_points count 20 | x = NArray.float(count).random 21 | y = NArray.float(count).random 22 | return x , y 23 | end 24 | 25 | MPI.Init 26 | 27 | world = MPI::Comm::WORLD 28 | 29 | size = world.size 30 | rank = world.rank 31 | 32 | def usage(rank) 33 | if rank==0 34 | print < 0 38 | numclusters <= numpoints and numproc <= numpoints 39 | EOF 40 | end 41 | MPI.Finalize 42 | exit -1 43 | end 44 | 45 | usage(rank) if ARGV.length != 2 46 | usage(rank) if ( ( /^\d+$/ =~ ARGV[0] ) != 0) 47 | usage(rank) if ( ( /^\d+$/ =~ ARGV[1] ) != 0) 48 | n_points = ARGV[0].to_i 49 | n_clusters = ARGV[1].to_i 50 | usage(rank) unless n_points > size 51 | usage(rank) unless n_clusters > 0 52 | usage(rank) unless n_points >= n_clusters 53 | 54 | my_points = n_points.div(size) 55 | if ( n_points % size > rank ) 56 | my_points += 1 57 | end 58 | 59 | cluster_x = NArray.float(n_clusters) 60 | cluster_y = NArray.float(n_clusters) 61 | my_cluster = NArray.int(my_points) 62 | min_distance = NArray.float(my_points) 63 | distance = NArray.float(n_clusters) 64 | cluster_member_count = NArray.int(n_clusters) 65 | total_cluster_x_sum = NArray.float(n_clusters) 66 | total_cluster_y_sum = NArray.float(n_clusters) 67 | total_cluster_member_count = NArray.int(n_clusters) 68 | my_cluster_x = NArray.float(n_clusters) 69 | my_cluster_y = NArray.float(n_clusters) 70 | my_cluster_member_count = NArray.int(n_clusters) 71 | my_energy = NArray.float(1) 72 | total_energy = NArray.float(1) 73 | random_x = NArray.float(n_clusters) 74 | random_y = NArray.float(n_clusters) 75 | 76 | my_x, my_y = generate_points my_points 77 | if rank == 0 78 | cluster_x, cluster_y = generate_points n_clusters 79 | end 80 | world.Bcast(cluster_x,0) 81 | world.Bcast(cluster_y,0) 82 | 83 | iter = 0 84 | # Do 10 iterations for testing purposes 85 | # in practice would use some convergence 86 | # criteria 87 | while iter < 10 do 88 | # Find cluster and calculate energy 89 | i = 0 90 | my_energy[0] = 0 91 | while i < my_points do 92 | distance = ( cluster_x - my_x[i] )**2 + ( cluster_y - my_y[i] )**2 93 | min_distance = distance.min 94 | my_energy[0] += min_distance 95 | # If multiple minimum values, take the first one 96 | my_cluster[i] = distance.eq(min_distance).where[0] 97 | i +=1 98 | end 99 | world.Allreduce(my_energy,total_energy,MPI::Op::SUM) 100 | if rank == 0 101 | p total_energy[0] 102 | end 103 | # Find new cluster centroids 104 | j = 0 105 | while j < n_clusters do 106 | mask = my_cluster.eq(j) 107 | my_cluster_member_count[j] = mask.count_true 108 | if mask.any? 109 | my_cluster_x[j] = (my_x[mask]).sum 110 | my_cluster_y[j] = (my_y[mask]).sum 111 | end 112 | j +=1 113 | end 114 | world.Allreduce(my_cluster_member_count,total_cluster_member_count,MPI::Op::SUM) 115 | world.Allreduce(my_cluster_x,total_cluster_x_sum,MPI::Op::SUM) 116 | world.Allreduce(my_cluster_y,total_cluster_y_sum,MPI::Op::SUM) 117 | # If a cluster is empty, choose a random point to try 118 | no_members = total_cluster_member_count.eq(0) 119 | if no_members.any? 120 | if rank == 0 121 | random_x, random_y = generate_points no_members.count_true 122 | total_cluster_member_count[no_members]= 1 123 | total_cluster_x_sum[no_members] = random_x 124 | total_cluster_y_sum[no_members] = random_y 125 | cluster_x = total_cluster_x_sum / total_cluster_member_count 126 | cluster_y = total_cluster_y_sum / total_cluster_member_count 127 | end 128 | world.Bcast(cluster_x,0) 129 | world.Bcast(cluster_y,0) 130 | else 131 | cluster_x = total_cluster_x_sum / total_cluster_member_count 132 | cluster_y = total_cluster_y_sum / total_cluster_member_count 133 | end 134 | iter += 1 135 | end 136 | 137 | MPI.Finalize 138 | -------------------------------------------------------------------------------- /spec/ruby-mpi_spec.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path(File.dirname(__FILE__) + '/spec_helper') 2 | 3 | if defined?(NumRu::NArray) 4 | include NumRu 5 | end 6 | 7 | describe "MPI" do 8 | before(:all) do 9 | MPI.Init() 10 | end 11 | after(:all) do 12 | MPI.Finalize() 13 | end 14 | 15 | before do 16 | @world = MPI::Comm::WORLD 17 | end 18 | 19 | it "should give version" do 20 | expect(MPI::VERSION.class).to eq(Integer) 21 | expect(MPI::SUBVERSION.class).to eq(Integer) 22 | end 23 | 24 | it "should give rank and size" do 25 | expect(@world.rank.class).to eql(Integer) 26 | expect(@world.size.class).to eql(Integer) 27 | expect(@world.size).to be > 0 28 | end 29 | 30 | it "should send and receive String" do 31 | rank = @world.rank 32 | message = "Hello from #{rank}" 33 | tag = 0 34 | @world.Send(message, 0, tag) if rank != 0 35 | if rank == 0 36 | (@world.size-1).times do |i| 37 | str = " "*"Hello from #{i+1}".length 38 | status = @world.Recv(str, i+1, tag) 39 | expect(status.source).to eql(i+1) 40 | expect(status.tag).to eql(tag) 41 | expect(str).to match /\AHello from #{i+1}/ 42 | end 43 | end 44 | end 45 | 46 | it "should send and receive NArray" do 47 | tag = 10 48 | rank = @world.rank 49 | [NArray[1,2,3], NArray[3.0,2.0,1.0]].each_with_index do |ary0,j| 50 | @world.Send(ary0, 0, tag+j) if rank != 0 51 | if rank == 0 52 | (@world.size-1).times do |i| 53 | ary1 = NArray.new(ary0.typecode, ary0.total) 54 | status = @world.Recv(ary1, i+1, tag+j) 55 | expect(status.source).to eql(i+1) 56 | expect(status.tag).to eql(tag+j) 57 | expect(ary1).to be == ary0 58 | end 59 | end 60 | end 61 | end 62 | 63 | it "should send and receive without blocking" do 64 | tag = 20 65 | rank = @world.rank 66 | message = "Hello from #{rank}" 67 | if rank != 0 68 | request = @world.Isend(message, 0, tag) 69 | status = request.Wait 70 | end 71 | if rank == 0 72 | request_recv = [] 73 | str = [] 74 | (@world.size-1).times do |i| 75 | str.push " "*"Hello from #{i+1}".length 76 | request_recv.push @world.Irecv(str[-1], i+1, tag) 77 | end 78 | status = MPI.Waitall(request_recv) 79 | (@world.size-1).times do |i| 80 | expect(status[i].source).to eql(i+1) 81 | expect(status[i].tag).to eql(tag) 82 | expect(str[i]).to match(/\AHello from #{i+1}/) 83 | end 84 | end 85 | end 86 | 87 | it "should gather data" do 88 | rank = @world.rank 89 | size = @world.size 90 | root = 0 91 | bufsize = 2 92 | sendbuf = rank.to_s[0,1]*bufsize 93 | recvbuf = rank == root ? "?"*bufsize*size : nil 94 | @world.Gather(sendbuf, recvbuf, root) 95 | if rank == root 96 | str = "" 97 | size.times{|i| str << i.to_s[0,1]*bufsize} 98 | expect(recvbuf).to eql(str) 99 | end 100 | end 101 | 102 | it "should gather data without blocking" do 103 | rank = @world.rank 104 | size = @world.size 105 | root = 0 106 | bufsize = 2 107 | sendbuf = rank.to_s[0,1]*bufsize 108 | recvbuf = rank == root ? "?"*bufsize*size : nil 109 | request = @world.Igather(sendbuf, recvbuf, root) 110 | if rank == root 111 | str = "" 112 | size.times{|i| str << i.to_s[0,1]*bufsize} 113 | request.Wait 114 | expect(recvbuf).to eql(str) 115 | end 116 | end 117 | 118 | it "should gather data of various sizes (gatherv)" do 119 | rank = @world.rank 120 | size = @world.size 121 | root = 0 122 | sendbuf = rank.to_s*(rank+1) 123 | recvcounts = [] 124 | displs = [0] 125 | size.times do |i| 126 | recvcounts.push i.to_s.length * (i+1) 127 | displs[i+1] = displs[i] + recvcounts[-1] if i size-1 340 | #source = MPI::PROC_NULL if source > size-1 341 | sendtag = 30 + rank 342 | recvtag = 30 + source 343 | bufsize = 2 344 | sendbuf = rank.to_s*bufsize 345 | recvbuf = " "*bufsize 346 | @world.Sendrecv(sendbuf, dest, sendtag, recvbuf, source, recvtag); 347 | if source != MPI::PROC_NULL 348 | expect(recvbuf).to eql(source.to_s*bufsize) 349 | end 350 | end 351 | 352 | it "should change data between each others (alltoall)" do 353 | rank = @world.rank 354 | size = @world.size 355 | bufsize = 2 356 | sendbuf = rank.to_s*bufsize*size 357 | recvbuf = "?"*bufsize*size 358 | @world.Alltoall(sendbuf, recvbuf) 359 | str = "" 360 | size.times{|i| str << i.to_s*bufsize} 361 | expect(recvbuf).to eql(str) 362 | end 363 | 364 | it "should change data between each others without blocking (ialltoall)" do 365 | rank = @world.rank 366 | size = @world.size 367 | bufsize = 2 368 | sendbuf = rank.to_s*bufsize*size 369 | recvbuf = "?"*bufsize*size 370 | request = @world.Ialltoall(sendbuf, recvbuf) 371 | str = "" 372 | size.times{|i| str << i.to_s*bufsize} 373 | request.Wait 374 | expect(recvbuf).to eql(str) 375 | end 376 | 377 | it "should change data of various sizes between each others (alltoallv)" do 378 | rank = @world.rank 379 | size = @world.size 380 | sendbuf = rank.to_s * (rank+1) * size 381 | sendcounts = Array.new(size) 382 | sdispls = Array.new(size) 383 | len = rank.to_s.length * (rank+1) 384 | size.times do |i| 385 | sendcounts[i] = len 386 | sdispls[i] = len * i 387 | end 388 | recvcounts = Array.new(size) 389 | rdispls = [0] 390 | str = "" 391 | size.times do |i| 392 | tmp = i.to_s * (i+1) 393 | str << tmp 394 | recvcounts[i] = tmp.length 395 | rdispls[i+1] = rdispls[i] + recvcounts[i] if i 0 542 | ary = NArray.new(sendbuf.typecode,count).fill(rank*(rank-1)/2.0) 543 | expect(recvbuf).to be == ary 544 | end 545 | end 546 | 547 | it "should exclusively scan data without blocking" do 548 | rank = @world.rank 549 | size = @world.size 550 | count = 2 551 | sendbuf = NArray.to_na([rank]*count) 552 | recvbuf = NArray.new(sendbuf.typecode,count) 553 | request = @world.Iexscan(sendbuf, recvbuf, MPI::Op::SUM) 554 | if rank > 0 555 | ary = NArray.new(sendbuf.typecode,count).fill(rank*(rank-1)/2.0) 556 | request.Wait 557 | expect(recvbuf).to be == ary 558 | end 559 | end 560 | 561 | it "should reduce data and send to all processes (allreduce)" do 562 | rank = @world.rank 563 | size = @world.size 564 | bufsize = 2 565 | sendbuf = NArray.to_na([rank]*bufsize) 566 | recvbuf = NArray.new(sendbuf.typecode,bufsize) 567 | @world.Allreduce(sendbuf, recvbuf, MPI::Op::SUM) 568 | ary = NArray.new(sendbuf.typecode,bufsize).fill(size*(size-1)/2.0) 569 | expect(recvbuf).to be == ary 570 | end 571 | 572 | it "should reduce data and send to all processes without blocking (iallreduce)" do 573 | rank = @world.rank 574 | size = @world.size 575 | bufsize = 2 576 | sendbuf = NArray.to_na([rank]*bufsize) 577 | recvbuf = NArray.new(sendbuf.typecode,bufsize) 578 | request = @world.Iallreduce(sendbuf, recvbuf, MPI::Op::SUM) 579 | ary = NArray.new(sendbuf.typecode,bufsize).fill(size*(size-1)/2.0) 580 | request.Wait 581 | expect(recvbuf).to be == ary 582 | end 583 | 584 | it "should not raise exception in calling barrier" do 585 | @world.Barrier 586 | end 587 | 588 | it "should not raise exception in calling barrier without blocking" do 589 | request = @world.Ibarrier 590 | request.Wait 591 | end 592 | 593 | 594 | it "shoud raise exeption" do 595 | expect { @world.Send("", @world.size+1, 0) }.to raise_error(MPI::ERR::RANK) 596 | expect(@world.Errhandler).to eql(MPI::Errhandler::ERRORS_RETURN) 597 | end 598 | 599 | end 600 | -------------------------------------------------------------------------------- /ext/mpi/mpi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ruby.h" 5 | #include "narray.h" 6 | #include "mpi.h" 7 | 8 | #if SIZEOF_SHORT == 2 9 | # define NA_MPI_SINT MPI_SHORT 10 | #else 11 | ---->> Please define NA_MPI_SINT manually because sizeof(short) != 2. <<---- 12 | #endif 13 | 14 | #if SIZEOF_LONG == 4 15 | # define NA_MPI_LINT MPI_LONG 16 | #else 17 | # if SIZEOF_INT == 4 18 | # define NA_MPI_LINT MPI_INT 19 | # else 20 | ---->> Please define NA_MPI_LINT manually because sizeof(long) != 4. <<---- 21 | # endif 22 | #endif 23 | 24 | #if SIZEOF_LONG_LONG == 8 25 | # define NA_MPI_LLINT MPI_LONG_LONG 26 | #else 27 | ---->> Please define NA_MPI_LLINT manually because sizeof(long long) != 8. <<---- 28 | #endif 29 | 30 | #ifndef NARRAY_BIGMEM 31 | # define NA_LLINT -999 32 | #endif 33 | 34 | 35 | #define OBJ2C(rb_obj, len, buffer, typ, off) \ 36 | {\ 37 | if (TYPE(rb_obj) == T_STRING) {\ 38 | if (len==0) len = RSTRING_LEN(rb_obj);\ 39 | buffer = (void*)(StringValuePtr(rb_obj) + off);\ 40 | typ = MPI_BYTE;\ 41 | } else if (IsNArray(rb_obj)) {\ 42 | struct NARRAY *a;\ 43 | GetNArray(rb_obj, a);\ 44 | buffer = (void*)(a->ptr);\ 45 | if (len==0) len = a->total;\ 46 | switch (a->type) {\ 47 | case NA_BYTE:\ 48 | typ = MPI_BYTE;\ 49 | buffer = (void*)((char*)buffer + off);\ 50 | break;\ 51 | case NA_SINT:\ 52 | typ = NA_MPI_SINT;\ 53 | buffer = (void*)((char*)buffer + off*2);\ 54 | break;\ 55 | case NA_LINT:\ 56 | typ = NA_MPI_LINT;\ 57 | buffer = (void*)((char*)buffer + off*4);\ 58 | break;\ 59 | case NA_LLINT:\ 60 | typ = NA_MPI_LLINT;\ 61 | buffer = (void*)((char*)buffer + off*8);\ 62 | break;\ 63 | case NA_SFLOAT:\ 64 | typ = MPI_FLOAT;\ 65 | buffer = (void*)((char*)buffer + off*4);\ 66 | break;\ 67 | case NA_DFLOAT:\ 68 | typ = MPI_DOUBLE;\ 69 | buffer = (void*)((char*)buffer + off*8);\ 70 | break;\ 71 | case NA_SCOMPLEX:\ 72 | typ = MPI_COMPLEX;\ 73 | buffer = (void*)((char*)buffer + off*8);\ 74 | break;\ 75 | case NA_DCOMPLEX:\ 76 | typ = MPI_DOUBLE_COMPLEX;\ 77 | buffer = (void*)((char*)buffer + off*16);\ 78 | break;\ 79 | default:\ 80 | rb_raise(rb_eArgError, "narray type is invalid");\ 81 | }\ 82 | } else {\ 83 | rb_raise(rb_eArgError, "Only String and NArray are supported");\ 84 | }\ 85 | } 86 | 87 | static VALUE mMPI; 88 | static VALUE cComm, cRequest, cOp, cErrhandler, cStatus; 89 | 90 | static VALUE eBUFFER, eCOUNT, eTYPE, eTAG, eCOMM, eRANK, eREQUEST, eROOT, eGROUP, eOP, eTOPOLOGY, eDIMS, eARG, eUNKNOWN, eTRUNCATE, eOTHER, eINTERN, eIN_STATUS, ePENDING, eACCESS, eAMODE, eASSERT, eBAD_FILE, eBASE, eCONVERSION, eDISP, eDUP_DATAREP, eFILE_EXISTS, eFILE_IN_USE, eFILE, eINFO_KEY, eINFO_NOKEY, eINFO_VALUE, eINFO, eIO, eKEYVAL, eLOCKTYPE, eNAME, eNO_MEM, eNOT_SAME, eNO_SPACE, eNO_SUCH_FILE, ePORT, eQUOTA, eREAD_ONLY, eRMA_CONFLICT, eRMA_SYNC, eSERVICE, eSIZE, eSPAWN, eUNSUPPORTED_DATAREP, eUNSUPPORTED_OPERATION, eWIN, eLASTCODE, eSYSRESOURCE; 91 | 92 | struct _Comm { 93 | MPI_Comm Comm; 94 | bool free; 95 | }; 96 | struct _Request { 97 | MPI_Request Request; 98 | bool free; 99 | }; 100 | struct _Op { 101 | MPI_Op Op; 102 | bool free; 103 | }; 104 | struct _Errhandler { 105 | MPI_Errhandler Errhandler; 106 | bool free; 107 | }; 108 | 109 | static bool _initialized = false; 110 | static bool _finalized = false; 111 | 112 | 113 | #define CAE_ERR(type) case MPI_ERR_ ## type: rb_raise(e ## type,"%s",str); break 114 | static void 115 | check_error(int error) 116 | { 117 | if (error == MPI_SUCCESS) return; 118 | int code, len; 119 | char str[MPI_MAX_ERROR_STRING]; 120 | if (MPI_Error_class(error, &code)!=MPI_SUCCESS || MPI_Error_string(error, str, &len)!=MPI_SUCCESS) 121 | rb_raise(rb_eRuntimeError, "unknown error occuerd in MPI call"); 122 | 123 | switch (code) { 124 | CAE_ERR(BUFFER); 125 | CAE_ERR(COUNT); 126 | CAE_ERR(TYPE); 127 | CAE_ERR(TAG); 128 | CAE_ERR(COMM); 129 | CAE_ERR(RANK); 130 | CAE_ERR(REQUEST); 131 | CAE_ERR(ROOT); 132 | CAE_ERR(GROUP); 133 | CAE_ERR(OP); 134 | CAE_ERR(TOPOLOGY); 135 | CAE_ERR(DIMS); 136 | CAE_ERR(ARG); 137 | CAE_ERR(UNKNOWN); 138 | CAE_ERR(TRUNCATE); 139 | CAE_ERR(OTHER); 140 | CAE_ERR(INTERN); 141 | CAE_ERR(IN_STATUS); 142 | CAE_ERR(PENDING); 143 | CAE_ERR(ACCESS); 144 | CAE_ERR(AMODE); 145 | CAE_ERR(ASSERT); 146 | CAE_ERR(BAD_FILE); 147 | CAE_ERR(BASE); 148 | CAE_ERR(CONVERSION); 149 | CAE_ERR(DISP); 150 | CAE_ERR(DUP_DATAREP); 151 | CAE_ERR(FILE_EXISTS); 152 | CAE_ERR(FILE_IN_USE); 153 | CAE_ERR(FILE); 154 | CAE_ERR(INFO_KEY); 155 | CAE_ERR(INFO_NOKEY); 156 | CAE_ERR(INFO_VALUE); 157 | CAE_ERR(INFO); 158 | CAE_ERR(IO); 159 | CAE_ERR(KEYVAL); 160 | CAE_ERR(LOCKTYPE); 161 | CAE_ERR(NAME); 162 | CAE_ERR(NO_MEM); 163 | CAE_ERR(NOT_SAME); 164 | CAE_ERR(NO_SPACE); 165 | CAE_ERR(NO_SUCH_FILE); 166 | CAE_ERR(PORT); 167 | CAE_ERR(QUOTA); 168 | CAE_ERR(READ_ONLY); 169 | CAE_ERR(RMA_CONFLICT); 170 | CAE_ERR(RMA_SYNC); 171 | CAE_ERR(SERVICE); 172 | CAE_ERR(SIZE); 173 | CAE_ERR(SPAWN); 174 | CAE_ERR(UNSUPPORTED_DATAREP); 175 | CAE_ERR(UNSUPPORTED_OPERATION); 176 | CAE_ERR(WIN); 177 | CAE_ERR(LASTCODE); 178 | #ifdef MPI_ERR_SYSRESOURCE 179 | CAE_ERR(SYSRESOURCE); 180 | #endif 181 | default: 182 | rb_raise(rb_eRuntimeError, "unknown error: %d", code); 183 | } 184 | } 185 | 186 | #define DEF_FREE(name, capit) \ 187 | static void \ 188 | name ## _free(void *ptr)\ 189 | {\ 190 | struct _ ## name *obj;\ 191 | obj = (struct _ ## name*) ptr;\ 192 | if (!_finalized && obj->free && obj->name!=MPI_ ## capit ##_NULL)\ 193 | check_error(MPI_ ## name ## _free(&(obj->name))); \ 194 | free(obj);\ 195 | } 196 | #define DEF_FREE2(name, capit) \ 197 | static void \ 198 | name ## _free2(void *ptr)\ 199 | {\ 200 | struct _ ## name *obj;\ 201 | obj = (struct _ ## name*) ptr;\ 202 | free(obj);\ 203 | } 204 | //DEF_FREE(Comm, COMM) 205 | DEF_FREE(Request, REQUEST) 206 | //DEF_FREE(Op, OP) 207 | DEF_FREE(Errhandler, ERRHANDLER) 208 | DEF_FREE2(Comm, COMM) 209 | DEF_FREE2(Op, OP) 210 | DEF_FREE2(Errhandler, ERRHANDLER) 211 | static void 212 | Status_free(void *ptr) 213 | { 214 | free((MPI_Status*) ptr); 215 | } 216 | 217 | 218 | #define DEF_CONST(v, const, name) \ 219 | {\ 220 | v = ALLOC(struct _ ## v);\ 221 | v->v = const;\ 222 | v->free = false;\ 223 | rb_define_const(c ## v, #name, Data_Wrap_Struct(c ## v, NULL, v ## _free2, v)); \ 224 | } 225 | 226 | static void 227 | _finalize() 228 | { 229 | if(_initialized && !_finalized) { 230 | _finalized = true; 231 | check_error(MPI_Finalize()); 232 | } 233 | } 234 | static VALUE 235 | rb_m_init(int argc, VALUE *argv, VALUE self) 236 | { 237 | VALUE argary; 238 | int cargc; 239 | char ** cargv; 240 | VALUE progname; 241 | int i; 242 | 243 | rb_scan_args(argc, argv, "01", &argary); 244 | 245 | if (NIL_P(argary)) { 246 | argary = rb_const_get(rb_cObject, rb_intern("ARGV")); 247 | cargc = RARRAY_LEN(argary); 248 | } else { 249 | Check_Type(argary, T_ARRAY); 250 | cargc = RARRAY_LEN(argary); 251 | } 252 | 253 | cargv = ALLOCA_N(char *, cargc+1); 254 | progname = rb_gv_get("$0"); 255 | cargv[0] = StringValueCStr(progname); 256 | 257 | for(i=0; iComm, NUM2INT(rerror)); 317 | return INT2NUM(ierror); 318 | } 319 | 320 | static VALUE 321 | rb_m_wtime(VALUE self) 322 | { 323 | double time; 324 | time = MPI_Wtime(); 325 | return rb_float_new(time); 326 | } 327 | 328 | static VALUE 329 | rb_m_waitall(VALUE self, VALUE rary) 330 | { 331 | struct _Request *req; 332 | MPI_Request *request; 333 | MPI_Status *status; 334 | VALUE rb_status; 335 | long count, i; 336 | 337 | count = RARRAY_LEN(rary); 338 | 339 | request = ALLOCA_N(MPI_Request, count); 340 | for (i=0; iRequest; 343 | } 344 | rb_status = rb_ary_new2(count); 345 | status = ALLOC_N(MPI_Status, count); 346 | check_error(MPI_Waitall(count, request, status)); 347 | for (i=0; ifree = true; 367 | return Qnil; 368 | } 369 | static VALUE 370 | rb_comm_size(VALUE self) 371 | { 372 | struct _Comm *comm; 373 | int size; 374 | Data_Get_Struct(self, struct _Comm, comm); 375 | check_error(MPI_Comm_size(comm->Comm, &size)); 376 | return INT2NUM(size); 377 | } 378 | static VALUE 379 | rb_comm_rank(VALUE self) 380 | { 381 | struct _Comm *comm; 382 | int rank; 383 | Data_Get_Struct(self, struct _Comm, comm); 384 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 385 | return INT2NUM(rank); 386 | } 387 | static VALUE 388 | rb_comm_send(VALUE self, VALUE rb_obj, VALUE rb_dest, VALUE rb_tag) 389 | { 390 | void* buffer; 391 | int len=0, dest, tag; 392 | MPI_Datatype type; 393 | struct _Comm *comm; 394 | 395 | OBJ2C(rb_obj, len, buffer, type, 0); 396 | dest = NUM2INT(rb_dest); 397 | tag = NUM2INT(rb_tag); 398 | Data_Get_Struct(self, struct _Comm, comm); 399 | check_error(MPI_Send(buffer, len, type, dest, tag, comm->Comm)); 400 | 401 | return Qnil; 402 | } 403 | static VALUE 404 | rb_comm_isend(VALUE self, VALUE rb_obj, VALUE rb_dest, VALUE rb_tag) 405 | { 406 | void* buffer; 407 | int len=0, dest, tag; 408 | MPI_Datatype type; 409 | struct _Comm *comm; 410 | struct _Request *request; 411 | VALUE rb_request; 412 | 413 | OBJ2C(rb_obj, len, buffer, type, 0); 414 | dest = NUM2INT(rb_dest); 415 | tag = NUM2INT(rb_tag); 416 | Data_Get_Struct(self, struct _Comm, comm); 417 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 418 | request->free = true; 419 | check_error(MPI_Isend(buffer, len, type, dest, tag, comm->Comm, &(request->Request))); 420 | 421 | return rb_request; 422 | } 423 | static VALUE 424 | rb_comm_recv(int argc, VALUE *argv, VALUE self) 425 | { 426 | VALUE rb_obj, rb_source, rb_tag; 427 | VALUE rb_len, rb_offset; // option 428 | void* buffer; 429 | int source, tag, len = 0, offset = 0; 430 | MPI_Datatype type; 431 | MPI_Status *status; 432 | struct _Comm *comm; 433 | 434 | rb_scan_args(argc, argv, "32", &rb_obj, &rb_source, &rb_tag, &rb_len, &rb_offset); 435 | 436 | if (rb_len != Qnil) { 437 | len = NUM2INT(rb_len); 438 | } 439 | if (rb_offset != Qnil) { 440 | offset = NUM2INT(rb_offset); 441 | } 442 | 443 | OBJ2C(rb_obj, len, buffer, type, offset); 444 | source = NUM2INT(rb_source); 445 | tag = NUM2INT(rb_tag); 446 | 447 | Data_Get_Struct(self, struct _Comm, comm); 448 | status = ALLOC(MPI_Status); 449 | check_error(MPI_Recv(buffer, len, type, source, tag, comm->Comm, status)); 450 | 451 | return Data_Wrap_Struct(cStatus, NULL, Status_free, status); 452 | } 453 | static VALUE 454 | rb_comm_irecv(int argc, VALUE *argv, VALUE self) 455 | { 456 | VALUE rb_obj, rb_source, rb_tag; 457 | VALUE rb_len, rb_offset; // option 458 | void* buffer; 459 | int source, tag, len = 0, offset = 0; 460 | MPI_Datatype type; 461 | struct _Comm *comm; 462 | struct _Request *request; 463 | VALUE rb_request; 464 | 465 | rb_scan_args(argc, argv, "32", &rb_obj, &rb_source, &rb_tag, &rb_len, &rb_offset); 466 | 467 | if (rb_len != Qnil) { 468 | len = NUM2INT(rb_len); 469 | } 470 | if (rb_offset != Qnil) { 471 | offset = NUM2INT(rb_offset); 472 | } 473 | 474 | OBJ2C(rb_obj, len, buffer, type, offset); 475 | source = NUM2INT(rb_source); 476 | tag = NUM2INT(rb_tag); 477 | 478 | Data_Get_Struct(self, struct _Comm, comm); 479 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 480 | request->free = true; 481 | check_error(MPI_Irecv(buffer, len, type, source, tag, comm->Comm, &(request->Request))); 482 | 483 | return rb_request; 484 | } 485 | static VALUE 486 | rb_comm_gather(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_root) 487 | { 488 | void *sendbuf, *recvbuf = NULL; 489 | int sendcount=0, recvcount = 0; 490 | MPI_Datatype sendtype, recvtype = 0; 491 | int root, rank, size; 492 | struct _Comm *comm; 493 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 494 | root = NUM2INT(rb_root); 495 | Data_Get_Struct(self, struct _Comm, comm); 496 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 497 | check_error(MPI_Comm_size(comm->Comm, &size)); 498 | if (rank == root) { 499 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 500 | if (recvcount < sendcount*size) 501 | rb_raise(rb_eArgError, "recvbuf is too small"); 502 | recvcount = sendcount; 503 | } else { 504 | recvtype = sendtype; // to avoid segmentation fault in an environment 505 | } 506 | check_error(MPI_Gather(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm->Comm)); 507 | return Qnil; 508 | } 509 | static VALUE 510 | rb_comm_igather(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_root) 511 | { 512 | void *sendbuf, *recvbuf = NULL; 513 | int sendcount=0, recvcount = 0; 514 | MPI_Datatype sendtype, recvtype = 0; 515 | int root, rank, size; 516 | struct _Comm *comm; 517 | struct _Request *request; 518 | VALUE rb_request; 519 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 520 | root = NUM2INT(rb_root); 521 | Data_Get_Struct(self, struct _Comm, comm); 522 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 523 | check_error(MPI_Comm_size(comm->Comm, &size)); 524 | if (rank == root) { 525 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 526 | if (recvcount < sendcount*size) 527 | rb_raise(rb_eArgError, "recvbuf is too small"); 528 | recvcount = sendcount; 529 | } else { 530 | recvtype = sendtype; // to avoid segmentation fault in an environment 531 | } 532 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 533 | request->free = true; 534 | check_error(MPI_Igather(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm->Comm, &(request->Request))); 535 | return rb_request; 536 | } 537 | static VALUE 538 | rb_comm_gatherv(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_recvcounts, VALUE rb_displs, VALUE rb_root) 539 | { 540 | void *sendbuf, *recvbuf = NULL; 541 | int sendcount=0, bufsize=0; 542 | int *recvcounts = NULL, *displs = NULL; 543 | MPI_Datatype sendtype, recvtype = 0; 544 | int root, rank, size; 545 | struct _Comm *comm; 546 | int max, tmp; 547 | int i; 548 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 549 | root = NUM2INT(rb_root); 550 | Data_Get_Struct(self, struct _Comm, comm); 551 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 552 | check_error(MPI_Comm_size(comm->Comm, &size)); 553 | if (rank == root) { 554 | if ( RARRAY_LEN(rb_recvcounts) != size ) 555 | rb_raise(rb_eArgError, "length of recvcounts must be the same as the group size"); 556 | if ( RARRAY_LEN(rb_displs) != size ) 557 | rb_raise(rb_eArgError, "length of displs must be the same as the group size"); 558 | recvcounts = ALLOCA_N(int, size); 559 | displs = ALLOCA_N(int, size); 560 | max = 0; 561 | for (i=0; i max) max = tmp; 566 | } 567 | OBJ2C(rb_recvbuf, bufsize, recvbuf, recvtype, 0); 568 | if (bufsize < max) 569 | rb_raise(rb_eArgError, "recvbuf is too small"); 570 | } else { 571 | recvtype = sendtype; // to avoid segmentation fault in an environment 572 | } 573 | check_error(MPI_Gatherv(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, root, comm->Comm)); 574 | return Qnil; 575 | } 576 | static VALUE 577 | rb_comm_igatherv(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_recvcounts, VALUE rb_displs, VALUE rb_root) 578 | { 579 | void *sendbuf, *recvbuf = NULL; 580 | int sendcount=0, bufsize=0; 581 | int *recvcounts = NULL, *displs = NULL; 582 | MPI_Datatype sendtype, recvtype = 0; 583 | int root, rank, size; 584 | struct _Comm *comm; 585 | struct _Request *request; 586 | VALUE rb_request; 587 | int max, tmp; 588 | int i; 589 | 590 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 591 | root = NUM2INT(rb_root); 592 | Data_Get_Struct(self, struct _Comm, comm); 593 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 594 | check_error(MPI_Comm_size(comm->Comm, &size)); 595 | if (rank == root) { 596 | recvcounts = ALLOCA_N(int, size); 597 | displs = ALLOCA_N(int, size); 598 | max = 0; 599 | if ( RARRAY_LEN(rb_recvcounts) != size ) 600 | rb_raise(rb_eArgError, "length of recvcounts must be the same as the group size"); 601 | if ( RARRAY_LEN(rb_displs) != size ) 602 | rb_raise(rb_eArgError, "length of displs must be the same as the group size"); 603 | for (i=0; i max) max = tmp; 608 | } 609 | OBJ2C(rb_recvbuf, bufsize, recvbuf, recvtype, 0); 610 | if (bufsize < max) 611 | rb_raise(rb_eArgError, "recvbuf is too small"); 612 | } else { 613 | recvtype = sendtype; // to avoid segmentation fault in an environment 614 | } 615 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 616 | request->free = true; 617 | check_error(MPI_Igatherv(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, root, comm->Comm, &(request->Request))); 618 | return rb_request; 619 | } 620 | static VALUE 621 | rb_comm_allgather(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf) 622 | { 623 | void *sendbuf, *recvbuf; 624 | int sendcount=0, recvcount=0; 625 | MPI_Datatype sendtype, recvtype; 626 | int rank, size; 627 | struct _Comm *comm; 628 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 629 | Data_Get_Struct(self, struct _Comm, comm); 630 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 631 | check_error(MPI_Comm_size(comm->Comm, &size)); 632 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 633 | if (recvcount < sendcount*size) 634 | rb_raise(rb_eArgError, "recvbuf is too small"); 635 | recvcount = sendcount; 636 | check_error(MPI_Allgather(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm->Comm)); 637 | return Qnil; 638 | } 639 | static VALUE 640 | rb_comm_iallgather(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf) 641 | { 642 | void *sendbuf, *recvbuf; 643 | int sendcount=0, recvcount=0; 644 | MPI_Datatype sendtype, recvtype; 645 | int rank, size; 646 | struct _Comm *comm; 647 | struct _Request *request; 648 | VALUE rb_request; 649 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 650 | Data_Get_Struct(self, struct _Comm, comm); 651 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 652 | check_error(MPI_Comm_size(comm->Comm, &size)); 653 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 654 | if (recvcount < sendcount*size) 655 | rb_raise(rb_eArgError, "recvbuf is too small"); 656 | recvcount = sendcount; 657 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 658 | request->free = true; 659 | check_error(MPI_Iallgather(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm->Comm, &(request->Request))); 660 | return rb_request; 661 | } 662 | static VALUE 663 | rb_comm_allgatherv(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_recvcounts, VALUE rb_displs) 664 | { 665 | void *sendbuf, *recvbuf; 666 | int sendcount=0, bufsize=0; 667 | int *recvcounts, *displs; 668 | MPI_Datatype sendtype, recvtype; 669 | int rank, size; 670 | struct _Comm *comm; 671 | int max, tmp; 672 | int i; 673 | Data_Get_Struct(self, struct _Comm, comm); 674 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 675 | check_error(MPI_Comm_size(comm->Comm, &size)); 676 | if ( RARRAY_LEN(rb_recvcounts) != size ) 677 | rb_raise(rb_eArgError, "length of recvcounts must be the same as the group size"); 678 | if ( RARRAY_LEN(rb_displs) != size ) 679 | rb_raise(rb_eArgError, "length of displs must be the same as the group size"); 680 | recvcounts = ALLOCA_N(int, size); 681 | displs = ALLOCA_N(int, size); 682 | max = 0; 683 | for (i=0; i max) max = tmp; 688 | } 689 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 690 | if (sendcount != recvcounts[rank]) 691 | rb_raise(rb_eArgError, "length of sendbuf is not the same as recvcounts[rank]"); 692 | OBJ2C(rb_recvbuf, bufsize, recvbuf, recvtype, 0); 693 | if (bufsize < max) 694 | rb_raise(rb_eArgError, "recvbuf is too small"); 695 | check_error(MPI_Allgatherv(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, comm->Comm)); 696 | return Qnil; 697 | } 698 | static VALUE 699 | rb_comm_iallgatherv(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_recvcounts, VALUE rb_displs) 700 | { 701 | void *sendbuf, *recvbuf; 702 | int sendcount=0, bufsize=0; 703 | int *recvcounts, *displs; 704 | MPI_Datatype sendtype, recvtype; 705 | int rank, size; 706 | struct _Comm *comm; 707 | struct _Request *request; 708 | VALUE rb_request; 709 | int max, tmp; 710 | int i; 711 | Data_Get_Struct(self, struct _Comm, comm); 712 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 713 | check_error(MPI_Comm_size(comm->Comm, &size)); 714 | if ( RARRAY_LEN(rb_recvcounts) != size ) 715 | rb_raise(rb_eArgError, "length of recvcounts must be the same as the group size"); 716 | if ( RARRAY_LEN(rb_displs) != size ) 717 | rb_raise(rb_eArgError, "length of displs must be the same as the group size"); 718 | recvcounts = ALLOCA_N(int, size); 719 | displs = ALLOCA_N(int, size); 720 | max = 0; 721 | for (i=0; i max) max = tmp; 726 | } 727 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 728 | if (sendcount != recvcounts[rank]) 729 | rb_raise(rb_eArgError, "length of sendbuf is not the same as recvcounts[rank]"); 730 | OBJ2C(rb_recvbuf, bufsize, recvbuf, recvtype, 0); 731 | if (bufsize < max) 732 | rb_raise(rb_eArgError, "recvbuf is too small"); 733 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 734 | request->free = true; 735 | check_error(MPI_Iallgatherv(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, comm->Comm, &(request->Request))); 736 | return rb_request; 737 | } 738 | static VALUE 739 | rb_comm_bcast(VALUE self, VALUE rb_buffer, VALUE rb_root) 740 | { 741 | void *buffer; 742 | int count=0; 743 | MPI_Datatype type; 744 | int root; 745 | struct _Comm *comm; 746 | OBJ2C(rb_buffer, count, buffer, type, 0); 747 | root = NUM2INT(rb_root); 748 | Data_Get_Struct(self, struct _Comm, comm); 749 | check_error(MPI_Bcast(buffer, count, type, root, comm->Comm)); 750 | return Qnil; 751 | } 752 | static VALUE 753 | rb_comm_ibcast(VALUE self, VALUE rb_buffer, VALUE rb_root) 754 | { 755 | void *buffer; 756 | int count=0; 757 | MPI_Datatype type; 758 | int root; 759 | struct _Comm *comm; 760 | struct _Request *request; 761 | VALUE rb_request; 762 | OBJ2C(rb_buffer, count, buffer, type, 0); 763 | root = NUM2INT(rb_root); 764 | Data_Get_Struct(self, struct _Comm, comm); 765 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 766 | request->free = true; 767 | check_error(MPI_Ibcast(buffer, count, type, root, comm->Comm, &(request->Request))); 768 | return rb_request; 769 | } 770 | static VALUE 771 | rb_comm_scatter(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_root) 772 | { 773 | void *sendbuf = NULL, *recvbuf; 774 | int sendcount = 0, recvcount=0; 775 | MPI_Datatype sendtype = 0, recvtype; 776 | int root, rank, size; 777 | struct _Comm *comm; 778 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 779 | root = NUM2INT(rb_root); 780 | Data_Get_Struct(self, struct _Comm, comm); 781 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 782 | check_error(MPI_Comm_size(comm->Comm, &size)); 783 | if (rank == root) { 784 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 785 | if (sendcount > recvcount*size) 786 | rb_raise(rb_eArgError, "recvbuf is too small"); 787 | sendcount = recvcount; 788 | } 789 | check_error(MPI_Scatter(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm->Comm)); 790 | return Qnil; 791 | } 792 | static VALUE 793 | rb_comm_iscatter(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_root) 794 | { 795 | void *sendbuf = NULL, *recvbuf; 796 | int sendcount = 0, recvcount=0; 797 | MPI_Datatype sendtype = 0, recvtype; 798 | int root, rank, size; 799 | struct _Comm *comm; 800 | struct _Request *request; 801 | VALUE rb_request; 802 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 803 | root = NUM2INT(rb_root); 804 | Data_Get_Struct(self, struct _Comm, comm); 805 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 806 | check_error(MPI_Comm_size(comm->Comm, &size)); 807 | if (rank == root) { 808 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 809 | if (sendcount > recvcount*size) 810 | rb_raise(rb_eArgError, "recvbuf is too small"); 811 | sendcount = recvcount; 812 | } 813 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 814 | request->free = true; 815 | check_error(MPI_Iscatter(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm->Comm, &(request->Request))); 816 | return rb_request; 817 | } 818 | static VALUE 819 | rb_comm_scatterv(VALUE self, VALUE rb_sendbuf, VALUE rb_sendcounts, VALUE rb_displs, VALUE rb_recvbuf, VALUE rb_root) 820 | { 821 | void *sendbuf = NULL, *recvbuf; 822 | int recvcount = 0, bufsize=0; 823 | int *sendcounts, *displs; 824 | MPI_Datatype sendtype = 0, recvtype; 825 | int root, rank, size; 826 | struct _Comm *comm; 827 | int max, tmp; 828 | int i; 829 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 830 | root = NUM2INT(rb_root); 831 | Data_Get_Struct(self, struct _Comm, comm); 832 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 833 | check_error(MPI_Comm_size(comm->Comm, &size)); 834 | if (rank == root) { 835 | if ( RARRAY_LEN(rb_sendcounts) != size ) 836 | rb_raise(rb_eArgError, "length of sendcounts must be the same as the group size"); 837 | if ( RARRAY_LEN(rb_displs) != size ) 838 | rb_raise(rb_eArgError, "length of displs must be the same as the group size"); 839 | sendcounts = ALLOCA_N(int, size); 840 | displs = ALLOCA_N(int, size); 841 | max = 0; 842 | for (i=0; i max) max = tmp; 847 | } 848 | OBJ2C(rb_sendbuf, bufsize, sendbuf, sendtype, 0); 849 | if (bufsize < max) 850 | rb_raise(rb_eArgError, "sendbuf is too small"); 851 | } 852 | check_error(MPI_Scatterv(sendbuf, sendcounts, displs, sendtype, recvbuf, recvcount, recvtype, root, comm->Comm)); 853 | return Qnil; 854 | } 855 | static VALUE 856 | rb_comm_iscatterv(VALUE self, VALUE rb_sendbuf, VALUE rb_sendcounts, VALUE rb_displs, VALUE rb_recvbuf, VALUE rb_root) 857 | { 858 | void *sendbuf = NULL, *recvbuf; 859 | int recvcount = 0, bufsize=0; 860 | int *sendcounts, *displs; 861 | MPI_Datatype sendtype = 0, recvtype; 862 | int root, rank, size; 863 | struct _Comm *comm; 864 | struct _Request *request; 865 | VALUE rb_request; 866 | int max, tmp; 867 | int i; 868 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 869 | root = NUM2INT(rb_root); 870 | Data_Get_Struct(self, struct _Comm, comm); 871 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 872 | check_error(MPI_Comm_size(comm->Comm, &size)); 873 | if (rank == root) { 874 | if ( RARRAY_LEN(rb_sendcounts) != size ) 875 | rb_raise(rb_eArgError, "length of sendcounts must be the same as the group size"); 876 | if ( RARRAY_LEN(rb_displs) != size ) 877 | rb_raise(rb_eArgError, "length of displs must be the same as the group size"); 878 | sendcounts = ALLOCA_N(int, size); 879 | displs = ALLOCA_N(int, size); 880 | max = 0; 881 | for (i=0; i max) max = tmp; 886 | } 887 | OBJ2C(rb_sendbuf, bufsize, sendbuf, sendtype, 0); 888 | if (bufsize < max) 889 | rb_raise(rb_eArgError, "sendbuf is too small"); 890 | } 891 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 892 | request->free = true; 893 | check_error(MPI_Iscatterv(sendbuf, sendcounts, displs, sendtype, recvbuf, recvcount, recvtype, root, comm->Comm, &(request->Request))); 894 | return rb_request; 895 | } 896 | static VALUE 897 | rb_comm_sendrecv(VALUE self, VALUE rb_sendbuf, VALUE rb_dest, VALUE rb_sendtag, VALUE rb_recvbuf, VALUE rb_source, VALUE rb_recvtag) 898 | { 899 | void *sendbuf, *recvbuf; 900 | int sendcount=0, recvcount=0; 901 | MPI_Datatype sendtype, recvtype; 902 | int dest, source; 903 | int sendtag, recvtag; 904 | int size; 905 | struct _Comm *comm; 906 | MPI_Status *status; 907 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 908 | Data_Get_Struct(self, struct _Comm, comm); 909 | check_error(MPI_Comm_size(comm->Comm, &size)); 910 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 911 | dest = NUM2INT(rb_dest); 912 | source = NUM2INT(rb_source); 913 | sendtag = NUM2INT(rb_sendtag); 914 | recvtag = NUM2INT(rb_recvtag); 915 | status = ALLOC(MPI_Status); 916 | check_error(MPI_Sendrecv(sendbuf, sendcount, sendtype, dest, sendtag, recvbuf, recvcount, recvtype, source, recvtag, comm->Comm, status)); 917 | return Data_Wrap_Struct(cStatus, NULL, Status_free, status); 918 | } 919 | static VALUE 920 | rb_comm_alltoall(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf) 921 | { 922 | void *sendbuf, *recvbuf; 923 | int sendcount=0, recvcount=0; 924 | MPI_Datatype sendtype, recvtype; 925 | int size; 926 | struct _Comm *comm; 927 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 928 | Data_Get_Struct(self, struct _Comm, comm); 929 | check_error(MPI_Comm_size(comm->Comm, &size)); 930 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 931 | if (recvcount < sendcount) 932 | rb_raise(rb_eArgError, "recvbuf is too small"); 933 | recvcount = recvcount/size; 934 | sendcount = sendcount/size; 935 | check_error(MPI_Alltoall(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm->Comm)); 936 | return Qnil; 937 | } 938 | static VALUE 939 | rb_comm_ialltoall(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf) 940 | { 941 | void *sendbuf, *recvbuf; 942 | int sendcount=0, recvcount=0; 943 | MPI_Datatype sendtype, recvtype; 944 | int size; 945 | struct _Comm *comm; 946 | struct _Request *request; 947 | VALUE rb_request; 948 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 949 | Data_Get_Struct(self, struct _Comm, comm); 950 | check_error(MPI_Comm_size(comm->Comm, &size)); 951 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 952 | if (recvcount < sendcount) 953 | rb_raise(rb_eArgError, "recvbuf is too small"); 954 | recvcount = recvcount/size; 955 | sendcount = sendcount/size; 956 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 957 | request->free = true; 958 | check_error(MPI_Ialltoall(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm->Comm, &(request->Request))); 959 | return rb_request; 960 | } 961 | static VALUE 962 | rb_comm_alltoallv(VALUE self, VALUE rb_sendbuf, VALUE rb_sendcounts, VALUE rb_sdispls, VALUE rb_recvbuf, VALUE rb_recvcounts, VALUE rb_rdispls) 963 | { 964 | void *sendbuf, *recvbuf; 965 | int bufsize=0; 966 | int *sendcounts, *sdispls; 967 | int *recvcounts, *rdispls; 968 | MPI_Datatype sendtype, recvtype; 969 | int size; 970 | struct _Comm *comm; 971 | int smax, rmax, tmp; 972 | int i; 973 | Data_Get_Struct(self, struct _Comm, comm); 974 | check_error(MPI_Comm_size(comm->Comm, &size)); 975 | if ( RARRAY_LEN(rb_sendcounts) != size ) 976 | rb_raise(rb_eArgError, "length of sendcounts must be the same as the group size"); 977 | if ( RARRAY_LEN(rb_sdispls) != size ) 978 | rb_raise(rb_eArgError, "length of sdispls must be the same as the group size"); 979 | if ( RARRAY_LEN(rb_recvcounts) != size ) 980 | rb_raise(rb_eArgError, "length of recvcounts must be the same as the group size"); 981 | if ( RARRAY_LEN(rb_rdispls) != size ) 982 | rb_raise(rb_eArgError, "length of rdispls must be the same as the group size"); 983 | sendcounts = ALLOCA_N(int, size); 984 | sdispls = ALLOCA_N(int, size); 985 | recvcounts = ALLOCA_N(int, size); 986 | rdispls = ALLOCA_N(int, size); 987 | smax = 0; 988 | rmax = 0; 989 | for (i=0; i smax) smax = tmp; 996 | tmp = rdispls[i] + recvcounts[i]; 997 | if(tmp > rmax) rmax = tmp; 998 | } 999 | OBJ2C(rb_sendbuf, bufsize, sendbuf, sendtype, 0); 1000 | if (bufsize < smax) 1001 | rb_raise(rb_eArgError, "sendbuf is too small"); 1002 | bufsize = 0; 1003 | OBJ2C(rb_recvbuf, bufsize, recvbuf, recvtype, 0); 1004 | if (bufsize < rmax) 1005 | rb_raise(rb_eArgError, "recvbuf is too small"); 1006 | check_error(MPI_Alltoallv(sendbuf, sendcounts, sdispls, sendtype, recvbuf, recvcounts, rdispls, recvtype, comm->Comm)); 1007 | return Qnil; 1008 | } 1009 | static VALUE 1010 | rb_comm_ialltoallv(VALUE self, VALUE rb_sendbuf, VALUE rb_sendcounts, VALUE rb_sdispls, VALUE rb_recvbuf, VALUE rb_recvcounts, VALUE rb_rdispls) 1011 | { 1012 | void *sendbuf, *recvbuf; 1013 | int bufsize=0; 1014 | int *sendcounts, *sdispls; 1015 | int *recvcounts, *rdispls; 1016 | MPI_Datatype sendtype, recvtype; 1017 | int size; 1018 | struct _Comm *comm; 1019 | struct _Request *request; 1020 | VALUE rb_request; 1021 | int smax, rmax, tmp; 1022 | int i; 1023 | Data_Get_Struct(self, struct _Comm, comm); 1024 | check_error(MPI_Comm_size(comm->Comm, &size)); 1025 | if ( RARRAY_LEN(rb_sendcounts) != size ) 1026 | rb_raise(rb_eArgError, "length of sendcounts must be the same as the group size"); 1027 | if ( RARRAY_LEN(rb_sdispls) != size ) 1028 | rb_raise(rb_eArgError, "length of sdispls must be the same as the group size"); 1029 | if ( RARRAY_LEN(rb_recvcounts) != size ) 1030 | rb_raise(rb_eArgError, "length of recvcounts must be the same as the group size"); 1031 | if ( RARRAY_LEN(rb_rdispls) != size ) 1032 | rb_raise(rb_eArgError, "length of rdispls must be the same as the group size"); 1033 | sendcounts = ALLOCA_N(int, size); 1034 | sdispls = ALLOCA_N(int, size); 1035 | recvcounts = ALLOCA_N(int, size); 1036 | rdispls = ALLOCA_N(int, size); 1037 | smax = 0; 1038 | rmax = 0; 1039 | for (i=0; i smax) smax = tmp; 1046 | tmp = rdispls[i] + recvcounts[i]; 1047 | if(tmp > rmax) rmax = tmp; 1048 | } 1049 | OBJ2C(rb_sendbuf, bufsize, sendbuf, sendtype, 0); 1050 | if (bufsize < smax) 1051 | rb_raise(rb_eArgError, "sendbuf is too small"); 1052 | bufsize = 0; 1053 | OBJ2C(rb_recvbuf, bufsize, recvbuf, recvtype, 0); 1054 | if (bufsize < rmax) 1055 | rb_raise(rb_eArgError, "recvbuf is too small"); 1056 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 1057 | request->free = true; 1058 | check_error(MPI_Ialltoallv(sendbuf, sendcounts, sdispls, sendtype, recvbuf, recvcounts, rdispls, recvtype, comm->Comm, &(request->Request))); 1059 | return rb_request; 1060 | } 1061 | static VALUE 1062 | rb_comm_reduce(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op, VALUE rb_root) 1063 | { 1064 | void *sendbuf, *recvbuf = NULL; 1065 | int sendcount=0, recvcount = 0; 1066 | MPI_Datatype sendtype, recvtype = 0; 1067 | int root, rank, size; 1068 | struct _Comm *comm; 1069 | struct _Op *op; 1070 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 1071 | root = NUM2INT(rb_root); 1072 | Data_Get_Struct(self, struct _Comm, comm); 1073 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 1074 | check_error(MPI_Comm_size(comm->Comm, &size)); 1075 | if (rank == root) { 1076 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 1077 | if (recvcount != sendcount) 1078 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same length"); 1079 | if (recvtype != sendtype) 1080 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same type"); 1081 | } 1082 | Data_Get_Struct(rb_op, struct _Op, op); 1083 | check_error(MPI_Reduce(sendbuf, recvbuf, sendcount, sendtype, op->Op, root, comm->Comm)); 1084 | return Qnil; 1085 | } 1086 | static VALUE 1087 | rb_comm_ireduce(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op, VALUE rb_root) 1088 | { 1089 | void *sendbuf, *recvbuf = NULL; 1090 | int sendcount=0, recvcount = 0; 1091 | MPI_Datatype sendtype, recvtype = 0; 1092 | int root, rank, size; 1093 | struct _Comm *comm; 1094 | struct _Op *op; 1095 | struct _Request *request; 1096 | VALUE rb_request; 1097 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 1098 | root = NUM2INT(rb_root); 1099 | Data_Get_Struct(self, struct _Comm, comm); 1100 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 1101 | check_error(MPI_Comm_size(comm->Comm, &size)); 1102 | if (rank == root) { 1103 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 1104 | if (recvcount != sendcount) 1105 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same length"); 1106 | if (recvtype != sendtype) 1107 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same type"); 1108 | } 1109 | Data_Get_Struct(rb_op, struct _Op, op); 1110 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 1111 | request->free = true; 1112 | check_error(MPI_Ireduce(sendbuf, recvbuf, sendcount, sendtype, op->Op, root, comm->Comm, &(request->Request))); 1113 | return rb_request; 1114 | } 1115 | static VALUE 1116 | rb_comm_reduce_scatter(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_recvcounts, VALUE rb_op) 1117 | { 1118 | void *sendbuf, *recvbuf = NULL; 1119 | int sendcount=0, bufsize = 0; 1120 | int *recvcounts; 1121 | MPI_Datatype sendtype, recvtype = 0; 1122 | int rank, size; 1123 | struct _Comm *comm; 1124 | struct _Op *op; 1125 | int i; 1126 | Data_Get_Struct(self, struct _Comm, comm); 1127 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 1128 | check_error(MPI_Comm_size(comm->Comm, &size)); 1129 | if ( RARRAY_LEN(rb_recvcounts) != size ) 1130 | rb_raise(rb_eArgError, "length of recvcounts must be the same as the group size"); 1131 | recvcounts = ALLOCA_N(int, size); 1132 | sendcount = 0; 1133 | for (i=0; iOp, comm->Comm)); 1148 | return Qnil; 1149 | } 1150 | static VALUE 1151 | rb_comm_ireduce_scatter(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_recvcounts, VALUE rb_op) 1152 | { 1153 | void *sendbuf, *recvbuf = NULL; 1154 | int sendcount=0, bufsize = 0; 1155 | int *recvcounts; 1156 | MPI_Datatype sendtype, recvtype = 0; 1157 | int rank, size; 1158 | struct _Comm *comm; 1159 | struct _Op *op; 1160 | struct _Request *request; 1161 | VALUE rb_request; 1162 | int i; 1163 | Data_Get_Struct(self, struct _Comm, comm); 1164 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 1165 | check_error(MPI_Comm_size(comm->Comm, &size)); 1166 | if ( RARRAY_LEN(rb_recvcounts) != size ) 1167 | rb_raise(rb_eArgError, "length of recvcounts must be the same as the group size"); 1168 | recvcounts = ALLOCA_N(int, size); 1169 | sendcount = 0; 1170 | for (i=0; ifree = true; 1186 | check_error(MPI_Ireduce_scatter(sendbuf, recvbuf, recvcounts, sendtype, op->Op, comm->Comm, &(request->Request))); 1187 | return rb_request; 1188 | } 1189 | static VALUE 1190 | rb_comm_reduce_scatter_block(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op) 1191 | { 1192 | void *sendbuf, *recvbuf = NULL; 1193 | int sendcount=0, recvcount = 0; 1194 | MPI_Datatype sendtype, recvtype = 0; 1195 | int size; 1196 | struct _Comm *comm; 1197 | struct _Op *op; 1198 | Data_Get_Struct(self, struct _Comm, comm); 1199 | check_error(MPI_Comm_size(comm->Comm, &size)); 1200 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 1201 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 1202 | if (sendcount != recvcount*size) 1203 | rb_raise(rb_eArgError, "length of sendbuf must be length of recvbuf times rank size"); 1204 | if (recvtype != sendtype) 1205 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same type"); 1206 | Data_Get_Struct(rb_op, struct _Op, op); 1207 | check_error(MPI_Reduce_scatter_block(sendbuf, recvbuf, recvcount, sendtype, op->Op, comm->Comm)); 1208 | return Qnil; 1209 | } 1210 | static VALUE 1211 | rb_comm_ireduce_scatter_block(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op) 1212 | { 1213 | void *sendbuf, *recvbuf = NULL; 1214 | int sendcount=0, recvcount = 0; 1215 | MPI_Datatype sendtype, recvtype = 0; 1216 | int size; 1217 | struct _Comm *comm; 1218 | struct _Op *op; 1219 | struct _Request *request; 1220 | VALUE rb_request; 1221 | Data_Get_Struct(self, struct _Comm, comm); 1222 | check_error(MPI_Comm_size(comm->Comm, &size)); 1223 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 1224 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 1225 | if (sendcount != recvcount*size) 1226 | rb_raise(rb_eArgError, "length of sendbuf must be length of recvbuf times rank size"); 1227 | if (recvtype != sendtype) 1228 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same type"); 1229 | Data_Get_Struct(rb_op, struct _Op, op); 1230 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 1231 | request->free = true; 1232 | check_error(MPI_Ireduce_scatter_block(sendbuf, recvbuf, recvcount, sendtype, op->Op, comm->Comm, &(request->Request))); 1233 | return rb_request; 1234 | } 1235 | static VALUE 1236 | rb_comm_scan(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op) 1237 | { 1238 | void *sendbuf, *recvbuf = NULL; 1239 | int sendcount=0, recvcount = 0; 1240 | MPI_Datatype sendtype, recvtype = 0; 1241 | struct _Comm *comm; 1242 | struct _Op *op; 1243 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 1244 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 1245 | if (sendcount != recvcount) 1246 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same length"); 1247 | if (recvtype != sendtype) 1248 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same type"); 1249 | Data_Get_Struct(self, struct _Comm, comm); 1250 | Data_Get_Struct(rb_op, struct _Op, op); 1251 | check_error(MPI_Scan(sendbuf, recvbuf, recvcount, sendtype, op->Op, comm->Comm)); 1252 | return Qnil; 1253 | } 1254 | static VALUE 1255 | rb_comm_iscan(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op) 1256 | { 1257 | void *sendbuf, *recvbuf = NULL; 1258 | int sendcount=0, recvcount = 0; 1259 | MPI_Datatype sendtype, recvtype = 0; 1260 | struct _Comm *comm; 1261 | struct _Op *op; 1262 | struct _Request *request; 1263 | VALUE rb_request; 1264 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 1265 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 1266 | if (sendcount != recvcount) 1267 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same length"); 1268 | if (recvtype != sendtype) 1269 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same type"); 1270 | Data_Get_Struct(self, struct _Comm, comm); 1271 | Data_Get_Struct(rb_op, struct _Op, op); 1272 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 1273 | request->free = true; 1274 | check_error(MPI_Iscan(sendbuf, recvbuf, recvcount, sendtype, op->Op, comm->Comm, &(request->Request))); 1275 | return rb_request; 1276 | } 1277 | static VALUE 1278 | rb_comm_exscan(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op) 1279 | { 1280 | void *sendbuf, *recvbuf = NULL; 1281 | int sendcount=0, recvcount = 0; 1282 | MPI_Datatype sendtype, recvtype = 0; 1283 | struct _Comm *comm; 1284 | struct _Op *op; 1285 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 1286 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 1287 | if (sendcount != recvcount) 1288 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same length"); 1289 | if (recvtype != sendtype) 1290 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same type"); 1291 | Data_Get_Struct(self, struct _Comm, comm); 1292 | Data_Get_Struct(rb_op, struct _Op, op); 1293 | check_error(MPI_Exscan(sendbuf, recvbuf, recvcount, sendtype, op->Op, comm->Comm)); 1294 | return Qnil; 1295 | } 1296 | static VALUE 1297 | rb_comm_iexscan(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op) 1298 | { 1299 | void *sendbuf, *recvbuf = NULL; 1300 | int sendcount=0, recvcount = 0; 1301 | MPI_Datatype sendtype, recvtype = 0; 1302 | struct _Comm *comm; 1303 | struct _Op *op; 1304 | struct _Request *request; 1305 | VALUE rb_request; 1306 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 1307 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 1308 | if (sendcount != recvcount) 1309 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same length"); 1310 | if (recvtype != sendtype) 1311 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same type"); 1312 | Data_Get_Struct(self, struct _Comm, comm); 1313 | Data_Get_Struct(rb_op, struct _Op, op); 1314 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 1315 | request->free = true; 1316 | check_error(MPI_Iexscan(sendbuf, recvbuf, recvcount, sendtype, op->Op, comm->Comm, &(request->Request))); 1317 | return rb_request; 1318 | } 1319 | static VALUE 1320 | rb_comm_allreduce(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op) 1321 | { 1322 | void *sendbuf, *recvbuf; 1323 | int sendcount=0, recvcount=0; 1324 | MPI_Datatype sendtype, recvtype; 1325 | int rank, size; 1326 | struct _Comm *comm; 1327 | struct _Op *op; 1328 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 1329 | Data_Get_Struct(self, struct _Comm, comm); 1330 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 1331 | check_error(MPI_Comm_size(comm->Comm, &size)); 1332 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 1333 | if (recvcount != sendcount) 1334 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same length"); 1335 | if (recvtype != sendtype) 1336 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same type"); 1337 | Data_Get_Struct(rb_op, struct _Op, op); 1338 | check_error(MPI_Allreduce(sendbuf, recvbuf, recvcount, recvtype, op->Op, comm->Comm)); 1339 | return Qnil; 1340 | } 1341 | static VALUE 1342 | rb_comm_iallreduce(VALUE self, VALUE rb_sendbuf, VALUE rb_recvbuf, VALUE rb_op) 1343 | { 1344 | void *sendbuf, *recvbuf; 1345 | int sendcount=0, recvcount=0; 1346 | MPI_Datatype sendtype, recvtype; 1347 | int rank, size; 1348 | struct _Comm *comm; 1349 | struct _Op *op; 1350 | struct _Request *request; 1351 | VALUE rb_request; 1352 | OBJ2C(rb_sendbuf, sendcount, sendbuf, sendtype, 0); 1353 | Data_Get_Struct(self, struct _Comm, comm); 1354 | check_error(MPI_Comm_rank(comm->Comm, &rank)); 1355 | check_error(MPI_Comm_size(comm->Comm, &size)); 1356 | OBJ2C(rb_recvbuf, recvcount, recvbuf, recvtype, 0); 1357 | if (recvcount != sendcount) 1358 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same length"); 1359 | if (recvtype != sendtype) 1360 | rb_raise(rb_eArgError, "sendbuf and recvbuf must have the same type"); 1361 | Data_Get_Struct(rb_op, struct _Op, op); 1362 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 1363 | request->free = true; 1364 | check_error(MPI_Iallreduce(sendbuf, recvbuf, recvcount, recvtype, op->Op, comm->Comm, &(request->Request))); 1365 | return rb_request; 1366 | } 1367 | static VALUE 1368 | rb_comm_get_Errhandler(VALUE self) 1369 | { 1370 | struct _Comm *comm; 1371 | struct _Errhandler *errhandler; 1372 | VALUE rb_errhandler; 1373 | 1374 | Data_Get_Struct(self, struct _Comm, comm); 1375 | rb_errhandler = Data_Make_Struct(cErrhandler, struct _Errhandler, NULL, Errhandler_free, errhandler); 1376 | errhandler->free = false; 1377 | check_error(MPI_Comm_get_errhandler(comm->Comm, &(errhandler->Errhandler))); 1378 | return rb_errhandler; 1379 | } 1380 | static VALUE 1381 | rb_comm_set_Errhandler(VALUE self, VALUE rb_errhandler) 1382 | { 1383 | struct _Comm *comm; 1384 | struct _Errhandler *errhandler; 1385 | 1386 | Data_Get_Struct(self, struct _Comm, comm); 1387 | Data_Get_Struct(rb_errhandler, struct _Errhandler, errhandler); 1388 | check_error(MPI_Comm_set_errhandler(comm->Comm, errhandler->Errhandler)); 1389 | return self; 1390 | } 1391 | static VALUE 1392 | rb_comm_barrier(VALUE self) 1393 | { 1394 | struct _Comm *comm; 1395 | Data_Get_Struct(self, struct _Comm, comm); 1396 | check_error(MPI_Barrier(comm->Comm)); 1397 | return Qnil; 1398 | } 1399 | static VALUE 1400 | rb_comm_ibarrier(VALUE self) 1401 | { 1402 | struct _Comm *comm; 1403 | struct _Request *request; 1404 | VALUE rb_request; 1405 | Data_Get_Struct(self, struct _Comm, comm); 1406 | rb_request = Data_Make_Struct(cRequest, struct _Request, NULL, Request_free, request); 1407 | request->free = true; 1408 | check_error(MPI_Ibarrier(comm->Comm, &(request->Request))); 1409 | return rb_request; 1410 | } 1411 | 1412 | // MPI::Request 1413 | static VALUE 1414 | rb_request_wait(VALUE self) 1415 | { 1416 | MPI_Status *status; 1417 | struct _Request *request; 1418 | Data_Get_Struct(self, struct _Request, request); 1419 | status = ALLOC(MPI_Status); 1420 | check_error(MPI_Wait(&(request->Request), status)); 1421 | return Data_Wrap_Struct(cStatus, NULL, Status_free, status); 1422 | } 1423 | 1424 | // MPI::Errhandler 1425 | static VALUE 1426 | rb_errhandler_eql(VALUE self, VALUE other) 1427 | { 1428 | struct _Errhandler *eh0, *eh1; 1429 | Data_Get_Struct(self, struct _Errhandler, eh0); 1430 | Data_Get_Struct(other, struct _Errhandler, eh1); 1431 | return eh0->Errhandler == eh1->Errhandler ? Qtrue : Qfalse; 1432 | } 1433 | 1434 | // MPI::Status 1435 | static VALUE 1436 | rb_status_source(VALUE self) 1437 | { 1438 | MPI_Status *status; 1439 | Data_Get_Struct(self, MPI_Status, status); 1440 | return INT2NUM(status->MPI_SOURCE); 1441 | } 1442 | static VALUE 1443 | rb_status_tag(VALUE self) 1444 | { 1445 | MPI_Status *status; 1446 | Data_Get_Struct(self, MPI_Status, status); 1447 | return INT2NUM(status->MPI_TAG); 1448 | } 1449 | static VALUE 1450 | rb_status_error(VALUE self) 1451 | { 1452 | MPI_Status *status; 1453 | Data_Get_Struct(self, MPI_Status, status); 1454 | return INT2NUM(status->MPI_ERROR); 1455 | } 1456 | 1457 | 1458 | void Init_mpi() 1459 | { 1460 | 1461 | // MPI 1462 | mMPI = rb_define_module("MPI"); 1463 | rb_define_module_function(mMPI, "Init", rb_m_init, -1); 1464 | rb_define_module_function(mMPI, "Finalize", rb_m_finalize, 0); 1465 | rb_define_module_function(mMPI, "Abort", rb_m_abort, 2); 1466 | rb_define_module_function(mMPI, "Wtime", rb_m_wtime, 0); 1467 | rb_define_module_function(mMPI, "Waitall", rb_m_waitall, 1); 1468 | rb_define_const(mMPI, "VERSION", INT2NUM(MPI_VERSION)); 1469 | rb_define_const(mMPI, "SUBVERSION", INT2NUM(MPI_SUBVERSION)); 1470 | rb_define_const(mMPI, "SUCCESS", INT2NUM(MPI_SUCCESS)); 1471 | rb_define_const(mMPI, "PROC_NULL", INT2NUM(MPI_PROC_NULL)); 1472 | 1473 | // MPI::Comm 1474 | cComm = rb_define_class_under(mMPI, "Comm", rb_cObject); 1475 | // rb_define_alloc_func(cComm, rb_comm_alloc); 1476 | rb_define_private_method(cComm, "initialize", rb_comm_initialize, 0); 1477 | rb_define_method(cComm, "rank", rb_comm_rank, 0); 1478 | rb_define_method(cComm, "Rank", rb_comm_rank, 0); 1479 | rb_define_method(cComm, "size", rb_comm_size, 0); 1480 | rb_define_method(cComm, "Size", rb_comm_size, 0); 1481 | rb_define_method(cComm, "Send", rb_comm_send, 3); 1482 | rb_define_method(cComm, "Isend", rb_comm_isend, 3); 1483 | rb_define_method(cComm, "Recv", rb_comm_recv, -1); 1484 | rb_define_method(cComm, "Irecv", rb_comm_irecv, -1); 1485 | rb_define_method(cComm, "Gather", rb_comm_gather, 3); 1486 | rb_define_method(cComm, "Igather", rb_comm_igather, 3); 1487 | rb_define_method(cComm, "Gatherv", rb_comm_gatherv, 5); 1488 | rb_define_method(cComm, "Igatherv", rb_comm_igatherv, 5); 1489 | rb_define_method(cComm, "Allgather", rb_comm_allgather, 2); 1490 | rb_define_method(cComm, "Iallgather", rb_comm_iallgather, 2); 1491 | rb_define_method(cComm, "Allgatherv", rb_comm_allgatherv, 4); 1492 | rb_define_method(cComm, "Iallgatherv", rb_comm_iallgatherv, 4); 1493 | rb_define_method(cComm, "Bcast", rb_comm_bcast, 2); 1494 | rb_define_method(cComm, "Ibcast", rb_comm_ibcast, 2); 1495 | rb_define_method(cComm, "Scatter", rb_comm_scatter, 3); 1496 | rb_define_method(cComm, "Iscatter", rb_comm_iscatter, 3); 1497 | rb_define_method(cComm, "Scatterv", rb_comm_scatterv, 5); 1498 | rb_define_method(cComm, "Iscatterv", rb_comm_iscatterv, 5); 1499 | rb_define_method(cComm, "Sendrecv", rb_comm_sendrecv, 6); 1500 | rb_define_method(cComm, "Alltoall", rb_comm_alltoall, 2); 1501 | rb_define_method(cComm, "Ialltoall", rb_comm_ialltoall, 2); 1502 | rb_define_method(cComm, "Alltoallv", rb_comm_alltoallv, 6); 1503 | rb_define_method(cComm, "Ialltoallv", rb_comm_ialltoallv, 6); 1504 | // rb_define_method(cComm, "Alltoallw", rb_comm_alltoallw, 2); 1505 | // rb_define_method(cComm, "Ialltoallw", rb_comm_ialltoallw, 2); 1506 | rb_define_method(cComm, "Reduce", rb_comm_reduce, 4); 1507 | rb_define_method(cComm, "Ireduce", rb_comm_ireduce, 4); 1508 | rb_define_method(cComm, "Reduce_scatter", rb_comm_reduce_scatter, 4); 1509 | rb_define_method(cComm, "Ireduce_scatter", rb_comm_ireduce_scatter, 4); 1510 | rb_define_method(cComm, "Reduce_scatter_block", rb_comm_reduce_scatter_block, 3); 1511 | rb_define_method(cComm, "Ireduce_scatter_block", rb_comm_ireduce_scatter_block, 3); 1512 | rb_define_method(cComm, "Scan", rb_comm_scan, 3); 1513 | rb_define_method(cComm, "Iscan", rb_comm_iscan, 3); 1514 | rb_define_method(cComm, "Exscan", rb_comm_exscan, 3); 1515 | rb_define_method(cComm, "Iexscan", rb_comm_iexscan, 3); 1516 | rb_define_method(cComm, "Allreduce", rb_comm_allreduce, 3); 1517 | rb_define_method(cComm, "Iallreduce", rb_comm_iallreduce, 3); 1518 | rb_define_method(cComm, "Barrier", rb_comm_barrier, 0); 1519 | rb_define_method(cComm, "Ibarrier", rb_comm_ibarrier, 0); 1520 | rb_define_method(cComm, "Errhandler", rb_comm_get_Errhandler, 0); 1521 | rb_define_method(cComm, "Errhandler=", rb_comm_set_Errhandler, 1); 1522 | 1523 | // MPI::Request 1524 | cRequest = rb_define_class_under(mMPI, "Request", rb_cObject); 1525 | rb_define_method(cRequest, "Wait", rb_request_wait, 0); 1526 | 1527 | // MPI::Op 1528 | cOp = rb_define_class_under(mMPI, "Op", rb_cObject); 1529 | 1530 | // MPI::Errhandler 1531 | cErrhandler = rb_define_class_under(mMPI, "Errhandler", rb_cObject); 1532 | rb_define_method(cErrhandler, "eql?", rb_errhandler_eql, 1); 1533 | 1534 | // MPI::Status 1535 | cStatus = rb_define_class_under(mMPI, "Status", rb_cObject); 1536 | rb_define_method(cStatus, "source", rb_status_source, 0); 1537 | rb_define_method(cStatus, "tag", rb_status_tag, 0); 1538 | rb_define_method(cStatus, "error", rb_status_error, 0); 1539 | 1540 | 1541 | //MPI::ERR 1542 | VALUE mERR = rb_define_module_under(mMPI, "ERR"); 1543 | eBUFFER = rb_define_class_under(mERR, "BUFFER", rb_eStandardError); 1544 | eCOUNT = rb_define_class_under(mERR, "COUNT", rb_eStandardError); 1545 | eTYPE = rb_define_class_under(mERR, "TYPE", rb_eStandardError); 1546 | eTAG = rb_define_class_under(mERR, "TAG", rb_eStandardError); 1547 | eCOMM = rb_define_class_under(mERR, "COMM", rb_eStandardError); 1548 | eRANK = rb_define_class_under(mERR, "RANK", rb_eStandardError); 1549 | eREQUEST = rb_define_class_under(mERR, "REQUEST", rb_eStandardError); 1550 | eROOT = rb_define_class_under(mERR, "ROOT", rb_eStandardError); 1551 | eGROUP = rb_define_class_under(mERR, "GROUP", rb_eStandardError); 1552 | eOP = rb_define_class_under(mERR, "OP", rb_eStandardError); 1553 | eTOPOLOGY = rb_define_class_under(mERR, "TOPOLOGY", rb_eStandardError); 1554 | eDIMS = rb_define_class_under(mERR, "DIMS", rb_eStandardError); 1555 | eARG = rb_define_class_under(mERR, "ARG", rb_eStandardError); 1556 | eUNKNOWN = rb_define_class_under(mERR, "UNKNOWN", rb_eStandardError); 1557 | eTRUNCATE = rb_define_class_under(mERR, "TRUNCATE", rb_eStandardError); 1558 | eOTHER = rb_define_class_under(mERR, "OTHER", rb_eStandardError); 1559 | eINTERN = rb_define_class_under(mERR, "INTERN", rb_eStandardError); 1560 | eIN_STATUS = rb_define_class_under(mERR, "IN_STATUS", rb_eStandardError); 1561 | ePENDING = rb_define_class_under(mERR, "PENDING", rb_eStandardError); 1562 | eACCESS = rb_define_class_under(mERR, "ACCESS", rb_eStandardError); 1563 | eAMODE = rb_define_class_under(mERR, "AMODE", rb_eStandardError); 1564 | eASSERT = rb_define_class_under(mERR, "ASSERT", rb_eStandardError); 1565 | eBAD_FILE = rb_define_class_under(mERR, "BAD_FILE", rb_eStandardError); 1566 | eBASE = rb_define_class_under(mERR, "BASE", rb_eStandardError); 1567 | eCONVERSION = rb_define_class_under(mERR, "CONVERSION", rb_eStandardError); 1568 | eDISP = rb_define_class_under(mERR, "DISP", rb_eStandardError); 1569 | eDUP_DATAREP = rb_define_class_under(mERR, "DUP_DATAREP", rb_eStandardError); 1570 | eFILE_EXISTS = rb_define_class_under(mERR, "FILE_EXISTS", rb_eStandardError); 1571 | eFILE_IN_USE = rb_define_class_under(mERR, "FILE_IN_USE", rb_eStandardError); 1572 | eFILE = rb_define_class_under(mERR, "FILE", rb_eStandardError); 1573 | eINFO_KEY = rb_define_class_under(mERR, "INFO_KEY", rb_eStandardError); 1574 | eINFO_NOKEY = rb_define_class_under(mERR, "INFO_NOKEY", rb_eStandardError); 1575 | eINFO_VALUE = rb_define_class_under(mERR, "INFO_VALUE", rb_eStandardError); 1576 | eINFO = rb_define_class_under(mERR, "INFO", rb_eStandardError); 1577 | eIO = rb_define_class_under(mERR, "IO", rb_eStandardError); 1578 | eKEYVAL = rb_define_class_under(mERR, "KEYVAL", rb_eStandardError); 1579 | eLOCKTYPE = rb_define_class_under(mERR, "LOCKTYPE", rb_eStandardError); 1580 | eNAME = rb_define_class_under(mERR, "NAME", rb_eStandardError); 1581 | eNO_MEM = rb_define_class_under(mERR, "NO_MEM", rb_eStandardError); 1582 | eNOT_SAME = rb_define_class_under(mERR, "NOT_SAME", rb_eStandardError); 1583 | eNO_SPACE = rb_define_class_under(mERR, "NO_SPACE", rb_eStandardError); 1584 | eNO_SUCH_FILE = rb_define_class_under(mERR, "NO_SUCH_FILE", rb_eStandardError); 1585 | ePORT = rb_define_class_under(mERR, "PORT", rb_eStandardError); 1586 | eQUOTA = rb_define_class_under(mERR, "QUOTA", rb_eStandardError); 1587 | eREAD_ONLY = rb_define_class_under(mERR, "READ_ONLY", rb_eStandardError); 1588 | eRMA_CONFLICT = rb_define_class_under(mERR, "RMA_CONFLICT", rb_eStandardError); 1589 | eRMA_SYNC = rb_define_class_under(mERR, "RMA_SYNC", rb_eStandardError); 1590 | eSERVICE = rb_define_class_under(mERR, "SERVICE", rb_eStandardError); 1591 | eSIZE = rb_define_class_under(mERR, "SIZE", rb_eStandardError); 1592 | eSPAWN = rb_define_class_under(mERR, "SPAWN", rb_eStandardError); 1593 | eUNSUPPORTED_DATAREP = rb_define_class_under(mERR, "UNSUPPORTED_DATAREP", rb_eStandardError); 1594 | eUNSUPPORTED_OPERATION = rb_define_class_under(mERR, "UNSUPPORTED_OPERATION", rb_eStandardError); 1595 | eWIN = rb_define_class_under(mERR, "WIN", rb_eStandardError); 1596 | eLASTCODE = rb_define_class_under(mERR, "LASTCODE", rb_eStandardError); 1597 | eSYSRESOURCE = rb_define_class_under(mERR, "SYSRESOURCE", rb_eStandardError); 1598 | } 1599 | --------------------------------------------------------------------------------