James C. McPherson wrote:
> Doug Scott wrote:
>> The patch in xfce-goodies has now been updated. I have been running
>> the cpugraph on my machine for a few hours now and the memory usage
>> has not changed. Also, it "should" now support changing the number of
>> CPU's in your machine. It should have segfaulted before if you added
>> more physical CPU's. Sorry I can not test that on my machine :(
>
>
> Hi Doug,
> do you mind telling us what the problem was?
My bad actually :)
Previously, every time GetCPUUsage is called a malloc of the "new"
array was never freed. It must have been late at night when I wrote the
Solaris code (and just happy it worked). Also both the old and new
arrays of cpu_time_t would never be increased or decreased with any
change in the number of cpu's from the sysconf(_SC_CPUID_MAX) call.
Therefore if you dynamically added more CPU's the code would try to
access past the end of the array. I really think this would only be a
problem with Sun Ray's connected to a domain capable server.
Since Solaris does not seem to have anywhere that you can get a single
average CPU usage across all online CPU's (linux you can just read
/proc/stat I think). The code I wrote uses values (cpu ticks) from
kstat, subtracts from the previous and computes the average within the code.
Below is a very cutdown snip of the offending code. Below that is the
current Solaris section of the os.c file.
Doug
-----------Before (cutdown)----------------------------
typedef struct cpu_time {
uint64_t stat[NUM_STATS];
} cpu_time_t;
static cpu_time_t *old=(cpu_time_t *)NULL;
long GetCPUUsage (int *oldusage, int *oldtotal){
cpu_time_t *new;
.
.
.
new=calloc(sizeof(cpu_time_t),ncpu);
// ^---- Do not Free!!
.
.
.
}
---------- After Complete Solaris code ---------------
#elif defined (sun)
/*
For Solaris we need to get the cpu stats from kstat for each CPU.
We then return the average usage of all valid CPU's
*/
#define NUM_STATS 4
/*
Probably should ignore cpu_ticks_wait on Solaris 10+ as it is always 0
*/
char *stat_id[] = {
"cpu_ticks_idle",
"cpu_ticks_kernel",
"cpu_ticks_user",
"cpu_ticks_wait"
};
typedef struct cpu_time {
uint64_t stat[NUM_STATS];
} cpu_time_t;
static cpu_time_t *old=(cpu_time_t *)NULL;
static cpu_time_t *new=(cpu_time_t *)NULL;
static kstat_ctl_t *kc=NULL;
/*
With Solaris cpu's can be enable and disabled at any time. Some systems
the CPU's are hot-plugable. Therefore every time we need to check to see
if a change has been made, and adjust the data structure accordingly.
*/
static int last_ncpu=-1;
long GetCPUUsage (int *oldusage, int *oldtotal)
{
uint64_t total;
uint64_t busy;
uint64_t ticks;
uint64_t usage;
int ncpu;
int i;
int j;
int cnt=0;
int sum=0;
ncpu = (int)sysconf(_SC_CPUID_MAX);
if (ncpu!=last_ncpu){
if (old!=(cpu_time_t *)NULL) free(old);
if (new!=(cpu_time_t *)NULL) free(new);
}
/*
Initiallize old structure if first time round, or if the
number of CPU's has changed.
*/
if (old==(cpu_time_t *)NULL){
old=calloc(sizeof(cpu_time_t),ncpu);
for (i=0;i<ncpu;i++){
for (j=0;j<NUM_STATS;j++){
old[i].stat[j]=0;
}
}
}
/*
Only allocate a new structure if this is the first time
or the number of CPU's has changed.
*/
if (new==(cpu_time_t *)NULL){
new=calloc(sizeof(cpu_time_t),ncpu);
}
if (kc==(kstat_ctl_t *)NULL){
kc = (kstat_ctl_t *)kstat_open();
}
for (i=0;i<ncpu;i++) {
kstat_t *ksp;
kstat_named_t *knp;
ksp = kstat_lookup(kc, "cpu", i, "sys");
/* No CPU in this slot, then look at the next one */
if (p_online(i, P_STATUS)==-1) continue;
kstat_read(kc, ksp, NULL);
for (j=0;j<NUM_STATS;j++){
knp = kstat_data_lookup(ksp, stat_id[j]);
ticks = (uint64_t)knp->value.ui64;
if (last_ncpu!=ncpu){
old[i].stat[j]=ticks;
new[i].stat[j]=0;
} else {
uint64_t store_ticks=ticks;
ticks=ticks - old[i].stat[j];
old[i].stat[j]=store_ticks;
new[i].stat[j]=ticks;
}
}
/* busy = kernel + user + wait */
busy = new[i].stat[1] + new[i].stat[2] + new[i].stat[3];
/* total = busy + idle */
total = new[i].stat[0] + busy;
if (total!=0){
usage = busy*100/total;
} else {
usage=0;
}
cnt++;
sum=sum+usage;
}
last_ncpu=ncpu;
if (cnt==0){
return(0);
} else {
return(sum/cnt);
}
}
#else
#error "You're OS is not supported."
#endif