#/* -*- Mode: C -*- */
#/* Author: Wilson Snyder <wsnyder@wsnyder.org> */
#/* IRIX & FreeBSD port by: Daniel Gustafson <daniel@hobbit.se> */
#/*##################################################################### */
#/* */
#/* Copyright 1999-2017 by Wilson Snyder. This program is free software; */
#/* you can redistribute it and/or modify it under the terms of either the GNU */
#/* Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. */
#/* */
#/* This program is distributed in the hope that it will be useful, */
#/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
#/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
#/* GNU General Public License for more details. */
#/* */
#/*##################################################################### */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#if defined(_AIX)
# define AIX
#endif
#if defined(hpux) || defined(__hpux)
# define HPUX
#endif
#if defined(__osf__) && (defined(__alpha) || defined(__alpha__))
# define OSF_ALPHA
#endif
#if defined(__mips)
# define MIPS
# if defined(sgi)
# define IRIX
# endif
#endif
#if defined(sun) || defined(__sun__)
# define SUNOS
#endif
#ifdef AIX
# ifdef HAS_PMAPI
# include <pmapi.h>
# endif
# ifdef HAS_PERFSTAT
# include <libperfstat.h>
# endif
#endif
#ifdef HPUX
#include <sys/param.h>
#include <sys/pstat.h>
struct
pst_dynamic psd;
#endif
#ifdef OSF_ALPHA
#include <sys/sysinfo.h>
#include <machine/hal_sysinfo.h>
#endif
#if defined(MIPS) && !defined(__linux__)
#include <sys/systeminfo.h>
#endif
#ifdef IRIX
#include <dirent.h>
#include <sys/invent.h>
#include <sys/pda.h>
#include <sys/sbd.h>
#include <sys/sysmp.h>
#include <sys/iograph.h>
#include <invent.h>
#include <sys/param.h>
#endif
#ifdef SUNOS
#include <sys/processor.h>
#endif
#if defined(__FreeBSD__) || defined(__APPLE__)
#include <stdlib.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/param.h>
#endif
#ifndef P_POWEROFF
#define P_POWEROFF 5
#endif
typedef
int
CpuNumFromRef_t;
#/**************************************************************/
#ifdef __linux__
const
char
* proc_cpuinfo_field (
const
char
*field)
{
FILE
* fp;
static
char
line[1000];
static
char
result[1000];
int
len =
strlen
(field);
char
* resultp = NULL;
if
(NULL!=(fp =
fopen
(
"/proc/cpuinfo"
,
"r"
))) {
while
(!
feof
(fp)) {
const
char
* ok =
fgets
(line, 990, fp);
if
(ok && 0==strncasecmp (field, line, len)) {
char
*loc =
strchr
(line,
':'
);
if
(loc) {
strncpy
(result,loc+2, 990);
resultp = result;
loc =
strchr
(result,
'\n'
);
if
(loc) *loc =
'\0'
;
}
}
}
fclose
(fp);
}
return
(resultp);
}
int
_proc_cpuinfo_clock_calc (
void
)
{
const
char
* value;
value = proc_cpuinfo_field (
"cpu MHz"
);
if
(value)
return
(
atoi
(value));
value = proc_cpuinfo_field (
"clock"
);
if
(value)
return
(
atoi
(value));
value = proc_cpuinfo_field (
"bogomips"
);
if
(value)
return
(
atoi
(value));
return
(0);
}
int
proc_cpuinfo_clock (
void
)
{
static
int
cache = 0;
if
(!cache) cache = _proc_cpuinfo_clock_calc();
return
cache;
}
#endif
int
_proc_nthreaders_calc (
void
)
{
int
num_cpus = 0;
#ifdef HPUX
if
(pstat_getdynamic(&psd,
sizeof
(psd), (
size_t
)1, 0) != -1)
num_cpus = psd.psd_proc_cnt;
#endif
#ifdef OSF_ALPHA
getsysinfo(GSI_CPUS_IN_BOX,&num_cpus,
sizeof
(num_cpus),0,0)
#endif
#if defined(MIPS) && !defined(__linux__)
char
buf[16];
if
(sysinfo(_MIPS_SI_NUM_PROCESSORS, buf, 10) != -1)
num_cpus =
atoi
(buf);
#endif
#if defined(SUNOS) || defined(AIX) || defined(__APPLE__) || defined (__linux__)
if
(num_cpus < 1)
num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
# ifdef __linux__
if
(num_cpus < 1) {
const
char
* value = proc_cpuinfo_field(
"ncpus active"
);
if
(value) num_cpus =
atoi
(value);
}
# endif
#endif
#if defined(__FreeBSD__) || defined(HW_NCPU)
size_t
len =
sizeof
(num_cpus);
sysctlbyname(
"hw.ncpu"
, &num_cpus, &len, NULL, 0);
#endif
if
(num_cpus < 1)
num_cpus=1;
return
(num_cpus);
}
int
proc_nthreaders (
void
)
{
static
int
cache = 0;
if
(!cache) cache = _proc_nthreaders_calc();
return
cache;
}
#ifdef IRIX
invent_cpuinfo_t irix_get_cpuinf(
int
cpuid) {
union
{
invent_generic_t generic;
invent_cpuinfo_t cpu;
} hw_inv;
int
attr_len =
sizeof
(hw_inv);
DIR *hw_graph;
struct
dirent *hw_entry;
char
*hw_entry_buf = (
char
*)
malloc
(MAXPATHLEN);
char
*hw_filename = (
char
*)
malloc
(MAXPATHLEN);
if
((hw_graph = opendir(
"/hw/cpunum"
)) != NULL) {
while
((hw_entry = readdir(hw_graph)) != NULL) {
if
((
strcmp
(hw_entry->d_name,
"."
) != 0) && (
strcmp
(hw_entry->d_name,
".."
) != 0)) {
strcpy
(hw_filename,
"/hw/cpunum/"
);
strncat
(hw_filename, hw_entry->d_name, 1);
if
(realpath(hw_filename, hw_entry_buf) != NULL) {
if
(attr_get(hw_entry_buf, INFO_LBL_DETAIL_INVENT, (
char
*)&hw_inv, &attr_len, 0) == 0) {
if
(hw_inv.generic.ig_invclass == INV_PROCESSOR) {
if
(hw_inv.cpu.ic_cpuid == cpuid) {
break
;
}
}
}
}
}
}
}
closedir(hw_graph);
return
(hw_inv.cpu);
}
#endif
int
logical_per_physical_cpu() {
int
logical_per = 1;
#ifdef __linux__
const
char
* flags = proc_cpuinfo_field (
"flags"
);
if
(flags &&
strstr
(flags,
" ht "
)) {
logical_per = 2;
}
#endif
#ifdef __FreeBSD__
int
hlt_htt_cpu = 0;
size_t
len =
sizeof
(hlt_htt_cpu);
if
(sysctlbyname(
"machdep.hlt_logical_cpus"
,
&hlt_htt_cpu, &len, NULL, 0) == 0) {
if
(hlt_htt_cpu == 0) {
logical_per = 2;
}
}
#endif
return
logical_per;
}
int
proc_num_physical_ids() {
#ifdef __linux__
{
const
char
* value = proc_cpuinfo_field (
"physical id"
);
if
(value) {
int
phys =
atoi
(value)+1;
return
phys;
}
}
#endif
return
0;
}
int
_proc_ncores_calc() {
int
num = proc_nthreaders();
#ifdef __linux__
{
int
phys = proc_num_physical_ids();
const
char
* cvalue = proc_cpuinfo_field (
"cpu cores"
);
if
(phys && cvalue) {
int
cores_per_phys =
atoi
(cvalue);
int
cores = phys * cores_per_phys;
if
(cores && (cores <= num))
return
cores;
}
}
#endif
{
if
(num > 1) {
num /= logical_per_physical_cpu();
}
return
num;
}
}
int
proc_ncores() {
static
int
cache = 0;
if
(!cache) cache = _proc_ncores_calc();
return
cache;
}
int
_proc_nsockets_calc() {
int
num = proc_ncores();
int
phys = proc_num_physical_ids();
if
(phys && ((phys <= num))) num = phys;
return
num;
}
int
proc_nsockets() {
static
int
cache = 0;
if
(!cache) cache = _proc_nsockets_calc();
return
cache;
}
MODULE = Unix::Processors PACKAGE = Unix::Processors
#/**********************************************************************/
#/* class->max_online() */
#/* Self is a argument, but we don't need it */
#/* We use sysconf, as that is more portable */
#/* Other packages also provide sysconf, but saves downloading them... */
long
max_online(self)
SV *self;
CODE:
{
if
(self) {}
RETVAL = proc_nthreaders();
}
OUTPUT: RETVAL
#/**********************************************************************/
#/* class->max_physical() */
#/* Self is a argument, but we don't need it */
long
max_physical(self)
SV *self;
CODE:
{
if
(self) {}
RETVAL = proc_ncores();
}
OUTPUT: RETVAL
#/**********************************************************************/
#/* class->max_socket() */
#/* Self is a argument, but we don't need it */
long
max_socket(self)
SV *self;
CODE:
{
if
(self) {}
RETVAL = proc_nsockets();
}
OUTPUT: RETVAL
#/**********************************************************************/
#/* class->max_clock() */
#/* Self is a argument, but we don't need it */
int
max_clock(self)
SV *self;
CODE:
{
int
clock
= 0;
#ifdef AIX
# if defined(HAS_PERFSTAT)
perfstat_cpu_total_t data;
if
(perfstat_cpu_total (0, &data,
sizeof
(data), 1)) {
clock
= data.processorHZ / 1000000;
}
# elif defined(HAS_PMAPI)
clock
= (
int
)((pm_cycles() + 500000) / 1000000);
# endif
#endif
#ifdef HPUX
struct
pst_processor psp;
if
(pstat_getprocessor(&psp,
sizeof
(psp), 1, 0)) {
clock
= psp.psp_iticksperclktick / 10000;
}
#endif
#ifdef SUNOS
int
cpu;
int
last_cpu = 0;
processor_info_t info, *infop=&info;
for
(cpu=0; cpu < last_cpu+16; cpu++) {
if
(processor_info (cpu, infop)==0
&& infop->pi_state == P_ONLINE) {
if
(
clock
< infop->pi_clock) {
clock
= infop->pi_clock;
}
last_cpu = cpu;
}
}
#endif
#ifdef IRIX
int
num_cpus = proc_nthreaders();
if
((num_cpus > 0) && (num_cpus < 3)) {
inventory_t *sys_invent;
if
(setinvent() != -1) {
for
(sys_invent = getinvent(); (sys_invent); sys_invent = getinvent()) {
if
((sys_invent->inv_class == INV_PROCESSOR) && (sys_invent->inv_type == INV_CPUBOARD)) {
clock
= sys_invent->inv_controller;
break
;
}
}
endinvent();
}
}
else
{
invent_cpuinfo_t cpu_info;
int
i;
for
(i = 0; i < proc_nthreaders(); i++) {
cpu_info = irix_get_cpuinf(i);
if
(cpu_info.ic_cpuid == i)
if
(cpu_info.ic_cpu_info.cpufq >
clock
)
clock
= cpu_info.ic_cpu_info.cpufq;
}
}
#endif
#if (defined(__FreeBSD__) && (__FreeBSD_version >= 503105))
int
value = 0;
size_t
len =
sizeof
(value);
if
(sysctlbyname(
"dev.cpu.0.freq"
, &value, &len, NULL, 0) == 0) {
clock
= value;
}
#elif defined(HW_CPU_FREQ)
long
long
value = 0;
size_t
len =
sizeof
(value);
if
(sysctlbyname(
"hw.cpufrequency"
, &value, &len, NULL, 0) == 0) {
clock
= value;
}
#endif
#ifdef __linux__
int
value = proc_cpuinfo_clock();
if
(value)
clock
= value;
#endif
if
(self) {}
RETVAL =
clock
;
}
OUTPUT: RETVAL
#/**********************************************************************/
#/**********************************************************************/
#/**********************************************************************/
#/**********************************************************************/
#/**********************************************************************/
MODULE = Unix::Processors PACKAGE = Unix::Processors::Info
#/**********************************************************************/
#/* class->id() */
int
id (cpu)
CpuNumFromRef_t cpu
PROTOTYPE: $
CODE:
{
RETVAL = cpu;
}
OUTPUT: RETVAL
#/**********************************************************************/
#/* class->clock() */
SV *
clock
(cpu)
CpuNumFromRef_t cpu
PROTOTYPE: $
CODE:
{
int
value = 0;
#ifdef AIX
int
num_cpus = proc_nthreaders();
if
(cpu < num_cpus) {
# if defined(HAS_PERFSTAT)
perfstat_cpu_total_t data;
if
(perfstat_cpu_total (0, &data,
sizeof
(data), 1)) {
value = data.processorHZ / 1000000;
}
# elif defined(HAS_PMAPI)
clock
= (
int
)((pm_cycles() + 500000) / 1000000);
# endif
}
#endif
#ifdef HPUX
int
num_cpus = proc_nthreaders();
if
(cpu < num_cpus) {
struct
pst_processor psp;
if
(pstat_getprocessor(&psp,
sizeof
(psp), 1, 0)) {
value = psp.psp_iticksperclktick / 10000;
}
}
#endif
#ifdef SUNOS
processor_info_t info, *infop=&info;
if
(processor_info (cpu, infop)==0) {
value = infop->pi_clock;
}
#endif
#ifdef IRIX
int
num_cpus = proc_nthreaders();
if
((num_cpus > 0) && (num_cpus < 3)) {
inventory_t *sys_invent;
if
(setinvent() != -1) {
while
((sys_invent = getinvent()) != NULL) {
if
((sys_invent->inv_class == INV_PROCESSOR) && (sys_invent->inv_type == INV_CPUBOARD)) {
value = sys_invent->inv_controller;
break
;
}
}
endinvent();
}
}
else
{
invent_cpuinfo_t cpu_info;
cpu_info = irix_get_cpuinf(cpu);
if
(cpu_info.ic_cpuid == cpu)
value = cpu_info.ic_cpu_info.cpufq;
}
#endif
#if (defined(__FreeBSD__) && (__FreeBSD_version >= 503105))
int
cpu_freq = 0;
size_t
len =
sizeof
(cpu_freq);
char
cpu_freq_req[16];
snprintf(cpu_freq_req, 16,
"dev.cpu.%d.freq"
, cpu);
if
(sysctlbyname(cpu_freq_req, &cpu_freq, &len, NULL, 0) == 0) {
value = cpu_freq;
}
#endif
#ifdef __linux__
value = proc_cpuinfo_clock();
#endif
if
(value) {
ST(0) = sv_newmortal();
sv_setiv (ST(0), value);
}
else
{
ST(0) = &PL_sv_undef;
}
}
#/**********************************************************************/
#/* class->state() */
SV *
state (cpu)
CpuNumFromRef_t cpu
PROTOTYPE: $
CODE:
{
char
*value = NULL;
#ifdef SUNOS
processor_info_t info, *infop=&info;
if
(processor_info (cpu, infop)==0) {
switch
(infop->pi_state) {
case
P_ONLINE:
value =
"online"
;
break
;
case
P_OFFLINE:
value =
"offline"
;
break
;
case
P_POWEROFF:
value =
"poweroff"
;
break
;
}
}
#endif
#ifdef IRIX
int
num_cpus;
if
((num_cpus = sysmp(MP_NPROCS)) != -1) {
struct
pda_stat proc_info[num_cpus];
if
(sysmp(MP_STAT, proc_info) != -1) {
if
(proc_info[cpu].p_flags == PDAF_MASTER)
value =
"MASTER"
;
else
if
(proc_info[cpu].p_flags == PDAF_CLOCK)
value =
"CLOCK"
;
else
if
(proc_info[cpu].p_flags == PDAF_ENABLED)
value =
"ENABLED"
;
else
if
(proc_info[cpu].p_flags == PDAF_FASTCLOCK)
value =
"FASTCLOCK"
;
else
if
(proc_info[cpu].p_flags == PDAF_ISOLATED)
value =
"ISOLATED"
;
else
if
(proc_info[cpu].p_flags == PDAF_BROADCAST_OFF)
value =
"BROADCAST_OFF"
;
else
if
(proc_info[cpu].p_flags == PDAF_NONPREEMPTIVE)
value =
"NONPREEMPTIVE"
;
else
if
(proc_info[cpu].p_flags == PDAF_NOINTR)
value =
"NOINTR"
;
else
if
(proc_info[cpu].p_flags == PDAF_ITHREADSOK)
value =
"ITHREADSOK"
;
else
if
(proc_info[cpu].p_flags == PDAF_DISABLE_CPU)
value =
"DISABLE_CPU"
;
else
if
(proc_info[cpu].p_flags == PDAF_EXCLUDED)
value =
"EXCLUDED"
;
else
value =
"ONLINE"
;
}
}
#endif
if
(value == NULL)
value =
"online"
;
if
(value) {
ST(0) = sv_newmortal();
sv_setpv (ST(0), value);
}
else
{
ST(0) = &PL_sv_undef;
}
}
#/**********************************************************************/
#/* class->type() */
SV *
type (cpu)
CpuNumFromRef_t cpu
PROTOTYPE: $
CODE:
{
const
char
* value = NULL;
#ifdef AIX
# if defined(HAS_PERFSTAT)
int
num_cpus = proc_nthreaders();
if
(cpu < num_cpus) {
perfstat_cpu_total_t data;
if
(perfstat_cpu_total (0, &data,
sizeof
(data), 1)) {
value = data.description;
}
}
# endif
#endif
#ifdef HPUX
int
num_cpus = proc_nthreaders();
if
(cpu < num_cpus) {
switch
(sysconf(_SC_CPU_VERSION)) {
case
CPU_PA_RISC1_0:
value =
"HP PA-RISC 1.0"
;
break
;
case
CPU_PA_RISC1_1:
value =
"HP PA-RISC 1.1"
;
break
;
case
CPU_PA_RISC1_2:
value =
"HP PA-RISC 1.2"
;
break
;
case
CPU_PA_RISC2_0:
value =
"HP PA-RISC 2.0"
;
break
;
}
}
#endif
#ifdef SUNOS
processor_info_t info, *infop=&info;
if
(processor_info (cpu, infop)==0) {
value = infop->pi_processor_type;
}
#endif
#ifdef __linux__
int
ncpu = proc_nthreaders();
if
(cpu < ncpu) {
value = proc_cpuinfo_field (
"model name"
);
if
(!value) value = proc_cpuinfo_field (
"machine"
);
if
(!value) value = proc_cpuinfo_field (
"family"
);
}
#endif
#if defined(MIPS) && !defined(__linux__)
if
(cpu < proc_nthreaders()) {
if
((value = (
char
*)
malloc
(64)) != NULL) {
sysinfo(SI_MACHINE, value, 64);
}
}
#endif
#ifdef IRIX
if
(cpu < proc_nthreaders()) {
int
cpu_data = 0;
int
num_cpus = proc_nthreaders();
if
((num_cpus > 0) && (num_cpus < 3)) {
inventory_t *sys_invent;
if
(setinvent() != -1) {
while
((sys_invent = getinvent()) != NULL) {
if
((sys_invent->inv_class == INV_PROCESSOR) && (sys_invent->inv_type == INV_CPUCHIP)) {
cpu_data = sys_invent->inv_state;
break
;
}
}
endinvent();
}
}
else
{
invent_cpuinfo_t cpu_info;
cpu_info = irix_get_cpuinf(cpu);
if
(cpu_info.ic_cpuid == cpu)
cpu_data = cpu_info.ic_cpu_info.cpuflavor;
}
if
(cpu_data != 0) {
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R2000A)
strcat
(value,
" MIPS R2000A"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R2000)
strcat
(value,
" MIPS R2000A"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R3000A)
strcat
(value,
" MIPS R3000A"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R3000)
strcat
(value,
" MIPS R3000"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R4000) {
if
(((cpu_data&C0_MAJREVMASK)>>C0_MAJREVSHIFT) >= C0_MAJREVMIN_R4400)
strcat
(value,
" MIPS R4400"
);
else
strcat
(value,
" MIPS R4000"
);
}
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R4650)
strcat
(value,
" MIPS R4650"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R4700)
strcat
(value,
" MIPS R4700"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R4600)
strcat
(value,
" MIPS R4600"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R5000)
strcat
(value,
" MIPS R5000"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_RM5271)
strcat
(value,
" MIPS RM5271"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R6000A)
strcat
(value,
" MIPS R6000A"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R6000)
strcat
(value,
" MIPS R6000"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_RM7000)
strcat
(value,
" MIPS RM7000"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R8000)
strcat
(value,
" MIPS R8000"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R10000)
strcat
(value,
" MIPS R10000"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R12000)
strcat
(value,
" MIPS R12000"
);
else
if
((cpu_data >> C0_IMPSHIFT) == C0_IMP_R14000)
strcat
(value,
" MIPS R14000"
);
else
strcat
(value,
" Undefined MIPS"
);
sprintf
(value,
"%s Chip Rev: %x.%x"
, value, ((cpu_data&C0_MAJREVMASK)>>C0_MAJREVSHIFT), ((cpu_data&C0_MINREVMASK)>>C0_MINREVSHIFT));
}
}
#endif
#ifdef __FreeBSD__
if
(cpu < proc_nthreaders()) {
if
((value = (
char
*)
malloc
(64)) != NULL) {
size_t
len = 64;
sysctlbyname(
"hw.machine_arch"
, value, &len, NULL, 0);
}
}
#endif
if
(value) {
ST(0) = sv_newmortal();
sv_setpv (ST(0), value);
}
else
{
ST(0) = &PL_sv_undef;
}
}