From 67ab68914a654515ba232a82e7dbc39d1d0a75fc Mon Sep 17 00:00:00 2001 From: David Carter Date: Sun, 27 Nov 2005 06:56:35 +0000 Subject: [PATCH] new cpu % routines in top.c and linux.c git-svn-id: https://conky.svn.sourceforge.net/svnroot/conky/trunk/conky@431 7f574dfc-610e-0410-a909-a81674777703 --- ChangeLog | 2 + src/common.c | 2 +- src/conky.c | 8 +-- src/conky.h | 17 +++++- src/linux.c | 154 ++++++++++++++++++++++++++++++++------------------- src/top.c | 57 +++++++++---------- 6 files changed, 145 insertions(+), 95 deletions(-) diff --git a/ChangeLog b/ChangeLog index a4387bfe..c3658d0c 100644 --- 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 diff --git a/src/common.c b/src/common.c index 745ec2bc..f73348d2 100644 --- a/src/common.c +++ b/src/common.c @@ -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) diff --git a/src/conky.c b/src/conky.c index 0ec10822..ae8fc7fc 100644 --- a/src/conky.c +++ b/src/conky.c @@ -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) { diff --git a/src/conky.h b/src/conky.h index 58f4fd79..3ab87f37 100644 --- a/src/conky.h +++ b/src/conky.h @@ -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; diff --git a/src/linux.c b/src/linux.c index e0a340ae..87e17c45 100644 --- a/src/linux.c +++ b/src/linux.c @@ -29,6 +29,10 @@ #include #include +#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++; - 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; - } + } 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) + ); - 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 { + 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); + + 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() diff --git a/src/top.c b/src/top.c index e35b1ad7..9faf8261 100644 --- 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);