Howdy Ganglia Developers,
Doh!!!!
When I downloaded 2.5 on Thursday and noticed the lack of HP-UX support,
I should've checked the developers list to see if anyone was doing
such a thing.
Browsing the archives, I see someone already has.
Anyway, I've attached my take thus far on an hpux.c. I haven't looked
at Martin's code yet so I don't know if it is helpful or how the
two can be merged.
It requires the use of -D_PSTAT64 on 64-bit wide HP-SUX 11.0.
Or it will.
The code was/is still in transition. Needs cleanup in a few places
and I still haven't figured out what coding style is used in most
the ganglia code and therefore not sure how to best clean it up...
I tried to use the style in linux.c but it was irksome and I know
I have places that don't follow it.
Just thought I'd toss it out and perhaps between me an
Martin we can nail it down.
What I have works on are R390 and I'm sure once I recompile
it wide, it will work on our V2200, but I'm stopping work
on it for the day (or so I think).
HIH,
jack
[EMAIL PROTECTED]
#include <time.h>
#include <unistd.h>
#include <sys/pstat.h>
#include <sys/utsname.h>
#include "ganglia.h"
#include "metric_typedefs.h"
/*
#include "set_metric_val.h"
*/
#define OSNAME "HP-UX"
#define OSNAME_LEN strlen(OSNAME)
/* buffer and keep global some info */
struct pst_static staticinfo;
int cpu_num_func_cpu_num = 0;
/*
* This function is called only once by the gmond. Use to
* initialize data structures, etc or just return SYNAPSE_SUCCESS;
*/
g_val_t
metric_init(void)
{
g_val_t rval;
if( -1 == pstat_getstatic( &staticinfo, sizeof(struct pst_static), 1, 0)){
err_msg("metric_init() got an error from pstat_getstatic()");
rval.int32 = SYNAPSE_FAILURE;
return rval;
}
rval.int32 = SYNAPSE_SUCCESS;
return rval;
}
#ifdef NOTYETJKP
g_val_t
pkts_in_func ( void )
{
char *p;
register int i;
static g_val_t val;
int size;
static int stamp;
static double last_bytes_in,
last_bytes_out,
last_pkts_in,
last_pkts_out;
double bytes_in, bytes_out, pkts_in, pkts_out, t = 0;
unsigned long diff;
p = update_file(&proc_net_dev);
if (proc_net_dev.last_read != stamp) {
size = ( index (p, 0x00) ) - p;
/* skip past the two-line header ... */
p = index (p, '\n')+1;
p = index (p, '\n')+1;
p = index (p, '\n')+1; // and skip loopback, which is always the first one
while (*p != 0x00 )
{
p = index(p, ':')+1; /* skip past the interface tag portion of this
line */
if ( (*p-1 != 'o') && (*p-2 != 'l') )
{
t = strtod( p, &p );
bytes_in += t;
t = strtod( p, &p );
pkts_in += t;
for (i = 0; i < 6; i++) strtol(p, &p, 10);
t == strtod( p, &p );
bytes_out += t;
pkts_out += strtod( p, &p );
}
p = index (p, '\n') + 1; // skips a line
}
(unsigned long) diff = pkts_in - last_pkts_in;
if ( diff )
{
t = proc_net_dev.last_read - stamp;
t = diff / t;
debug_msg("Returning value: %f\n",t);
}
else
t = 0;
val.f = t;
last_bytes_in = bytes_in;
last_pkts_in = pkts_in;
last_pkts_out = pkts_out;
last_bytes_out = bytes_out;
stamp = proc_net_dev.last_read;
}
return val;
}
g_val_t
pkts_out_func ( void )
{
char *p;
register int i;
static g_val_t val;
int size;
static int stamp;
static double last_bytes_in,
last_bytes_out,
last_pkts_in,
last_pkts_out;
double bytes_in, bytes_out, pkts_in, pkts_out, t = 0;
unsigned long diff;
p = update_file(&proc_net_dev);
if (proc_net_dev.last_read != stamp) {
size = ( index (p, 0x00) ) - p;
/* skip past the two-line header ... */
p = index (p, '\n')+1;
p = index (p, '\n')+1;
p = index (p, '\n')+1; // and skip loopback, which is always the first one
while (*p != 0x00 )
{
p = index(p, ':')+1; /* skip past the interface tag portion of this
line */
if ( (*p-1 != 'o') && (*p-2 != 'l') )
{
t = strtod( p, &p );
bytes_in += t;
t = strtod( p, &p );
pkts_in += t;
for (i = 0; i < 6; i++) strtol(p, &p, 10);
t == strtod( p, &p );
bytes_out += t;
pkts_out += strtod( p, &p );
}
p = index (p, '\n') + 1; // skips a line
}
(unsigned long) diff = pkts_out - last_pkts_out;
if ( diff )
{
t = proc_net_dev.last_read - stamp;
t = diff / t;
}
else
t = 0;
val.f = t;
last_bytes_in = bytes_in;
last_pkts_in = pkts_in;
last_pkts_out = pkts_out;
last_bytes_out = bytes_out;
stamp = proc_net_dev.last_read;
}
return val;
}
g_val_t
bytes_out_func ( void )
{
char *p;
register int i;
static g_val_t val;
int size;
static int stamp;
static double last_bytes_in,
last_bytes_out,
last_pkts_in,
last_pkts_out;
double bytes_in, bytes_out, pkts_in, pkts_out, t = 0;
unsigned long diff;
p = update_file(&proc_net_dev);
if (proc_net_dev.last_read != stamp) {
size = ( index (p, 0x00) ) - p;
/* skip past the two-line header ... */
p = index (p, '\n')+1;
p = index (p, '\n')+1;
p = index (p, '\n')+1; // and skip loopback, which is always the first one
while (*p != 0x00 )
{
p = index(p, ':')+1; /* skip past the interface tag portion of this
line */
if ( (*p-1 != 'o') && (*p-2 != 'l') )
{
t = strtod( p, &p );
bytes_in += t;
t = strtod( p, &p );
pkts_in += t;
for (i = 0; i < 6; i++) strtol(p, &p, 10);
t == strtod( p, &p );
bytes_out += t;
pkts_out += strtod( p, &p );
}
p = index (p, '\n') + 1; // skips a line
}
(unsigned long) diff = bytes_out - last_bytes_out;
if ( diff )
{
t = proc_net_dev.last_read - stamp;
t = diff / t;
}
else
t = 0;
val.f = t;
last_bytes_in = bytes_in;
last_pkts_in = pkts_in;
last_pkts_out = pkts_out;
last_bytes_out = bytes_out;
stamp = proc_net_dev.last_read;
}
debug_msg(" ********** BYTES_OUT RETURN: %f", val.f);
return val;
}
g_val_t
bytes_in_func ( void )
{
char *p;
register int i;
static g_val_t val;
int size;
static int stamp;
static double last_bytes_in,
last_bytes_out,
last_pkts_in,
last_pkts_out;
double bytes_in, bytes_out, pkts_in, pkts_out, t = 0;
unsigned long diff;
p = update_file(&proc_net_dev);
if (proc_net_dev.last_read != stamp) {
size = ( index (p, 0x00) ) - p;
/* skip past the two-line header ... */
p = index (p, '\n')+1;
p = index (p, '\n')+1;
p = index (p, '\n')+1; // and skip loopback, which is always the first one
while (*p != 0x00 )
{
p = index(p, ':')+1; /* skip past the interface tag portion of this
line */
debug_msg(" Last two chars: %c%c\n", *p-2, *p-1 );
if ( (*p-1 != 'o') && (*p-2 != 'l') )
{
debug_msg(" Last two chars: %c%c\n", *p-2, *p-1 );
t = strtod( p, &p );
bytes_in += t;
t = strtod( p, &p );
pkts_in += t;
for (i = 0; i < 6; i++) strtol(p, &p, 10);
t == strtod( p, &p );
bytes_out += t;
pkts_out += strtod( p, &p );
}
p = index (p, '\n') + 1; // skips a line
}
(unsigned long) diff = bytes_in - last_bytes_in;
if ( diff )
{
t = proc_net_dev.last_read - stamp;
t = diff / t;
}
else
t = 0;
val.f = t;
last_bytes_in = bytes_in;
last_pkts_in = pkts_in;
last_pkts_out = pkts_out;
last_bytes_out = bytes_out;
stamp = proc_net_dev.last_read;
}
return val;
}
#endif
g_val_t
cpu_num_func ( void )
{
g_val_t val;
struct pst_dynamic p;
/* Only need to do this once */
if (! cpu_num_func_cpu_num) {
if( 1 == pstat_getdynamic( &p, sizeof(struct pst_dynamic), 1, 0))
cpu_num_func_cpu_num = p.psd_max_proc_cnt;
else cpu_num_func_cpu_num = -1;
}
val.uint16 = cpu_num_func_cpu_num;
return val;
}
g_val_t
cpu_speed_func ( void )
{
static g_val_t val = {0};
val.uint32 = 0;
return val;
}
g_val_t
mem_total_func ( void )
{
g_val_t val;
val.uint32 = (staticinfo.physical_memory / 1024) * staticinfo.page_size;
return val;
}
g_val_t
swap_total_func ( void )
{
g_val_t val;
val.uint32 = 0;
return val;
}
g_val_t
boottime_func ( void )
{
g_val_t val;
val.uint32 = staticinfo.boot_time;
return val;
}
g_val_t
sys_clock_func ( void )
{
g_val_t val;
val.uint32 = time(NULL);
return val;
}
g_val_t
machine_type_func ( void )
{
g_val_t val;
#ifdef __ia64__
snprintf(val.str, MAX_G_STRING_SIZE, "ia64");
#endif
#ifdef __m68k__
snprintf(val.str, MAX_G_STRING_SIZE, "m68k");
#endif
#ifdef __hppa__
snprintf(val.str, MAX_G_STRING_SIZE, "hppa");
#endif
return val;
}
g_val_t
os_name_func ( void )
{
g_val_t val;
snprintf(val.str, MAX_G_STRING_SIZE, "HP-UX");
return val;
}
g_val_t
os_release_func ( void )
{
g_val_t val;
struct utsname uts;
if ( uname( &uts ) == -1 )
{
( void )perror ( "uname" );
strcpy( uts.release, "uname() error");
}
snprintf(val.str, MAX_G_STRING_SIZE, "%s", uts.release);
return val;
}
/* we want five states... in order... USER NICE SYS IDLE WAIT */
enum {CPU_USER, CPU_NICE, CPU_SYS, CPU_IDLE, CPU_WAIT, CPUSTATESWEWANT};
/*
* A helper function to return the total number of cpu cycles
*/
unsigned long
#if !defined(_PSTAT64)
total_cycles_func ( uint32_t totals[])
#else
total_cycles_func ( uint64_t totals[])
#endif
{
#if !defined(_PSTAT64)
uint32_t total_cycles = 0;
#else
uint64_t total_cycles = 0L;
#endif
struct pst_processor p;
int i,j;
for( i = 0; i < cpu_num_func_cpu_num; i++) {
if( -1 == pstat_getprocessor( &p, sizeof(struct pst_processor), 1, 0)){
err_msg("load_one_func() got an error from pstat_getprocessor()");
return 0;
}
for( j = 0; j < CPUSTATESWEWANT; j++) {
if( !i) totals[j] = 0;
totals[j] += p.psp_cpu_time[j];
}
}
for( j = 0; j < CPUSTATESWEWANT; j++) total_cycles += totals[j];
return total_cycles;
}
g_val_t
cpu_func (int which)
{
int j, alltime=0;
g_val_t val;
/* static int stamp; */
time_t stamp;
static time_t laststamp;
double diff;
#if !defined(_PSTAT64)
static uint32_t total_cycles, last_total_cycles,
cycles[CPUSTATESWEWANT], last_cycles[CPUSTATESWEWANT];
#else
static uint64_t total_cycles, last_total_cycles,
cycles[CPUSTATESWEWANT], last_cycles[CPUSTATESWEWANT];
#endif
if( which >= CPUSTATESWEWANT)
{
alltime = 1;
which -= CPUSTATESWEWANT; /* idle */
}
stamp = time(NULL);
/* don't call total_cycles_func() more than once per second */
if( stamp != laststamp)
{
total_cycles = total_cycles_func(cycles);
/* printf("tot:%ld - %ld %ld %ld %ld %ld\n", total_cycles,
cycles[0], cycles[1], cycles[2], cycles[3], cycles[4]); */
}
val.f = 0.0;
if( alltime) /* percentage since systems has been up */
{
if( total_cycles != 0)
val.f = (cycles[which]*100.0)/total_cycles;
}
else /* percentage in last time slice */
{
diff = total_cycles - last_total_cycles;
if( diff != 0.0)
val.f = ((cycles[which] - last_cycles[which])/diff)*100;
}
if( stamp != laststamp)
{
laststamp = stamp;
last_total_cycles = total_cycles;
for( j = 0; j < CPUSTATESWEWANT; j++)
last_cycles[j] = cycles[j];
}
return val;
}
g_val_t
cpu_user_func ( void )
{
return cpu_func(CPU_USER);
}
g_val_t
cpu_nice_func ( void )
{
return cpu_func(CPU_NICE);
}
g_val_t
cpu_system_func ( void )
{
return cpu_func(CPU_SYS);
}
g_val_t
cpu_idle_func ( void )
{
return cpu_func(CPU_IDLE);
}
g_val_t
cpu_aidle_func ( uint32_t i )
{
return cpu_func(CPU_IDLE + CPUSTATESWEWANT);
}
g_val_t
load_one_func ( void )
{
g_val_t val;
struct pst_dynamic p;
if( -1 == pstat_getdynamic( &p, sizeof(struct pst_dynamic), 1, 0)){
err_msg("load_one_func() got an error from pstat_getdynamic()");
val.f = 0;
return val;
}
val.f = p.psd_avg_1_min;
return val;
}
g_val_t
load_five_func ( void )
{
g_val_t val;
struct pst_dynamic p;
if( -1 == pstat_getdynamic( &p, sizeof(struct pst_dynamic), 1, 0)){
err_msg("load_five_func() got an error from pstat_getdynamic()");
val.f = 0;
return val;
}
val.f = p.psd_avg_5_min;
return val;
}
g_val_t
load_fifteen_func ( void )
{
g_val_t val;
struct pst_dynamic p;
if( -1 == pstat_getdynamic( &p, sizeof(struct pst_dynamic), 1, 0)){
err_msg("load_fifteen_func() got an error from pstat_getdynamic()");
val.f = 0;
return val;
}
val.f = p.psd_avg_15_min;
return val;
}
#define PROC_CHUNK 256
g_val_t
proc_func(int pstate){
g_val_t val;
unsigned int i, got, sum = 0, index = 0;
struct pst_status p[PROC_CHUNK];
do
{
got = pstat_getproc( p, sizeof(struct pst_status), PROC_CHUNK, index);
if( -1 == got) {
err_msg("proc_func() got an error from pstat_getproc()");
val.uint32 = 0;
return val;
}
index += got;
if( !pstate)
sum += got; /* total */
else
for( i = 0; i < got; i++)
if(pstate == p[i].pst_stat) /* total by state */
++sum;
}
while( got == PROC_CHUNK);
val.uint32 = sum;
return val;
}
g_val_t
proc_run_func( void )
{
return proc_func(PS_RUN);
}
g_val_t
proc_total_func ( void )
{
return proc_func(0);
}
g_val_t
mem_free_func ( void )
{
g_val_t val;
struct pst_dynamic p;
if( -1 == pstat_getdynamic( &p, sizeof(struct pst_dynamic), 1, 0)){
err_msg("mem_free_func() got an error from pstat_getdynamic()");
val.uint32 = 0;
return val;
}
val.uint32 = (p.psd_free / 1024) * staticinfo.page_size;
return val;
}
g_val_t
mem_shared_func ( void )
{
char *p;
g_val_t val;
/*
p = strstr( update_file(&proc_meminfo), "MemShared:" );
p = skip_token(p);
val.uint32 = strtol( p, (char **)NULL, 10 );
*/
val.uint32 = 0;
return val;
}
g_val_t
mem_buffers_func ( void )
{
char *p;
g_val_t val;
/*
p = strstr( update_file(&proc_meminfo), "Buffers:" );
p = skip_token(p);
val.uint32 = strtol( p, (char **)NULL, 10 );
*/
val.uint32 = 0;
return val;
}
g_val_t
mem_cached_func ( void )
{
char *p;
g_val_t val;
/*
p = strstr( update_file(&proc_meminfo), "Cached:");
p = skip_token(p);
val.uint32 = strtol( p, (char **)NULL, 10 );
*/
val.uint32 = 0;
return val;
}
g_val_t
swap_free_func ( void )
{
char *p;
g_val_t val;
/*
p = strstr( update_file(&proc_meminfo), "SwapFree:" );
p = skip_token(p);
val.uint32 = strtol( p, (char **)NULL, 10 );
*/
val.uint32 = 0;
return val;
}
/* ===================================================== */
/* Using the UNIX-independant libdnet library */
#include "dnet.h"
static int
find_mtu(const struct intf_entry *entry, void *arg)
{
unsigned int mtu;
unsigned int *min = (unsigned int *) arg;
/* Only consider interfaces that are up. */
if (! entry->intf_flags & INTF_FLAG_UP)
return 0;
mtu=entry->intf_mtu;
if ( !*min || *min>mtu)
*min=mtu;
return 0;
}
/* ---------------------------------------------------------------------------
*/
g_val_t
mtu_func ( void )
{
/* We want to find the minimum MTU (Max packet size) over all UP interfaces.
*/
unsigned int min=0;
g_val_t val;
intf_t *intf;
intf = intf_open();
intf_loop(intf, find_mtu, &min);
intf_close(intf);
val.uint32 = min;
/* A val of 0 means there are no UP interfaces. Shouldn't happen. */
return val;
}
/* ===================================================== */
/* Disk Usage. Using fsusage.c from the GNU fileutils-4.1.5 package. */
#include <inttypes.h>
#include <ganglia/fsusage.h>
/* Linux Specific, but we are in the Linux machine file. */
#define MOUNTS "/proc/mounts"
struct nlist {
struct nlist *next;
char *name;
};
#define DFHASHSIZE 101
static struct nlist *DFhashvector[DFHASHSIZE];
/* ---------------------------------------------------------------------------
*/
unsigned int DFhash(const char *s)
{
unsigned int hashval;
for (hashval=0; *s != '\0'; s++)
hashval = *s + 31 * hashval;
return hashval % DFHASHSIZE;
}
/* ---------------------------------------------------------------------------
*/
/* From K&R C book, pp. 144-145 */
struct nlist * seen_before(const char *name)
{
struct nlist *found=0, *np;
unsigned int hashval;
/* lookup */
hashval=DFhash(name);
for (np=DFhashvector[hashval]; np; np=np->next) {
if (!strcmp(name,np->name)) {
found=np;
break;
}
}
if (!found) { /* not found */
np = (struct nlist *) malloc(sizeof(*np));
if (!np || !(np->name = (char *) strdup(name)))
return NULL;
np->next = DFhashvector[hashval];
DFhashvector[hashval] = np;
return NULL;
}
else /* found name */
return found;
}
/* ---------------------------------------------------------------------------
*/
void DFcleanup()
{
struct nlist *np, *next;
int i;
for (i=0; i<DFHASHSIZE; i++) {
/* Non-standard for loop. Note the last clause happens at the end of the
loop. */
for (np = DFhashvector[i]; np; np=next) {
next=np->next;
free(np->name);
free(np);
}
DFhashvector[i] = 0;
}
}
/* ---------------------------------------------------------------------------
*/
int remote_mount(const char *device, const char *type)
{
/* From ME_REMOTE macro in mountlist.h:
A file system is `remote' if its Fs_name contains a `:'
or if (it is of type smbfs and its Fs_name starts with `//'). */
return ((strchr(device,':') != 0)
|| (!strcmp(type, "smbfs") && device[0]=='/' && device[1]=='/')
|| (!strcmp(type, "autofs")));
}
#ifdef NOTYETJKP
/* ---------------------------------------------------------------------------
*/
float device_space(char *mount, char *device, double *total_size, double
*total_free)
{
struct fs_usage fsu;
uint32_t blocksize;
uint32_t free;
uint32_t size;
double reported_total, reported_free;
/* We report in GB = 1e9 bytes. */
double reported_units = 1e9;
/* The percent used: used/total * 100 */
float pct=0.0;
/* Avoid multiply-mounted disks - not done in df. */
if (seen_before(device)) return pct;
if (get_fs_usage(mount, device, &fsu)) {
/* Ignore funky devices... */
return pct;
}
free = fsu.fsu_bavail;
/* Is the space available negative? */
if (fsu.fsu_bavail_top_bit_set) free = 0;
size = fsu.fsu_blocks;
blocksize = fsu.fsu_blocksize;
/* Keep running sum of total used, free local disk space. */
*total_size += size * (double) blocksize;
*total_free += free * (double) blocksize;
/* The percentage of space used on this partition. */
pct = size ? ((size - free) / (float) size) * 100 : 0.0;
return pct;
}
/* ---------------------------------------------------------------------------
*/
float find_disk_space(double *total_size, double *total_free)
{
FILE *mounts;
char procline[256];
char mount[128], device[128], type[32];
/* We report in GB = 1e9 bytes. */
double reported_units = 1e9;
/* Track the most full disk partition, report with a percentage. */
float thispct, max=0.0;
int i, rc;
struct nlist *np, *next;
/* Read all currently mounted filesystems. */
mounts=fopen(MOUNTS,"r");
if (!mounts) {
debug_msg("Df Error: could not open mounts file %s. Are we on the right
OS?\n", MOUNTS);
return max;
}
while ( fgets(procline, sizeof(procline), mounts) ) {
rc=sscanf(procline, "%s %s %s ", device, mount, type);
if (!rc) continue;
if (remote_mount(device, type)) continue;
thispct = device_space(mount, device, total_size, total_free);
if (!max || max<thispct)
max = thispct;
}
fclose(mounts);
*total_size = *total_size / reported_units;
*total_free = *total_free / reported_units;
/* debug_msg("For all disks: %.3f GB total, %.3f GB free for users.",
*total_size, *total_free); */
DFcleanup();
return max;
}
/* ---------------------------------------------------------------------------
*/
g_val_t
disk_free_func( void )
{
double total_free=0.0;
double total_size=0.0;
g_val_t val;
find_disk_space(&total_size, &total_free);
val.d = total_free;
return val;
}
/* ---------------------------------------------------------------------------
*/
g_val_t
disk_total_func( void )
{
double total_free=0.0;
double total_size=0.0;
g_val_t val;
find_disk_space(&total_size, &total_free);
val.d = total_size;
return val;
}
/* ---------------------------------------------------------------------------
*/
g_val_t
part_max_used_func( void )
{
double total_free=0.0;
double total_size=0.0;
float most_full;
g_val_t val;
most_full = find_disk_space(&total_size, &total_free);
val.f = most_full;
return val;
}
#endif