new cpu % routines in top.c and linux.c
authorDavid Carter <boojit@pundo.com>
Sun, 27 Nov 2005 06:56:35 +0000 (06:56 +0000)
committerDavid Carter <boojit@pundo.com>
Sun, 27 Nov 2005 06:56:35 +0000 (06:56 +0000)
git-svn-id: https://conky.svn.sourceforge.net/svnroot/conky/trunk/conky@431 7f574dfc-610e-0410-a909-a81674777703

ChangeLog
src/common.c
src/conky.c
src/conky.h
src/linux.c
src/top.c

index a4387bf..c3658d0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,6 @@
 # $Id$
+2005-11-27 
+       * new code in linux.c and top.c to calculate CPU % correctly on 2.6 kernels.
 
 2005-11-24
        * Fixed gentoo bug# 113219
index 745ec2b..f73348d 100644 (file)
@@ -27,7 +27,7 @@ double get_time()
 {
        struct timeval tv;
        gettimeofday(&tv, 0);
-       return tv.tv_sec + tv.tv_usec / 1000000.0;
+       return tv.tv_sec + (tv.tv_usec / 1000000.0);
 }
 
 FILE *open_file(const char *file, int *reported)
index 0ec1082..ae8fc7f 100644 (file)
@@ -2751,17 +2751,17 @@ static void generate_text()
                        }
                        OBJ(processes) {
                                if (!use_spacer)
-                                       snprintf(p, n, "%d", cur->procs);
+                                       snprintf(p, n, "%hu", cur->procs);
                                else
-                                       snprintf(p, 5, "%d    ",
+                                       snprintf(p, 5, "%hu    ",
                                                 cur->procs);
                        }
                        OBJ(running_processes) {
                                if (!use_spacer)
-                                       snprintf(p, n, "%d",
+                                       snprintf(p, n, "%hu",
                                                 cur->run_procs);
                                else
-                                       snprintf(p, 3, "%d     ",
+                                       snprintf(p, 3, "%hu     ",
                                                 cur->run_procs);
                        }
                        OBJ(text) {
index 58f4fd7..3ab87f3 100644 (file)
@@ -172,8 +172,8 @@ struct information {
        unsigned long mem, memmax, swap, swapmax;
        unsigned long bufmem, buffers, cached;
 
-       unsigned int procs;
-       unsigned int run_procs;
+       unsigned short procs;
+       unsigned short run_procs;
 
        float *cpu_usage;
        /*      struct cpu_stat cpu_summed; what the hell is this? */
@@ -200,8 +200,21 @@ struct information {
 #ifdef TCP_PORT_MONITOR
         tcp_port_monitor_collection_t * p_tcp_port_monitor_collection;
 #endif
+       short kflags;  /* kernel settings, see enum KFLAG */
 };
 
+enum {
+       KFLAG_IS_LONGSTAT = 0x01,         /* set to true if kernel uses "long" format for /proc/stats */
+       KFLAG_PROC_IS_THREADS=0x02       /* set to true if kernel shows # of threads for the proc value in sysinfo() call */
+/*     KFLAG_NEXT_ONE=0x04                 bits 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 available for future use */
+     };        
+
+#define KFLAG_SETON(a) info.kflags |= a 
+#define KFLAG_SETOFF(a) info.kflags &= (~a)
+#define KFLAG_FLIP(a) info.kflags ^= a
+#define KFLAG_ISSET(a) info.kflags & a
+
+
 int out_to_console;
 
 int top_cpu;
index e0a340a..87e17c4 100644 (file)
 #include <net/if.h>
 #include <math.h>
 
+#define SHORTSTAT_TEMPL "%*s %llu %llu %llu"
+#define LONGSTAT_TEMPL "%*s %llu %llu %llu "
+
+
 static struct sysinfo s_info;
 
 static int show_nice_processes;
@@ -326,11 +330,18 @@ void update_total_processes()
 
 #define CPU_SAMPLE_COUNT 15
 struct cpu_info {
-       unsigned long cpu_user;
-       unsigned long cpu_system;
-       unsigned long cpu_nice;
-       double last_cpu_sum;
-       unsigned long clock_ticks;
+       unsigned long long cpu_user;
+       unsigned long long cpu_system;
+       unsigned long long cpu_nice;
+       unsigned long long cpu_idle;
+       unsigned long long cpu_iowait;
+       unsigned long long cpu_irq;
+       unsigned long long cpu_softirq;
+       unsigned long long cpu_steal;
+       unsigned long long cpu_total;
+       unsigned long long cpu_active_total;
+       unsigned long long cpu_last_total;
+       unsigned long long cpu_last_active_total;
        double cpu_val[CPU_SAMPLE_COUNT];
 };
 static short cpu_setup = 0;
@@ -339,6 +350,18 @@ static int rep;
 
 static FILE *stat_fp;
 
+/* 
+   determine if this kernel gives us "extended" statistics information in /proc/stat. 
+   Kernels around 2.5 and earlier only reported user, system, nice and idle values in proc stat. 
+   Kernels around 2.6 and greater report these PLUS iowait, irq, softirq, and steal 
+*/
+void determine_longstat(char * buf) { 
+       unsigned long long iowait=0;
+       KFLAG_SETOFF(KFLAG_IS_LONGSTAT);        
+       /* scanf will either return -1 or 1 because there is only 1 assignment  */
+       if (sscanf(buf, "%*s %*d %*d %*d %*d %llu",&iowait)>0) KFLAG_SETON(KFLAG_IS_LONGSTAT);
+}
+
 void get_cpu_count()
 {
        char buf[256];
@@ -356,12 +379,18 @@ void get_cpu_count()
                        break;
 
                if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3])) {
+                       if (info.cpu_count == 0) {
+                               determine_longstat(buf);
+                       }
                        info.cpu_count++;
                }
        }
        info.cpu_usage = malloc((info.cpu_count + 1) * sizeof(float));
+
 }
 
+#define TMPL_LONGSTAT "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
+#define TMPL_SHORTSTAT "%*s %llu %llu %llu %llu"
 
 inline static void update_stat()
 {
@@ -370,20 +399,25 @@ inline static void update_stat()
        unsigned int i;
        unsigned int index;
        double curtmp;
+       char * stat_template=NULL; 
+       unsigned int malloc_cpu_size=0;
+       
+
        if (!cpu_setup) {
                get_cpu_count();
                cpu_setup = 1;
        }
+
+       if (stat_template == NULL) {
+               stat_template = KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGSTAT : TMPL_SHORTSTAT ;
+       }       
+
        if (cpu == NULL) {
-               cpu = malloc((info.cpu_count + 1) * sizeof(struct cpu_info));
-               for (index = 0; index < info.cpu_count + 1; ++index) {
-                       cpu[index].clock_ticks = 0;
-                       cpu[index].last_cpu_sum = 0;
-                       for (i = 0; i < CPU_SAMPLE_COUNT; ++i) {
-                               cpu[index].cpu_val[i] = 0;
-                       }
-               }
+               malloc_cpu_size = (info.cpu_count + 1) *  sizeof(struct cpu_info);
+               cpu = malloc(malloc_cpu_size);
+               memset(cpu, 0, malloc_cpu_size);
        }
+
        if (stat_fp == NULL) {
                stat_fp = open_file("/proc/stat", &rep);
        } else {
@@ -398,57 +432,61 @@ inline static void update_stat()
                        break;
 
                if (strncmp(buf, "procs_running ", 14) == 0) {
-                       sscanf(buf, "%*s %d", &info.run_procs);
+                       sscanf(buf, "%*s %hu", &info.run_procs);
                        info.mask |= (1 << INFO_RUN_PROCS);
-               } else if (strncmp(buf, "cpu ", 4) == 0) {
-                       sscanf(buf, "%*s %lu %lu %lu", &(cpu[index].cpu_user), &(cpu[index].cpu_nice), &(cpu[index].cpu_system));
-                       index++;
+               } else if (strncmp(buf, "cpu", 3) == 0) {
+                       index = isdigit(buf[3]) ? ((int)buf[3]) - 0x2F : 0;
+                       sscanf(buf, stat_template 
+                               , &(cpu[index].cpu_user)
+                               , &(cpu[index].cpu_nice)
+                               , &(cpu[index].cpu_system)
+                               , &(cpu[index].cpu_idle)
+                               , &(cpu[index].cpu_iowait)
+                               , &(cpu[index].cpu_irq)
+                               , &(cpu[index].cpu_softirq)
+                               , &(cpu[index].cpu_steal)
+                               );
+
+                       cpu[index].cpu_total = cpu[index].cpu_user 
+                                        + cpu[index].cpu_nice 
+                                        + cpu[index].cpu_system 
+                                        + cpu[index].cpu_idle 
+                                        + cpu[index].cpu_iowait 
+                                        + cpu[index].cpu_irq
+                                        + cpu[index].cpu_softirq
+                                        + cpu[index].cpu_steal 
+                                        ; 
+
+                       cpu[index].cpu_active_total = cpu[index].cpu_total - (cpu[index].cpu_idle + cpu[index].cpu_iowait);
                        info.mask |= (1 << INFO_CPU);
-               } else if (strncmp(buf, "cpu", 3) == 0 && isdigit(buf[3]) && index <= info.cpu_count) {
-                       sscanf(buf, "%*s %lu %lu %lu", &(cpu[index].cpu_user), &(cpu[index].cpu_nice), &(cpu[index].cpu_system));
-                       index++;
-                       info.mask |= (1 << INFO_CPU);
-               }
-       }
-       for (index = 0; index < info.cpu_count + 1; index++) {
-               double delta;
-               delta = current_update_time - last_update_time;
-               if (delta <= 0.001) {
-                       return;
-               }
 
-               if (cpu[index].clock_ticks == 0) {
-                       cpu[index].clock_ticks = sysconf(_SC_CLK_TCK);
-               }
-               curtmp = 0;
-               cpu[index].cpu_val[0] =
-                               (cpu[index].cpu_user + cpu[index].cpu_nice + cpu[index].cpu_system -
-                               cpu[index].last_cpu_sum) / delta / (double) cpu[index].clock_ticks;
-               for (i = 0; i < info.cpu_avg_samples; i++) {
-                       curtmp += cpu[index].cpu_val[i];
-               }
-               if (index == 0) {
-                       info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count;
-               } else {
+                       double delta = current_update_time - last_update_time;
+                       if (delta <= 0.001) return;     
+
+                       cpu[index].cpu_val[0] = (cpu[index].cpu_active_total -  cpu[index].cpu_last_active_total) / 
+                                               (float )(cpu[index].cpu_total - cpu[index].cpu_last_total); 
+                       curtmp = 0;
+                       for (i=0; i < info.cpu_avg_samples; i++ ) {
+                               curtmp += cpu[index].cpu_val[i];
+                       }
+                       /* TESTING -- I've removed this, because I don't think it is right. You shouldn't divide 
+                                     by the cpu count here ... removing for testing */
+                       if (index == 0) {
+                               info.cpu_usage[index] = curtmp / info.cpu_avg_samples / info.cpu_count; 
+                       } else {
+                               info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
+                       } 
+                       /* TESTING -- this line replaces the prev. "suspect" if/else */
                        info.cpu_usage[index] = curtmp / info.cpu_avg_samples;
+
+                       cpu[index].cpu_last_total = cpu[index].cpu_total;
+                       cpu[index].cpu_last_active_total = cpu[index].cpu_active_total;
+                       for (i = info.cpu_avg_samples - 1; i > 0; i--) {
+                               cpu[index].cpu_val[i] = cpu[index].cpu_val[i - 1];
+                       }
                }
-               cpu[index].last_cpu_sum = cpu[index].cpu_user + cpu[index].cpu_nice + cpu[index].cpu_system;
-               for (i = info.cpu_avg_samples; i > 1; i--)
-                       cpu[index].cpu_val[i - 1] = cpu[index].cpu_val[i - 2];
 
        }
-
-// test code
-// this is for getting proc shit
-// pee pee
-// poo
-       //
-
-
-
-
-
-
 }
 
 void update_running_processes()
index e35b1ad..9faf826 100644 (file)
--- a/src/top.c
+++ b/src/top.c
@@ -8,9 +8,8 @@
 
 #include "top.h"
 
-static regex_t *exclusion_expression = 0;
 static unsigned long g_time = 0;
-static unsigned long previous_total = 0;
+static unsigned long long previous_total = 0;
 static struct process *first_process = 0;
 
 struct process *get_first_process()
@@ -88,8 +87,8 @@ static int calculate_cpu(struct process *);
 static void process_cleanup(void);
 static void delete_process(struct process *);
 /*inline void draw_processes(void);*/
-static unsigned long calc_cpu_total(void);
-static void calc_cpu_each(unsigned long);
+static unsigned long long calc_cpu_total(void);
+static void calc_cpu_each(unsigned long long);
 
 
 /******************************************/
@@ -210,7 +209,7 @@ static int process_parse_stat(struct process *process)
        /* store only the difference of the user_time here... */
        process->user_time = user_time;
        process->kernel_time = kernel_time;
-
+                 
 
        return 0;
 }
@@ -282,9 +281,10 @@ static int calculate_cpu(struct process *process)
        /*
         * Check name against the exclusion list
         */
-       if (process->counted && exclusion_expression
+/*     if (process->counted && exclusion_expression
            && !regexec(exclusion_expression, process->name, 0, 0, 0))
                process->counted = 0;
+*/
 
        return 0;
 }
@@ -347,31 +347,38 @@ static void delete_process(struct process *p)
 /******************************************/
 /* Calculate cpu total                    */
 /******************************************/
+#define TMPL_SHORTPROC "%*s %llu %llu %llu %llu"
+#define TMPL_LONGPROC "%*s %llu %llu %llu %llu %llu %llu %llu %llu"
 
-static unsigned long calc_cpu_total()
+static unsigned long long calc_cpu_total()
 {
-       unsigned long total = 0;
-       unsigned long t = 0;
+       unsigned long long total = 0;
+       unsigned long long t = 0;
        int rc;
        int ps;
        char line[BUFFER_LEN];
-       unsigned long cpu = 0;
-       unsigned long nice = 0;
-       unsigned long system = 0;
-       unsigned long idle = 0;
-
+       unsigned long long cpu = 0;
+       unsigned long long nice = 0;
+       unsigned long long system = 0;
+       unsigned long long idle = 0;
+       unsigned long long iowait = 0;
+       unsigned long long irq = 0;
+       unsigned long long softirq = 0;
+       unsigned long long steal = 0;
+       char * template = KFLAG_ISSET(KFLAG_IS_LONGSTAT) ? TMPL_LONGPROC : TMPL_SHORTPROC; 
        ps = open("/proc/stat", O_RDONLY);
        rc = read(ps, line, sizeof(line));
        close(ps);
        if (rc < 0)
                return 0;
-       sscanf(line, "%*s %lu %lu %lu %lu", &cpu, &nice, &system, &idle);
-       total = cpu + nice + system + idle;
+
+       sscanf(line, template, &cpu, &nice, &system, &idle, &iowait, &irq, &softirq, &steal);
+       total = cpu + nice + system + idle + iowait + irq + softirq + steal;
 
        t = total - previous_total;
        previous_total = total;
 
-
        return t;
 }
 
@@ -379,18 +386,13 @@ static unsigned long calc_cpu_total()
 /* Calculate each processes cpu           */
 /******************************************/
 
-inline static void calc_cpu_each(unsigned long total)
+inline static void calc_cpu_each(unsigned long long total)
 {
        struct process *p = first_process;
        while (p) {
-               /*p->amount = total ?
-                  (100.0 * (float) (p->user_time + p->kernel_time) /
-                  total) : 0; */
                p->amount =
-                   100.0 * ((float)(p->user_time + p->kernel_time) / (float)total);
+                   100.0 * (p->user_time + p->kernel_time) / (float)total;
 
-/*             if (p->amount > 100)
-               p->amount = 0;*/
                p = p->next;
        }
 }
@@ -399,14 +401,11 @@ inline static void calc_cpu_each(unsigned long total)
 /* Find the top processes                 */
 /******************************************/
 
-//static int tot_struct;  //for debugging..uncomment this and the 2 printfs in the next two functs
-
 /*
  * free a  sp_process structure
 */
 void free_sp(struct sorted_process * sp) {
        free(sp);
-//     printf("free: %d structs\n",--tot_struct );
 }
 
 /*
@@ -418,7 +417,6 @@ struct sorted_process * malloc_sp(struct process * proc) {
        sp->greater = NULL;
        sp->less = NULL;
        sp->proc = proc;
-//     printf("malloc: %d structs\n", ++tot_struct);
        return(sp);
 } 
 
@@ -521,7 +519,7 @@ inline void process_find_top(struct process **cpu, struct process **mem)
        struct sorted_process *spc_head = NULL, *spc_tail = NULL, *spc_cur = NULL;
        struct sorted_process *spm_head = NULL, *spm_tail = NULL, *spm_cur = NULL;
        struct process *cur_proc = NULL;
-       unsigned long total = 0;
+       unsigned long long total = 0;
 
        if (!top_cpu && !top_mem) return;
 
@@ -533,7 +531,6 @@ inline void process_find_top(struct process **cpu, struct process **mem)
        cur_proc = first_process;
 
        while (cur_proc !=NULL) {
-               //printf("\n\n cur_proc: %s %f %f\n",cur_proc->name, cur_proc->totalmem, cur_proc->amount );
                if (top_cpu) {
                        spc_cur = malloc_sp(cur_proc);
                        insert_sp_element(spc_cur, &spc_head, &spc_tail, MAX_SP, &compare_cpu);