SUMMANY: Problem finding number of CPUs online

From: Dr. David Kirkby (drkirkby@ntlworld.com)
Date: Mon Jun 09 2003 - 14:05:34 EDT


Thanks to everyone who came up with solutions on my original query on
how to find the number of CPUs online, using system calls, rather than
utilities at the command line.

I was trying to read the contents of the cpu_state structure at
/usr/include/machine/hal_sysinfo.h
using getsysinfo().

Thanks to Rebecca Naughton, Dr Thomas.Blinn, Spider Boardman, Oisin
McGuinness, Alan Rollow, Alan Davis and Peter.Wolfe. Sorry if I forgot
anyone.

It has been pointed out to me that getsysinfo() is Tru64 specific and
so not portable. I want the program to be portable - someone even
built it on a Sony Playstation 2 running under NetBSD !! However, it
clear some of system calls that get information from the kernel are
never going to be as portable as printf().

Several people suggested ways of getting the number of cpus, without
using the structure I was trying to use.

These included:

1) The simplest is the function call cpu_get_num() - you can't get
much simpler than that! That exists in Tru64, but not Solaris, so I
guess is probably quite Tru64 specific.

2) Another way is calling sysconf(_SC_NPROCESSORS_ONLN) to find the
number online. sysconf(_SC_NPROCESSORS_CONF) tells you the number of
processors in the system and sysconf(_SC_NPROCESSORS_MAX) tells you
the maximum number of processors a system will take.

sysconf() seems to be quite portable.

3) I was shown how to read the cpu_state structure properly and make
sense of it. This is undoubtedly an overly complex way of getting
*just* the information I asked for (since there are easier ways), but
this structure contains a lot of information that I suspect there is
no other way of obtaining. For example, you can get the CPU speed,
that you can't get using sysconf(). There's a lot of information in
the structure.

For this reason, I'm using a combination of sysconf() and
getsysinfo(), to get the data I wanted in a portable manner and a bit
more in a less portable manner.

Here's how to read the cpu_state structure properly.

#include <sys/sysinfo.h>
#include <machine/hal_sysinfo.h>
#include <errno.h>

main()
{
char *mhz, *cpu_type;
int cpuid,num_cpus,status;
struct cpu_state cpu_state_buffer;
struct cpu_info cpu_info_buffer;

bzero(&cpu_state_buffer, sizeof(cpu_state_buffer));
        cpusetcreate(&cpu_state_buffer.cs_configured);
        cpusetcreate(&cpu_state_buffer.cs_available);
        cpusetcreate(&cpu_state_buffer.cs_present);
        cpusetcreate(&cpu_state_buffer.cs_primary_eligible);
        cpusetcreate(&cpu_state_buffer.cs_binding);
        cpusetcreate(&cpu_state_buffer.cs_running);
        cpusetcreate(&cpu_state_buffer.cs_ex_binding);

errno=0;
if (getsysinfo(GSI_CPU_STATE,
            (void *)&cpu_state_buffer,
               (unsigned long)sizeof(struct cpu_state),0,0) < 0) {

    perror("Error");

}

num_cpus= cpucountset(cpu_state_buffer.cs_running);

}

4) And here is anothe piece of code sent to me, that was written some
time ago. It will be interesting to see how this works on Tru64 5.1B,
as I'd like to use something that works on older systems.

/* hinv.c: based on a news-post by Randy M. Hayman
(haymanr@icefog.alaska.edu)
 *
 * Hacked by Rob Hooft (hooft@embl-heidelberg.de). Version 1.1, Aug
14, 1996
 *
 * (C) 1996 Rob Hooft, EMBL. Distribute freely.
 */

#include <stdio.h>
#include <sys/sysinfo.h>
#include <machine/hal_sysinfo.h>
#include <machine/cpuconf.h>

#define debug(x) /* printf(x) */

/*
 * Some return buffers for different calls
 */

int status, int_buff, start;

#if defined(GSI_CPU_INFO) /* 3.x onwards? */
struct cpu_info buf;
#endif

struct { int width, height; } resbuf;

char gratype[9];

char hw[100];

long long_buf;

char *procid;

/*
 * CPU Id strings
 */

char *cpustr[]={
  /* 0 */ "UNKN_SYSTEM",
  /* 1 */ "VAX_780",
  /* 2 */ "VAX_750",
  /* 3 */ "VAX_730",
  /* 4 */ "VAX_8600",
  /* 5 */ "VAX_8200",
  /* 6 */ "VAX_8800",
  /* 7 */ "MVAX_I",
  /* 8 */ "MVAX_II",
  /* 9 */ "V_VAX Virtual VAX",
  /* 10 */ "VAX_3600 Mayfair I",
  /* 11 */ "VAX_6200 CVAX/Calypso",
  /* 12 */ "VAX_3400 Mayfair II",
  /* 13 */ "C_VAXSTAR VAX3100 (PVAX)",
  /* 14 */ "VAX_60 Firefox",
  /* 15 */ "VAX_3900 Mayfair III",
  /* 16 */ "DS_3100 DECstation 3100 (PMAX)",
  /* 17 */ "VAX_8820 Polarstar",
  /* 18 */ "DS_5400 MIPSfair",
  /* 19 */ "DS_5800 ISIS",
  /* 20 */ "DS_5000 3MAX",
  /* 21 */ "DS_CMAX",
  /* 22 */ "VAX_6400 RIGEL/Calypso",
  /* 23 */ "VAXSTAR",
  /* 24 */ "DS_5500 MIPSFAIR-2",
  /* 25 */ "DS_5100 MIPSMATE",
  /* 26 */ "VAX_9000",
  /* 27 */ "DS_5000_100 3MIN",
  /* 28 */ "ALPHA_ADU",
  /* 29 */ "DEC_4000 Cobra",
  /* 30 */ "DEC_3000_500 Flamingo workstation",
  /* 31 */ "DEC_7000 EV4 on Lazer platform",
  /* 32 */ "DS_5000_300 3MAX+/BIGMAX",
  /* 33 */ "DEC_3000_300 Pelican workstation",
  /* 34 */ "DEC_2000_300 Jensen Alpha PC",
  /* 35 */ "DEC_2100_A500 Sable",
  /* 36 */ "LCA_MUSTANG Mustang Desktop PC",
  /* 37 */ "DEC_2100_A50 Avanti Alpha PC system",
  /* 38 */ "ALPHA_KN20AA kn20aa workstation",
  /* 39 */ "DEC_21000 TurboLaser",
  /* 40 */ "DEC_AXPVME_64 Medulla",
  /* 41 */ "DEC_2100_C500 Gamma",
  /* 42 */ "DEC_AXPPCI_33",
  /* 43 */ "DEC_1000 Mikasa APS Server",
  /* 44 */ "EB64_PLUS EB64+ Evaluation Board",
  /* 45 */ "LCA_EB66 EB66 Evaluation Board",
  /* 46 */ "ALPHA_EB164 EB164 Evaluation Board",
  /* 47 */ "EV45_PBP LEGO K2 Passive Backplane SBC",
  /* 48 */ "DEC_1000A -Noritake",
  /* 49 */ "DEC_4100 RAWHIDE ",
  /* 50 */ "DEC_ALPHAVME_224 Cortex",
  /* 51 */ "DEC_1000_5 Mikasa/Pinnacle",
  /* 52 */ "DEC_1000A_5 Noritake/Pinnacle",
  /* 53 */ "DEC_EV56_PBP TAKARA Passive Backplance SBC",
  /* 54 */ "ALPHABOOK_1 Alphabook1",
  /* 55 */ "DEC_ALPHAVME_320 Yukon",
  /* 56 */ "DEC_550",
  /* 57 */ "DEC_6600 EV6-Tsunami based systems ",
  /* 58 */ "DMCC_EV6 EV6 Eiger DMCC passive bacplane system",
  /* 59 */ "ALPHA_WILDFIRE EV6-Wildfire systype "
};

#if CPU_MAX>59
#error Please check list of cpu names in
/usr/include/machine/hal/cpuconf.h
#endif

int main()
{
#if defined(GSI_PLATFORM_NAME)
  if (getsysinfo(GSI_PLATFORM_NAME,(caddr_t)hw,sizeof(hw),0,0)<0) {
    debug("O/S might be too old to get platform name\n");
  } else {
    printf("Platform name : %s\n", hw);
  }
#endif
#if defined(GSI_PHYSMEM)
  if
(getsysinfo(GSI_PHYSMEM,(caddr_t)&int_buff,sizeof(int_buff),0,0)<0) {
    debug("error getting GSI_PHYSMEM\n");
  } else {
    printf("Physical memory : %7d kB\n", int_buff);
  }
#endif
#if defined(GSI_PROC_TYPE)
  if
(getsysinfo(GSI_PROC_TYPE,(caddr_t)&long_buf,sizeof(long_buf),0,0)<0)
{
    debug("O/S might be too old to get processor type\n");
  } else {
    long_buf&=0xffffffff;
#if defined(CPU_TYPE_TO_TEXT)
    CPU_TYPE_TO_TEXT(long_buf,procid);
    printf("Processor type : %7ld [%s]\n", long_buf,procid);
#else
    printf("Processor type : %7ld\n", long_buf);
#endif
  }
#endif
#if defined(GSI_CPU_INFO)
  if (getsysinfo(GSI_CPU_INFO,(caddr_t)&buf,sizeof(buf),0,0)<0) {
    debug("O/S might be too old to ask for CPU info\n");
#endif
    if (getsysinfo(GSI_CPU,(caddr_t)&int_buff,sizeof(int_buff),0,0)<0)
{
      debug("Error getting GSI_CPU\n");
    } else {
      printf("CPU type : %7d [%s]\n", int_buff,
cpustr[int_buff]);
    }
#if defined(GSI_CPUS_IN_BOX)
    if
(getsysinfo(GSI_CPUS_IN_BOX,(caddr_t)&int_buff,sizeof(int_buff),0,0)<0)
{
      debug("O/S might be too old to get # of CPU's in box\n");
    } else {
      printf("CPU's in box : %7d\n", int_buff);
    }
#endif
#if defined(GSI_CPU_INFO)
  } else {
    printf("Current CPU : %7d\n", buf.current_cpu);
    printf("CPU's in box : %7d\n", buf.cpus_in_box);
    printf("CPU type : %7d [%s]\n", buf.cpu_type,
cpustr[buf.cpu_type]);
#if defined(GSI_PLATFORM_NAME) /* Dirty hack: how do I detect 4.0? */
    if (buf.mhz>1000 || buf.mhz<10) {
      debug("O/S might be too old to ask for CPU clock\n"); /*
pre-4.0? */
    } else {
      printf("CPU speed : %7d MHz\n",buf.mhz); /* 4.0
onwards? */
    }
#endif
  }
#endif
#if defined(GSI_CLK_TCK)
  if
(getsysinfo(GSI_CLK_TCK,(caddr_t)&int_buff,sizeof(int_buff),0,0)<0) {
    debug("error getting GSI_CLK_TCK\n");
  } else {
    printf("Time slices : %7d Hz\n", int_buff);
  }
#endif
#if defined(GSI_GRAPHICTYPE)
  start=0;
  while (1) {
   
if(getsysinfo(GSI_GRAPHICTYPE,(caddr_t)gratype,sizeof(gratype),&start,0)<0)
{
      debug("O/S might be too old to get graphic type\n");
    } else {
      if (start<0) break;
      gratype[8]=0;
      printf("Graphic type [unit %d]: %s\n", start,gratype);
    }
    if (!start) break;
  }
#endif
#if defined(GSI_GRAPHIC_RES)
  start=0;
  while (1) {
   
if(getsysinfo(GSI_GRAPHIC_RES,(caddr_t)&resbuf,sizeof(resbuf),&start,0)<0)
{
      debug("O/S might be too old to get graphic resolution\n");
    } else {
      if (start<0) break;
      printf("Graphic res [unit %d]: %dx%d\n",
start,resbuf.width,resbuf.height);
    }
    if (!start) break;
  }
#endif
  return 0;
}

-- 
Dr. David Kirkby,
Senior Research Fellow,
Department of Medical Physics,
University College London,
11-20 Capper St, London, WC1E 6JA.
Tel: 020 7679 6408 Fax: 020 7679 6269
Internal telephone: ext 46408
e-mail davek@medphys.ucl.ac.uk


This archive was generated by hypermail 2.1.7 : Sat Apr 12 2008 - 10:49:21 EDT