grosser
grosser

Reputation: 15097

Detect number of CPUs installed

I already found a solution for "Most unixes" via cat /proc/cpuinfo, but a pure-Ruby solution would be nicer.

Upvotes: 48

Views: 19550

Answers (12)

Anko
Anko

Reputation: 1332

EDIT: Now rails ships with concurrent-ruby as a dependency so it's probably the best solution;

$ gem install concurrent-ruby
$ irb
irb(main):001:0> require 'concurrent'
=> true
irb(main):002:0> Concurrent.processor_count
=> 8
irb(main):003:0> Concurrent.physical_processor_count
=> 4

see http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent.html for more info. Because it does both physical and logical cores, it's better than the inbuilt Etc.nprocessors.

and here is the previous answer;

$ gem install facter
$ irb
irb(main):001:0> require 'facter'
=> true
irb(main):002:0> puts Facter.value('processors')['count']
4
=> nil
irb(main):003:0> 

This facter gem is the best if you want other facts about the system too, it's not platform specific and designed to do this exact thing.

UPDATE: updated to include Nathan Kleyn's tip on the api change.

Upvotes: 46

Brandon Anzaldi
Brandon Anzaldi

Reputation: 7270

As of Ruby version 2.2.3, the etc module in Ruby's stdlib offers an nprocessors method which returns the number of processors. The caveat to this, is that if ruby is relegated to a subset of CPU cores, Etc.nprocessors will only return the number of cores that Ruby has access to. Also, as seanlinsley pointed out, this will only return virtual cores instead of physical cores, which may result in a disparity in the expected value.

require 'etc'
p Etc.nprocessors #=> 4

Upvotes: 56

Konstantin Haase
Konstantin Haase

Reputation: 25954

Here is an implementation for Linux, OSX, Windows and BSD: https://gist.github.com/1009994

Source code:

module System
  extend self
  def cpu_count
    return Java::Java.lang.Runtime.getRuntime.availableProcessors if defined? Java::Java
    return File.read('/proc/cpuinfo').scan(/^processor\s*:/).size if File.exist? '/proc/cpuinfo'
    require 'win32ole'
    WIN32OLE.connect("winmgmts://").ExecQuery("select * from Win32_ComputerSystem").NumberOfProcessors
  rescue LoadError
    Integer `sysctl -n hw.ncpu 2>/dev/null` rescue 1
  end
end

System.cpu_count # => 2

Upvotes: 11

Paul Tobias
Paul Tobias

Reputation: 2193

In linux you can also use nproc, which is cleaner that the other subshell-based solutions here. I wanted vagrant to give the same number of CPUs to the virtual machine as the host has. I added this to Vagrantfile:

vb.cpus = `nproc`.to_i

Upvotes: 4

fakeleft
fakeleft

Reputation: 2900

Combination of @grosser's and @paxdiablo's answer, since on my system (winxp) win32_computersystem doesn't have any processor info; this works though:

require 'win32ole'
wmi = WIN32OLE.connect("winmgmts://")
info = wmi.ExecQuery ("select NumberOfCores from Win32_processor")
puts info.to_enum.first.NumberOfCores

To see what's available on your system, run this from powershell (i used 1.0 in this case):

Get-WmiObject -list

(might want to pipe to grep if you've got cygwin installed)

Upvotes: 0

ioquatix
ioquatix

Reputation: 1476

I tried using Facter but found it a bit slow. I tried system gem and found it a lot faster. It is also very easy to use: System::CPU.count.

Upvotes: 3

lsd
lsd

Reputation: 389

I found something recently that may have to be taken into consideration. You can deactivate processors (take them offline), and then facter processorcount (plus some of the other methods above) gives the wrong result. You can count processor lines in /proc/cpuinfo, as long as you do it correctly. If you just populate an array with index numbers of the procs, if you have gaps in the procs (as in, procs 0,1,2,10,11,12 are active, all others to 20 say are inactive), it will automatically spring indexes 3-9 into existence (sort of), at least Array#size will report 13 in that case. You would have to do #compact to get the number of active processors. However, if you want total processors, perhaps better is looking at /sys/devices/system/cpu[0-9], and count that up. That will give you the total number of processors, but not how many (or which ones) are active.

Just something to think about. I trying to put through a patch to facter to add an activeprocessorcount and totalprocessorcount fact.

Upvotes: 0

grosser
grosser

Reputation: 15097

I am currently using this, which covers all os. https://github.com/grosser/parallel/blob/master/lib/parallel.rb#L63

  def self.processor_count
    case RbConfig::CONFIG['host_os']
    when /darwin9/
      `hwprefs cpu_count`.to_i
    when /darwin/
      ((`which hwprefs` != '') ? `hwprefs thread_count` : `sysctl -n hw.ncpu`).to_i
    when /linux/
      `cat /proc/cpuinfo | grep processor | wc -l`.to_i
    when /freebsd/
      `sysctl -n hw.ncpu`.to_i
    when /mswin|mingw/
      require 'win32ole'
      wmi = WIN32OLE.connect("winmgmts://")
      cpu = wmi.ExecQuery("select NumberOfCores from Win32_Processor") # TODO count hyper-threaded in this
      cpu.to_enum.first.NumberOfCores
    end
  end

Upvotes: 31

Guest
Guest

Reputation: 11

@grosser:

when /linux/  
  `grep -c processor /proc/cpuinfo`.to_i

http://www.partmaps.org/era/unix/award.html#cat
http://www.partmaps.org/era/unix/award.html#wc

Upvotes: 1

Thiago Pradi
Thiago Pradi

Reputation:

on Mac:

thiago-pradis-macbook:~ tchandy$ hwprefs cpu_count

2

Upvotes: 1

dfa
dfa

Reputation: 116324

with JRuby you can check it with the following Java code:

 Runtime runtime = Runtime.getRuntime();   
 int numberOfProcessors = runtime.availableProcessors(); 

Upvotes: 11

paxdiablo
paxdiablo

Reputation: 881293

Surely if you can cat it, you can open, read and close it using the standard features of the language without resorting to a system()-type call.

You may just need to detect what platform you're on dynamically and either:

  • use the /proc/cpuinfo "file" for Linux; or
  • communicate with WMI for Windows.

That last line can use:

require 'win32ole'
wmi = WIN32OLE.connect("winmgmts://")
info = wmi.ExecQuery ("select * from Win32_ComputerSystem")

Then use info's NumberOfProcessors item.

Upvotes: 5

Related Questions