#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <sys/types.h>
/**************************************************************************************
* some of the code for the CPU information was copied and modilefied from *
* the source for Unix::Processors. All code contained herein in free to use and edit *
* under the same licence as Perl itself. *
* *
**************************************************************************************/
#define MAX_IDENT_SIZE 256
#if defined(_WIN32) || defined(WIN32)
#define _have_cpu_type
#define _have_cpu_clock
#define WINDOWS
#endif
#ifdef WINDOWS /* WINDOWS */
#include <stdlib.h>
#include <windows.h>
#include <winbase.h>
#include <winreg.h>
#else /* other (try unix) */
#include <unistd.h>
#include <sys/unistd.h>
#endif
#if defined(__sun) || defined(__sun__)
#include <sys/processor.h>
#endif
#ifdef _HPUX_SOURCE
#include <pthread.h>
#include <sys/pstat.h>
#define _have_cpu_clock
#define _have_cpu_type
#endif
#ifdef __APPLE__
#include <sys/sysctl.h>
#define _have_cpu_clock
#define _have_cpu_type
#endif
#ifdef WINDOWS
/* Registry Functions */
int GetSysInfoKey(char *key_name,char *output) {
// Get values from registry, use REGEDIT to see how data is stored while sample is running
int ret;
HKEY hTestKey, hSubKey;
DWORD dwRegType, dwBuffSize;
// Access using preferred 'Ex' functions
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Hardware\\Description\\System\\CentralProcessor", 0, KEY_READ, &hTestKey) == ERROR_SUCCESS) {
if (RegOpenKey(hTestKey, "0", &hSubKey) == ERROR_SUCCESS) {
dwBuffSize = MAX_IDENT_SIZE;
ret = RegQueryValueEx(hSubKey, key_name, NULL, &dwRegType, output, &dwBuffSize);
if (ret != ERROR_SUCCESS) {
sprintf(output,"Failed to get Value for key : %d\n",GetLastError());
return(1);
}
RegCloseKey(hSubKey);
} else {
sprintf(output,"Failed to open sub-key : %d\n",GetLastError());
return(1);
}
RegCloseKey(hTestKey);
}
else
{
sprintf(output,"Failed to open test key : %d\n",GetLastError());
return(1);
}
return(0);
}
#endif /* WINDOWS */
#ifdef _HPUX_SOURCE
/*
* HP specific function to return the clock-speed of a specified CPU in MHz.
*/
int proc_get_mhz(int id) {
struct pst_processor st;
int result = 0;
if( !(result = pstat_getprocessor(&st, sizeof(st), (size_t)1, id)) ) {
/* Maybe the CPU id too high, so try for CPU 0, instead. */
result = pstat_getprocessor(&st, sizeof(st), (size_t)1, 0);
}
if( result ) {
return st.psp_iticksperclktick * sysconf(_SC_CLK_TCK) / 1000000;
}
/* Call failed - return 0 for unknown clock speed. */
return 0;
}
/*
* Depending on your version of HP-UX, you may or may not already have these
* but we need them, so make sure that they are defined.
*/
#ifndef CPU_PA_RISC1_0
#define CPU_PA_RISC1_0 0x20B /* HP PA-RISC1.0 */
#endif
#ifndef CPU_PA_RISC1_1
#define CPU_PA_RISC1_1 0x210 /* HP PA-RISC1.1 */
#endif
#ifndef CPU_PA_RISC1_2
#define CPU_PA_RISC1_2 0x211 /* HP PA-RISC1.2 */
#endif
#ifndef CPU_PA_RISC2_0
#define CPU_PA_RISC2_0 0x214 /* HP PA-RISC2.0 */
#endif
#ifndef CPU_PA_RISC_MAX
#define CPU_PA_RISC_MAX 0x2FF /* Maximum for HP PA-RISC systems. */
#endif
#ifndef CPU_IA64_ARCHREV_0
#define CPU_IA64_ARCHREV_0 0x300 /* IA-64 archrev 0 */
#endif
const char *proc_get_type_name () {
long cpuvers = sysconf(_SC_CPU_VERSION);
switch(cpuvers) {
case CPU_PA_RISC1_0:
return "HP PA-RISC1.0";
case CPU_PA_RISC1_1:
return "HP PA-RISC1.1";
case CPU_PA_RISC1_2:
return "HP PA-RISC1.2";
case CPU_PA_RISC2_0:
return "HP PA-RISC2.0";
case CPU_IA64_ARCHREV_0:
return "IA-64 archrev 0";
default:
if( CPU_IS_PA_RISC(cpuvers) ) {
return "HP PA-RISC";
}
}
return "UNKNOWN HP-UX";
}
#endif /* _HPUX_SOURCE */
#ifdef __APPLE__
#ifndef POWERPC_G3
#define POWERPC_G3 0xcee41549
#endif
#ifndef POWERPC_G4
#define POWERPC_G4 0x77c184ae
#endif
#ifndef POWERPC_G5
#define POWERPC_G5 0xed76d8aa
#endif
#ifndef INTEL_6_13
#define INTEL_6_13 0xaa33392b
#endif
#ifndef ARM_9
#define ARM_9 0xe73283ae
#endif
#ifndef ARM_11
#define ARM_11 0x8ff620d8
#endif
#ifndef INTEL_PENRYN
#define INTEL_PENRYN 0x78ea4fbc
#endif
#ifndef INTEL_NEHALEM
#define INTEL_NEHALEM 0x6b5a4cd2
#endif
#ifndef INTEL_CORE
#define INTEL_CORE 0x73d67300
#endif
#ifndef INTEL_CORE2
#define INTEL_CORE2 0x426f69ef
#endif
char *apple_get_type_name() {
int mib[2];
size_t len=2;
int kp;
sysctlnametomib ("hw.cpufamily", mib, &len);
sysctl(mib, 2, NULL, &len, NULL, 0);
sysctl(mib, 2, &kp, &len, NULL, 0);
switch (kp) {
case POWERPC_G3:
return "POWERPC_G3";
case POWERPC_G4:
return "POWERPC_G4";
case POWERPC_G5:
return "POWERPC_G5";
case INTEL_6_13:
return "INTEL_6_13";
case ARM_9:
return "ARM_9";
case ARM_11:
return "ARM_11";
case INTEL_PENRYN:
return "INTEL_PENRYN";
case INTEL_NEHALEM:
return "INTEL_NEHALEM";
case INTEL_CORE:
return "INTEL_CORE";
case INTEL_CORE2:
return "INTEL_CORE2";
default:
return "UNKNOWN";
}
}
#endif /* __APPLE__ */
/* the following few functions were shamlessly taken from UNIX::Processors *
* to make this linux compatable. No linux machine to test on, so had to *
* use existing code */
#ifdef __linux__
#define _have_cpu_type
#define _have_cpu_clock
/* Return string from a field of /proc/cpuinfo, NULL if not found */
/* Comparison is case insensitive */
char *proc_cpuinfo_field (const char *field) {
FILE *fp;
static char line[1000];
int len = strlen(field);
char *result = NULL;
if (NULL!=(fp = fopen ("/proc/cpuinfo", "r"))) {
while (!feof(fp) && result==NULL) {
if (NULL == fgets (line, 990, fp) && !feof(fp)) break;
if (0==strncasecmp (field, line, len)) {
char *loc = strchr (line, ':');
if (loc) {
result = loc+2;
loc = strchr (result, '\n');
if (loc) *loc = '\0';
}
}
}
fclose(fp);
}
return (result);
}
/* Return clock frequency */
int proc_cpuinfo_clock (void) {
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);
}
#if defined __s390__ || defined __s390x__
/* Return machine value from s390 processor line, NULL if not found */
char *processor_machine_field (char *processor) {
char *machine = NULL;
if (NULL == processor) {
return NULL;
}
if (NULL != (machine = strstr(processor, "machine = "))) {
machine += 10;
}
return machine;
}
#endif
#endif
int get_cpu_count() {
int ret;
#ifdef WINDOWS /* WINDOWS */
SYSTEM_INFO info;
GetSystemInfo(&info);
ret = info.dwNumberOfProcessors;
#else /*other (try *nix)*/
#ifdef _HPUX_SOURCE /* HP-UX */
ret = pthread_num_processors_np();
#else /*other unix - try sysconf*/
ret = (int )sysconf(_SC_NPROCESSORS_ONLN);
#endif /* HP-UX */
#endif /* WINDOWS */
return ret;
}
MODULE = Sys::CPU PACKAGE = Sys::CPU
int
cpu_count()
CODE:
{
int i = 0;
i = get_cpu_count();
if (i) {
ST(0) = sv_newmortal();
sv_setiv (ST(0), i);
} else {
ST(0) = &PL_sv_undef;
}
}
int
cpu_clock()
CODE:
{
int clock = 0;
#ifdef __linux__
int value = proc_cpuinfo_clock();
if (value) clock = value;
#endif
#ifdef WINDOWS
char *clock_str = malloc(MAX_IDENT_SIZE);
/*!! untested !!*/
if (GetSysInfoKey("~MHz",clock_str)) {
clock = 0;
} else {
clock = atoi(clock_str);
}
#endif /* not linux, not windows, not hpux */
#ifdef _HPUX_SOURCE
/* Try to get the clock speed for processor 0 - assume all the same. */
clock = proc_get_mhz(0);
#endif
#ifdef __APPLE__
clock = CurrentProcessorSpeed();
#endif
#ifndef _have_cpu_clock
processor_info_t info, *infop=&info;
if ( processor_info(0, infop) == 0 && infop->pi_state == P_ONLINE) {
if (clock < infop->pi_clock) {
clock = infop->pi_clock;
}
}
#endif
if (clock) {
ST(0) = sv_newmortal();
sv_setiv (ST(0), clock);
} else {
ST(0) = &PL_sv_undef;
}
}
SV *
cpu_type()
CODE:
{
char *value = NULL;
#ifdef __linux__
#if defined __s390__ || defined __s390x__
value = processor_machine_field (proc_cpuinfo_field ("processor") );
#endif
if (!value) value = proc_cpuinfo_field ("model name");
if (!value) value = proc_cpuinfo_field ("machine");
if (!value) value = proc_cpuinfo_field ("vendor_id");
#endif
#ifdef WINDOWS
if (GetSysInfoKey("Identifier", value)) {
value = NULL;
}
#endif
#ifdef _HPUX_SOURCE
value = proc_get_type_name();
#endif
#ifdef __APPLE__
value = apple_get_type_name();
#endif
#ifndef _have_cpu_type /* not linux, not windows */
processor_info_t info, *infop=&info;
if (processor_info (0, infop)==0) {
value = infop->pi_processor_type;
}
#endif
if (value) {
ST(0) = sv_newmortal();
sv_setpv (ST(0), value);
} else {
ST(0) = &PL_sv_undef;
}
}