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

Reply via email to