PetaMem has asked for the wisdom of the Perl Monks concerning the following question:

Hi, (Iīve searched for processor, SMP and multiprocessor here but didnīt find anything) How do I find out the number of CPUs on my system elegantly. I know of a relatively robust method under Linux, but it seems nonperlish nor seems it elegant nor seems it portable:

open FILE, "/proc/cpuinfo"; while(<FILE>) { if (/processor/) { $num_cpus++; } } close FILE; print $num_cpus;
Enlightment anyone?

Ciao

Replies are listed 'Best First'.
Re: Multiprocessor (SMP) system detection
by grinder (Bishop) on Jun 25, 2001 at 14:48 UTC

    That's probably about the best you can do.

    What you are trying to do is inherently non-portable, and one of Perl's strongest features is to be as portable as possible. In your case, you shall have to run

    perl -le 'print $^O'

    on as many systems as possible, and work out how to detect the number of CPU's in a platform-dependent way. All of this could be bundled in up in a module, e.g. System::CPU (there's probably a better category that already exists on CPAN to tell the truth). The code could look like:

    package System::CPU; use strict; sub nr_cpus { $^O eq 'linux' and return nr_cpus_linux(); $^O eq 'solaris' and return nr_cpus_solaris(); $^O eq 'palm' and return 1; 1; # default if we don't know any better } sub nr_cpus_linux { # your code here } sub nr_cpus_solaris { require Solaris::Funky::Stuff; Solaris::Funky::Stuff->import(); } 1;

    You could then get the number of CPUs by saying

    my $cpus = System::CPU::nr_cpus;

    You will have to ask yourself the question of what to do on a platform unknown to the script. In this particular case it probably makes sense to return 1, but in other contexts it may be wiser to die or croak (which could always be trapped by the caller in an eval.

    update: changed the example Solaris code a bit to show how you can include platform-dependent code at run-time.

    update: Thinking about your code over lunch I recalled that at least as recently as the late 2.0.x linux kernels, there was a problem with architecture-dependent /proc/cpuinfo files. You had to have two different ways of parsing the file depending on whether you were running on Intel or Alpha. Not sure if this is still true, and as I no longer have access to Alphas running Linux I cannot check this out. YMMV.


    --
    g r i n d e r
Re: Multiprocessor (SMP) system detection
by ariels (Curate) on Jun 25, 2001 at 15:55 UTC
    A reasonably portable way to do this is using the sysconf(3C) function. Unfortunately you can only call it from C.

    If you use the amazing Inline module, a function to get the number of CPUs is as easy as

    use Inline C => qq{
    #include <unistd.h>
    long nprocs() { return sysconf(_SC_NPROCESSORS_CONF); }
    };
    
    my $num_cpus = nprocs();
    

    This get the number of CPUs configured; replace "CONF" with "ONLN" to get the number of CPUs on line.

    UPDATE

    The standard module POSIX defines POSIX::sysconf. Unfortunately it doesn't appear to define the constants _SC_NPROCESSORS_CONF and _SC_NPROCESSORS_ONLN, so it doesn't solve your problem.
      Depending on his situation, it might be easier to build a table of known values for the constants and then just call sysconf anyway. As in:
      # Untested, but the constants are right use POSIX qw(sysconf); $const{linux}->{_SC_NPROCESSORS_CONF} = 83; $const{aix}->{_SC_NPROCESSORS_CONF} = 71; print sysconf($const{$^O}->{_SC_NPROCESSORS_CONF});
      If he's got more control over the target environment, he can use an h2ph-ish kind of tool to get them.
      This comment is actually more of a question.

      It seems to me that even though ANSI C may be widely available, any solution that involves calling a C function is inherently non-portable.

      I say that because in order to call a C function one would need to compile a call to the function. And even if ANSI C were widely available the mechanics of compiling C would differ. So no portable Makefile.PL could be created. Hence, non-portability.

        Well, if no portable Makefile.PL could be generated, Perl wouldn't be half as popular as it's today. Lots of modules on CPAN use C, including very popular ones like DBD::* and Date::Calc. All with a portable Makefile.PL That's what XS and the ExtUtils are for! And nowadays, the Inline family even gives us easy access to XS.

        -- Abigail

        Actually, the Inline module makes it possible to have C code that is compiled without changing your Makefile.PL on a number of systems. Now, whether the C code itself is portable depends on what it calls (for instance, there is no portable way to determine the number of processors). But it can be possible to make portable C routines that compile across platforms. Here's an example from the Inline::C::Cookbook :

        use Inline C => <<'END_C'; void greet() { printf("Hello, world\n"); } END_C greet;
Re: Multiprocessor (SMP) system detection
by MZSanford (Curate) on Jun 28, 2001 at 15:50 UTC
    I am in the process of uploading Sys::CPU to CPAN. This will woprk for Linux and Solaris machines (tested), but should also work for any machine with unistd.h and i think there is windows support, ahtough it is untested.
    may the foo be with you