mirror of
https://github.com/Llewellynvdm/conky.git
synced 2025-01-14 11:33:14 +00:00
${top}: big cleanup
Linux-specific code in top.cc was moved to linux.cc. Redundant code (e.g. the parts sorting by CPU usage, CPU time or memory usage) was removed. Sorting etc. happens in top.cc, whilst platform-dependent code in linux.cc, freebsd.cc or openbsd.cc just builds up the process table. In the Linux code, some functions had a return value which was never evaluated. They return void now. I tested it on FreeBSD and Linux; The OpenBSD port does not compile anyway. I changed the OpenBSD parts, too, so that it will be less effort to get conky working under OpenBSD. Signed-off-by: Alexander Graf <agraf@znc.in>
This commit is contained in:
parent
cc35a00a30
commit
0b3e3c637e
@ -57,7 +57,6 @@ char get_freq(char *, size_t, const char *, int, unsigned int);
|
||||
void print_voltage_mv(struct text_object *, char *, int);
|
||||
void print_voltage_v(struct text_object *, char *, int);
|
||||
int update_load_average(void);
|
||||
int update_top(void);
|
||||
void free_all_processes(void);
|
||||
struct process *get_first_process(void);
|
||||
void get_cpu_count(void);
|
||||
|
128
src/freebsd.cc
128
src/freebsd.cc
@ -595,12 +595,6 @@ char get_freq(char *p_client_buffer, size_t client_buffer_size, const char *p_fo
|
||||
return 1;
|
||||
}
|
||||
|
||||
int update_top(void)
|
||||
{
|
||||
proc_find_top(info.cpu, info.memu, info.time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void update_wifi_stats(void)
|
||||
{
|
||||
@ -711,127 +705,31 @@ int update_diskio(void)
|
||||
|
||||
/* While topless is obviously better, top is also not bad. */
|
||||
|
||||
int comparecpu(const void *a, const void *b)
|
||||
{
|
||||
if (((const struct process *)a)->amount > ((const struct process *)b)->amount) {
|
||||
return -1;
|
||||
} else if (((const struct process *)a)->amount < ((const struct process *)b)->amount) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int comparemem(const void *a, const void *b)
|
||||
{
|
||||
if (((const struct process *)a)->rss > ((const struct process *)b)->rss) {
|
||||
return -1;
|
||||
} else if (((const struct process *)a)->rss < ((const struct process *)b)->rss) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int comparetime(const void *va, const void *vb)
|
||||
{
|
||||
struct process *a = (struct process *)va, *b = (struct process *)vb;
|
||||
|
||||
return b->total_cpu_time - a->total_cpu_time;
|
||||
}
|
||||
|
||||
__attribute__((gnu_inline)) inline void
|
||||
proc_find_top(struct process **cpu, struct process **mem, struct process **time)
|
||||
void get_top_info(void)
|
||||
{
|
||||
struct kinfo_proc *p;
|
||||
struct process *proc;
|
||||
int n_processes;
|
||||
int i, j = 0;
|
||||
struct process *processes;
|
||||
|
||||
int total_pages;
|
||||
|
||||
/* we get total pages count again to be sure it is up to date */
|
||||
if (GETSYSCTL("vm.stats.vm.v_page_count", total_pages) != 0) {
|
||||
CRIT_ERR(NULL, NULL, "Cannot read sysctl \"vm.stats.vm.v_page_count\"");
|
||||
}
|
||||
int i;
|
||||
|
||||
p = kvm_getprocs(kd, KERN_PROC_PROC, 0, &n_processes);
|
||||
processes = (process *) malloc(n_processes * sizeof(struct process));
|
||||
|
||||
for (i = 0; i < n_processes; i++) {
|
||||
if (!((p[i].ki_flag & P_SYSTEM)) && p[i].ki_comm != NULL) {
|
||||
processes[j].pid = p[i].ki_pid;
|
||||
processes[j].name = strndup(p[i].ki_comm, text_buffer_size);
|
||||
processes[j].amount = 100.0 * p[i].ki_pctcpu / FSCALE;
|
||||
processes[j].vsize = p[i].ki_size;
|
||||
processes[j].rss = (p[i].ki_rssize * getpagesize());
|
||||
proc = find_process(p[i].ki_pid);
|
||||
if (!proc)
|
||||
proc = new_process(p[i].ki_pid);
|
||||
|
||||
proc->time_stamp = g_time;
|
||||
proc->name = strndup(p[i].ki_comm, text_buffer_size);
|
||||
proc->amount = 100.0 * p[i].ki_pctcpu / FSCALE;
|
||||
proc->vsize = p[i].ki_size;
|
||||
proc->rss = (p[i].ki_rssize * getpagesize());
|
||||
/* ki_runtime is in microseconds, total_cpu_time in centiseconds.
|
||||
* Therefore we divide by 10000. */
|
||||
processes[j].total_cpu_time = p[i].ki_runtime / 10000;
|
||||
j++;
|
||||
proc->total_cpu_time = p[i].ki_runtime / 10000;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(processes, j - 1, sizeof(struct process), comparemem);
|
||||
for (i = 0; i < 10 && i < n_processes; i++) {
|
||||
struct process *tmp, *ttmp;
|
||||
|
||||
tmp = (process *) malloc(sizeof(struct process));
|
||||
memcpy(tmp, &processes[i], sizeof(struct process));
|
||||
tmp->name = strndup(processes[i].name, text_buffer_size);
|
||||
|
||||
ttmp = mem[i];
|
||||
mem[i] = tmp;
|
||||
if (ttmp != NULL) {
|
||||
free(ttmp->name);
|
||||
free(ttmp);
|
||||
}
|
||||
}
|
||||
|
||||
qsort(processes, j - 1, sizeof(struct process), comparecpu);
|
||||
for (i = 0; i < 10 && i < n_processes; i++) {
|
||||
struct process *tmp, *ttmp;
|
||||
|
||||
tmp = (process *) malloc(sizeof(struct process));
|
||||
memcpy(tmp, &processes[i], sizeof(struct process));
|
||||
tmp->name = strndup(processes[i].name, text_buffer_size);
|
||||
|
||||
ttmp = cpu[i];
|
||||
cpu[i] = tmp;
|
||||
if (ttmp != NULL) {
|
||||
free(ttmp->name);
|
||||
free(ttmp);
|
||||
}
|
||||
}
|
||||
|
||||
qsort(processes, j - 1, sizeof(struct process), comparetime);
|
||||
for (i = 0; i < 10 && i < n_processes; i++) {
|
||||
struct process *tmp, *ttmp;
|
||||
|
||||
tmp = (process *) malloc(sizeof(struct process));
|
||||
memcpy(tmp, &processes[i], sizeof(struct process));
|
||||
tmp->name = strndup(processes[i].name, text_buffer_size);
|
||||
|
||||
ttmp = time[i];
|
||||
time[i] = tmp;
|
||||
if (ttmp != NULL) {
|
||||
free(ttmp->name);
|
||||
free(ttmp);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(FREEBSD_DEBUG)
|
||||
printf("=====\nmem\n");
|
||||
for (i = 0; i < 10; i++) {
|
||||
printf("%d: %s(%d) %ld %ld\n", i, mem[i]->name,
|
||||
mem[i]->pid, mem[i]->vsize, mem[i]->rss);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < j; i++) {
|
||||
free(processes[i].name);
|
||||
}
|
||||
free(processes);
|
||||
}
|
||||
|
||||
void get_battery_short_status(char *buffer, unsigned int n, const char *bat)
|
||||
|
354
src/linux.cc
354
src/linux.cc
@ -2218,17 +2218,6 @@ void get_powerbook_batt_info(struct text_object *obj, char *buffer, int n)
|
||||
snprintf(buffer, n, "%s", pb_battery_info[obj->data.i]);
|
||||
}
|
||||
|
||||
int update_top(void)
|
||||
{
|
||||
process_find_top(info.cpu, info.memu, info.time
|
||||
#ifdef BUILD_IOSTATS
|
||||
, info.io
|
||||
#endif
|
||||
);
|
||||
info.first_process = get_first_process();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ENTROPY_AVAIL_PATH "/proc/sys/kernel/random/entropy_avail"
|
||||
|
||||
int get_entropy_avail(unsigned int *val)
|
||||
@ -2418,3 +2407,346 @@ void print_distribution(struct text_object *obj, char *p, int p_max_size)
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* 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 long calc_cpu_total(void)
|
||||
{
|
||||
static unsigned long long previous_total = 0;
|
||||
unsigned long long total = 0;
|
||||
unsigned long long t = 0;
|
||||
int rc;
|
||||
int ps;
|
||||
char line[BUFFER_LEN] = { 0 };
|
||||
unsigned long long cpu = 0;
|
||||
unsigned long long niceval = 0;
|
||||
unsigned long long systemval = 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;
|
||||
const 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, template_, &cpu, &niceval, &systemval, &idle, &iowait, &irq,
|
||||
&softirq, &steal);
|
||||
total = cpu + niceval + systemval + idle + iowait + irq + softirq + steal;
|
||||
|
||||
t = total - previous_total;
|
||||
previous_total = total;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Calculate each processes cpu *
|
||||
******************************************/
|
||||
|
||||
inline static void calc_cpu_each(unsigned long long total)
|
||||
{
|
||||
struct process *p = first_process;
|
||||
|
||||
while (p) {
|
||||
p->amount = 100.0 * (cpu_separate ? info.cpu_count : 1) *
|
||||
(p->user_time + p->kernel_time) / (float) total;
|
||||
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BUILD_IOSTATS
|
||||
static void calc_io_each(void)
|
||||
{
|
||||
struct process *p;
|
||||
unsigned long long sum = 0;
|
||||
|
||||
for (p = first_process; p; p = p->next)
|
||||
sum += p->read_bytes + p->write_bytes;
|
||||
|
||||
if(sum == 0)
|
||||
sum = 1; /* to avoid having NANs if no I/O occured */
|
||||
for (p = first_process; p; p = p->next)
|
||||
p->io_perc = 100.0 * (p->read_bytes + p->write_bytes) / (float) sum;
|
||||
}
|
||||
#endif /* BUILD_IOSTATS */
|
||||
|
||||
/******************************************
|
||||
* Extract information from /proc *
|
||||
******************************************/
|
||||
|
||||
#define PROCFS_TEMPLATE "/proc/%d/stat"
|
||||
#define PROCFS_CMDLINE_TEMPLATE "/proc/%d/cmdline"
|
||||
|
||||
/* These are the guts that extract information out of /proc.
|
||||
* Anyone hoping to port wmtop should look here first. */
|
||||
static void process_parse_stat(struct process *process)
|
||||
{
|
||||
char line[BUFFER_LEN] = { 0 }, filename[BUFFER_LEN], procname[BUFFER_LEN];
|
||||
char state[4];
|
||||
int ps;
|
||||
unsigned long user_time = 0;
|
||||
unsigned long kernel_time = 0;
|
||||
int rc;
|
||||
char *r, *q;
|
||||
int endl;
|
||||
int nice_val;
|
||||
char *lparen, *rparen;
|
||||
|
||||
snprintf(filename, sizeof(filename), PROCFS_TEMPLATE, process->pid);
|
||||
|
||||
ps = open(filename, O_RDONLY);
|
||||
if (ps < 0) {
|
||||
/* The process must have finished in the last few jiffies! */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Mark process as up-to-date. */
|
||||
process->time_stamp = g_time;
|
||||
|
||||
rc = read(ps, line, sizeof(line));
|
||||
close(ps);
|
||||
if (rc < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Extract cpu times from data in /proc filesystem */
|
||||
lparen = strchr(line, '(');
|
||||
rparen = strrchr(line, ')');
|
||||
if(!lparen || !rparen || rparen < lparen)
|
||||
return; // this should not happen
|
||||
|
||||
rc = MIN((unsigned)(rparen - lparen - 1), sizeof(procname) - 1);
|
||||
strncpy(procname, lparen + 1, rc);
|
||||
procname[rc] = '\0';
|
||||
rc = sscanf(rparen + 1, "%3s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lu "
|
||||
"%lu %*s %*s %*s %d %*s %*s %*s %u %u", state, &process->user_time,
|
||||
&process->kernel_time, &nice_val, &process->vsize, &process->rss);
|
||||
if (rc < 6) {
|
||||
NORM_ERR("scaning data for %s failed, got only %d fields", procname, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
if(state[0]=='R')
|
||||
++ info.run_procs;
|
||||
|
||||
/* remove any "kdeinit: " */
|
||||
if (procname == strstr(procname, "kdeinit")) {
|
||||
snprintf(filename, sizeof(filename), PROCFS_CMDLINE_TEMPLATE,
|
||||
process->pid);
|
||||
|
||||
ps = open(filename, O_RDONLY);
|
||||
if (ps < 0) {
|
||||
/* The process must have finished in the last few jiffies! */
|
||||
return;
|
||||
}
|
||||
|
||||
endl = read(ps, line, sizeof(line));
|
||||
close(ps);
|
||||
|
||||
/* null terminate the input */
|
||||
line[endl] = 0;
|
||||
/* account for "kdeinit: " */
|
||||
if ((char *) line == strstr(line, "kdeinit: ")) {
|
||||
r = ((char *) line) + 9;
|
||||
} else {
|
||||
r = (char *) line;
|
||||
}
|
||||
|
||||
q = procname;
|
||||
/* stop at space */
|
||||
while (*r && *r != ' ') {
|
||||
*q++ = *r++;
|
||||
}
|
||||
*q = 0;
|
||||
}
|
||||
|
||||
free_and_zero(process->name);
|
||||
process->name = strndup(procname, text_buffer_size);
|
||||
process->rss *= getpagesize();
|
||||
|
||||
process->total_cpu_time = process->user_time + process->kernel_time;
|
||||
if (process->previous_user_time == ULONG_MAX) {
|
||||
process->previous_user_time = process->user_time;
|
||||
}
|
||||
if (process->previous_kernel_time == ULONG_MAX) {
|
||||
process->previous_kernel_time = process->kernel_time;
|
||||
}
|
||||
|
||||
/* strangely, the values aren't monotonous */
|
||||
if (process->previous_user_time > process->user_time)
|
||||
process->previous_user_time = process->user_time;
|
||||
|
||||
if (process->previous_kernel_time > process->kernel_time)
|
||||
process->previous_kernel_time = process->kernel_time;
|
||||
|
||||
/* store the difference of the user_time */
|
||||
user_time = process->user_time - process->previous_user_time;
|
||||
kernel_time = process->kernel_time - process->previous_kernel_time;
|
||||
|
||||
/* backup the process->user_time for next time around */
|
||||
process->previous_user_time = process->user_time;
|
||||
process->previous_kernel_time = process->kernel_time;
|
||||
|
||||
/* store only the difference of the user_time here... */
|
||||
process->user_time = user_time;
|
||||
process->kernel_time = kernel_time;
|
||||
}
|
||||
|
||||
#ifdef BUILD_IOSTATS
|
||||
#define PROCFS_TEMPLATE_IO "/proc/%d/io"
|
||||
static void process_parse_io(struct process *process)
|
||||
{
|
||||
static const char *read_bytes_str="read_bytes:";
|
||||
static const char *write_bytes_str="write_bytes:";
|
||||
|
||||
char line[BUFFER_LEN] = { 0 }, filename[BUFFER_LEN];
|
||||
int ps;
|
||||
int rc;
|
||||
char *pos, *endpos;
|
||||
unsigned long long read_bytes, write_bytes;
|
||||
|
||||
snprintf(filename, sizeof(filename), PROCFS_TEMPLATE_IO, process->pid);
|
||||
|
||||
ps = open(filename, O_RDONLY);
|
||||
if (ps < 0) {
|
||||
/* The process must have finished in the last few jiffies!
|
||||
* Or, the kernel doesn't support I/O accounting.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
rc = read(ps, line, sizeof(line));
|
||||
close(ps);
|
||||
if (rc < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
pos = strstr(line, read_bytes_str);
|
||||
if (pos == NULL) {
|
||||
/* these should not happen (unless the format of the file changes) */
|
||||
return;
|
||||
}
|
||||
pos += strlen(read_bytes_str);
|
||||
process->read_bytes = strtoull(pos, &endpos, 10);
|
||||
if (endpos == pos) {
|
||||
return;
|
||||
}
|
||||
|
||||
pos = strstr(line, write_bytes_str);
|
||||
if (pos == NULL) {
|
||||
return;
|
||||
}
|
||||
pos += strlen(write_bytes_str);
|
||||
process->write_bytes = strtoull(pos, &endpos, 10);
|
||||
if (endpos == pos) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (process->previous_read_bytes == ULLONG_MAX) {
|
||||
process->previous_read_bytes = process->read_bytes;
|
||||
}
|
||||
if (process->previous_write_bytes == ULLONG_MAX) {
|
||||
process->previous_write_bytes = process->write_bytes;
|
||||
}
|
||||
|
||||
/* store the difference of the byte counts */
|
||||
read_bytes = process->read_bytes - process->previous_read_bytes;
|
||||
write_bytes = process->write_bytes - process->previous_write_bytes;
|
||||
|
||||
/* backup the counts for next time around */
|
||||
process->previous_read_bytes = process->read_bytes;
|
||||
process->previous_write_bytes = process->write_bytes;
|
||||
|
||||
/* store only the difference here... */
|
||||
process->read_bytes = read_bytes;
|
||||
process->write_bytes = write_bytes;
|
||||
}
|
||||
#endif /* BUILD_IOSTATS */
|
||||
|
||||
/******************************************
|
||||
* Get process structure for process pid *
|
||||
******************************************/
|
||||
|
||||
/* This function seems to hog all of the CPU time.
|
||||
* I can't figure out why - it doesn't do much. */
|
||||
static void calculate_stats(struct process *process)
|
||||
{
|
||||
/* compute each process cpu usage by reading /proc/<proc#>/stat */
|
||||
process_parse_stat(process);
|
||||
|
||||
#ifdef BUILD_IOSTATS
|
||||
process_parse_io(process);
|
||||
#endif /* BUILD_IOSTATS */
|
||||
|
||||
/*
|
||||
* Check name against the exclusion list
|
||||
*/
|
||||
/* if (process->counted && exclusion_expression &&
|
||||
* !regexec(exclusion_expression, process->name, 0, 0, 0))
|
||||
* process->counted = 0; */
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Update process table *
|
||||
******************************************/
|
||||
|
||||
static void update_process_table(void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
if (!(dir = opendir("/proc"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
info.run_procs = 0;
|
||||
++g_time;
|
||||
|
||||
/* Get list of processes from /proc directory */
|
||||
while ((entry = readdir(dir))) {
|
||||
pid_t pid;
|
||||
|
||||
if (!entry) {
|
||||
/* Problem reading list of processes */
|
||||
closedir(dir);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sscanf(entry->d_name, "%d", &pid) > 0) {
|
||||
struct process *p;
|
||||
|
||||
p = find_process(pid);
|
||||
if (!p) {
|
||||
p = new_process(pid);
|
||||
}
|
||||
|
||||
/* compute each process cpu usage */
|
||||
calculate_stats(p);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
void get_top_info(void)
|
||||
{
|
||||
unsigned long long total = 0;
|
||||
|
||||
total = calc_cpu_total(); /* calculate the total of the processor */
|
||||
update_process_table(); /* update the table with process list */
|
||||
calc_cpu_each(total); /* and then the percentage for each task */
|
||||
#ifdef BUILD_IOSTATS
|
||||
calc_io_each(); /* percentage of I/O for each task */
|
||||
#endif /* BUILD_IOSTATS */
|
||||
}
|
||||
|
112
src/openbsd.cc
112
src/openbsd.cc
@ -611,12 +611,6 @@ char get_freq(char *p_client_buffer, size_t client_buffer_size,
|
||||
return 1;
|
||||
}
|
||||
|
||||
void update_top()
|
||||
{
|
||||
kvm_init();
|
||||
proc_find_top(info.cpu, info.memu);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* deprecated, will rewrite this soon in update_net_stats() -hifi */
|
||||
void update_wifi_stats()
|
||||
@ -685,108 +679,30 @@ void update_diskio()
|
||||
|
||||
/* While topless is obviously better, top is also not bad. */
|
||||
|
||||
int comparecpu(const void *a, const void *b)
|
||||
{
|
||||
if (((struct process *) a)->amount > ((struct process *) b)->amount) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (((struct process *) a)->amount < ((struct process *) b)->amount) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int comparemem(const void *a, const void *b)
|
||||
{
|
||||
if (((struct process *) a)->rss > ((struct process *) b)->rss) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (((struct process *) a)->rss < ((struct process *) b)->rss) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void proc_find_top(struct process **cpu, struct process **mem)
|
||||
void get_top_info(void)
|
||||
{
|
||||
struct kinfo_proc2 *p;
|
||||
struct process *proc;
|
||||
int n_processes;
|
||||
int i, j = 0;
|
||||
struct process *processes;
|
||||
int mib[2];
|
||||
int i;
|
||||
|
||||
u_int total_pages;
|
||||
int64_t usermem;
|
||||
int pagesize = getpagesize();
|
||||
kvm_init();
|
||||
|
||||
/* we get total pages count again to be sure it is up to date */
|
||||
mib[0] = CTL_HW;
|
||||
mib[1] = HW_USERMEM64;
|
||||
size_t size = sizeof(usermem);
|
||||
|
||||
if (sysctl(mib, 2, &usermem, &size, NULL, 0) == -1) {
|
||||
NORM_ERR("error reading usermem");
|
||||
}
|
||||
|
||||
/* translate bytes into page count */
|
||||
total_pages = usermem / pagesize;
|
||||
|
||||
int max_size = sizeof(struct kinfo_proc2);
|
||||
|
||||
p = kvm_getproc2(kd, KERN_PROC_ALL, 0, max_size, &n_processes);
|
||||
processes = malloc(n_processes * sizeof(struct process));
|
||||
p = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
|
||||
&n_processes);
|
||||
|
||||
for (i = 0; i < n_processes; i++) {
|
||||
if (!((p[i].p_flag & P_SYSTEM)) && p[i].p_comm != NULL) {
|
||||
processes[j].pid = p[i].p_pid;
|
||||
processes[j].name = strndup(p[i].p_comm, text_buffer_size);
|
||||
processes[j].amount = 100.0 * p[i].p_pctcpu / FSCALE;
|
||||
j++;
|
||||
proc = find_process(p[i].p_pid);
|
||||
if (!proc)
|
||||
proc = new_process(p[i].p_pid);
|
||||
|
||||
proc->time_stamp = g_time;
|
||||
proc->name = strndup(p[i].p_comm, text_buffer_size);
|
||||
proc->amount = 100.0 * p[i].p_pctcpu / FSCALE;
|
||||
/* TODO: vsize, rss, total_cpu_time */
|
||||
}
|
||||
}
|
||||
|
||||
qsort(processes, j - 1, sizeof(struct process), comparemem);
|
||||
for (i = 0; i < 10; i++) {
|
||||
struct process *tmp, *ttmp;
|
||||
|
||||
tmp = malloc(sizeof(struct process));
|
||||
tmp->pid = processes[i].pid;
|
||||
tmp->amount = processes[i].amount;
|
||||
tmp->name = strndup(processes[i].name, text_buffer_size);
|
||||
|
||||
ttmp = mem[i];
|
||||
mem[i] = tmp;
|
||||
if (ttmp != NULL) {
|
||||
free(ttmp->name);
|
||||
free(ttmp);
|
||||
}
|
||||
}
|
||||
|
||||
qsort(processes, j - 1, sizeof(struct process), comparecpu);
|
||||
for (i = 0; i < 10; i++) {
|
||||
struct process *tmp, *ttmp;
|
||||
|
||||
tmp = malloc(sizeof(struct process));
|
||||
tmp->pid = processes[i].pid;
|
||||
tmp->amount = processes[i].amount;
|
||||
tmp->name = strndup(processes[i].name, text_buffer_size);
|
||||
|
||||
ttmp = cpu[i];
|
||||
cpu[i] = tmp;
|
||||
if (ttmp != NULL) {
|
||||
free(ttmp->name);
|
||||
free(ttmp);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < j; i++) {
|
||||
free(processes[i].name);
|
||||
}
|
||||
free(processes);
|
||||
}
|
||||
|
||||
/* empty stubs so conky links */
|
||||
|
378
src/top.cc
378
src/top.cc
@ -36,9 +36,9 @@
|
||||
/* hash table size - always a power of 2 */
|
||||
#define HTABSIZE 256
|
||||
|
||||
static unsigned long g_time = 0;
|
||||
static unsigned long long previous_total = 0;
|
||||
static struct process *first_process = 0;
|
||||
struct process *first_process = 0;
|
||||
|
||||
unsigned long g_time = 0;
|
||||
|
||||
/* a simple hash table to speed up find_process() */
|
||||
struct proc_hash_entry {
|
||||
@ -138,7 +138,7 @@ struct process *get_process_by_name(const char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct process *find_process(pid_t pid)
|
||||
struct process *find_process(pid_t pid)
|
||||
{
|
||||
struct proc_hash_entry *phe;
|
||||
|
||||
@ -152,7 +152,7 @@ static struct process *find_process(pid_t pid)
|
||||
}
|
||||
|
||||
/* Create a new process object and insert it into the process list */
|
||||
static struct process *new_process(int p)
|
||||
struct process *new_process(int p)
|
||||
{
|
||||
struct process *process;
|
||||
process = (struct process *) malloc(sizeof(struct process));
|
||||
@ -191,273 +191,6 @@ static struct process *new_process(int p)
|
||||
* Functions *
|
||||
******************************************/
|
||||
|
||||
/******************************************
|
||||
* Extract information from /proc *
|
||||
******************************************/
|
||||
|
||||
/* These are the guts that extract information out of /proc.
|
||||
* Anyone hoping to port wmtop should look here first. */
|
||||
static int process_parse_stat(struct process *process)
|
||||
{
|
||||
char line[BUFFER_LEN] = { 0 }, filename[BUFFER_LEN], procname[BUFFER_LEN];
|
||||
char state[4];
|
||||
int ps;
|
||||
unsigned long user_time = 0;
|
||||
unsigned long kernel_time = 0;
|
||||
int rc;
|
||||
char *r, *q;
|
||||
int endl;
|
||||
int nice_val;
|
||||
char *lparen, *rparen;
|
||||
|
||||
snprintf(filename, sizeof(filename), PROCFS_TEMPLATE, process->pid);
|
||||
|
||||
ps = open(filename, O_RDONLY);
|
||||
if (ps < 0) {
|
||||
/* The process must have finished in the last few jiffies! */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Mark process as up-to-date. */
|
||||
process->time_stamp = g_time;
|
||||
|
||||
rc = read(ps, line, sizeof(line));
|
||||
close(ps);
|
||||
if (rc < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Extract cpu times from data in /proc filesystem */
|
||||
lparen = strchr(line, '(');
|
||||
rparen = strrchr(line, ')');
|
||||
if(!lparen || !rparen || rparen < lparen)
|
||||
return 1; // this should not happen
|
||||
|
||||
rc = MIN((unsigned)(rparen - lparen - 1), sizeof(procname) - 1);
|
||||
strncpy(procname, lparen + 1, rc);
|
||||
procname[rc] = '\0';
|
||||
rc = sscanf(rparen + 1, "%3s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lu "
|
||||
"%lu %*s %*s %*s %d %*s %*s %*s %u %u", state, &process->user_time,
|
||||
&process->kernel_time, &nice_val, &process->vsize, &process->rss);
|
||||
if (rc < 6) {
|
||||
NORM_ERR("scaning data for %s failed, got only %d fields", procname, rc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(state[0]=='R')
|
||||
++ info.run_procs;
|
||||
|
||||
/* remove any "kdeinit: " */
|
||||
if (procname == strstr(procname, "kdeinit")) {
|
||||
snprintf(filename, sizeof(filename), PROCFS_CMDLINE_TEMPLATE,
|
||||
process->pid);
|
||||
|
||||
ps = open(filename, O_RDONLY);
|
||||
if (ps < 0) {
|
||||
/* The process must have finished in the last few jiffies! */
|
||||
return 1;
|
||||
}
|
||||
|
||||
endl = read(ps, line, sizeof(line));
|
||||
close(ps);
|
||||
|
||||
/* null terminate the input */
|
||||
line[endl] = 0;
|
||||
/* account for "kdeinit: " */
|
||||
if ((char *) line == strstr(line, "kdeinit: ")) {
|
||||
r = ((char *) line) + 9;
|
||||
} else {
|
||||
r = (char *) line;
|
||||
}
|
||||
|
||||
q = procname;
|
||||
/* stop at space */
|
||||
while (*r && *r != ' ') {
|
||||
*q++ = *r++;
|
||||
}
|
||||
*q = 0;
|
||||
}
|
||||
|
||||
free_and_zero(process->name);
|
||||
process->name = strndup(procname, text_buffer_size);
|
||||
process->rss *= getpagesize();
|
||||
|
||||
process->total_cpu_time = process->user_time + process->kernel_time;
|
||||
if (process->previous_user_time == ULONG_MAX) {
|
||||
process->previous_user_time = process->user_time;
|
||||
}
|
||||
if (process->previous_kernel_time == ULONG_MAX) {
|
||||
process->previous_kernel_time = process->kernel_time;
|
||||
}
|
||||
|
||||
/* strangely, the values aren't monotonous */
|
||||
if (process->previous_user_time > process->user_time)
|
||||
process->previous_user_time = process->user_time;
|
||||
|
||||
if (process->previous_kernel_time > process->kernel_time)
|
||||
process->previous_kernel_time = process->kernel_time;
|
||||
|
||||
/* store the difference of the user_time */
|
||||
user_time = process->user_time - process->previous_user_time;
|
||||
kernel_time = process->kernel_time - process->previous_kernel_time;
|
||||
|
||||
/* backup the process->user_time for next time around */
|
||||
process->previous_user_time = process->user_time;
|
||||
process->previous_kernel_time = process->kernel_time;
|
||||
|
||||
/* store only the difference of the user_time here... */
|
||||
process->user_time = user_time;
|
||||
process->kernel_time = kernel_time;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef BUILD_IOSTATS
|
||||
static int process_parse_io(struct process *process)
|
||||
{
|
||||
static const char *read_bytes_str="read_bytes:";
|
||||
static const char *write_bytes_str="write_bytes:";
|
||||
|
||||
char line[BUFFER_LEN] = { 0 }, filename[BUFFER_LEN];
|
||||
int ps;
|
||||
int rc;
|
||||
char *pos, *endpos;
|
||||
unsigned long long read_bytes, write_bytes;
|
||||
|
||||
snprintf(filename, sizeof(filename), PROCFS_TEMPLATE_IO, process->pid);
|
||||
|
||||
ps = open(filename, O_RDONLY);
|
||||
if (ps < 0) {
|
||||
/* The process must have finished in the last few jiffies!
|
||||
* Or, the kernel doesn't support I/O accounting.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
rc = read(ps, line, sizeof(line));
|
||||
close(ps);
|
||||
if (rc < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
pos = strstr(line, read_bytes_str);
|
||||
if (pos == NULL) {
|
||||
/* these should not happen (unless the format of the file changes) */
|
||||
return 1;
|
||||
}
|
||||
pos += strlen(read_bytes_str);
|
||||
process->read_bytes = strtoull(pos, &endpos, 10);
|
||||
if (endpos == pos) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
pos = strstr(line, write_bytes_str);
|
||||
if (pos == NULL) {
|
||||
return 1;
|
||||
}
|
||||
pos += strlen(write_bytes_str);
|
||||
process->write_bytes = strtoull(pos, &endpos, 10);
|
||||
if (endpos == pos) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (process->previous_read_bytes == ULLONG_MAX) {
|
||||
process->previous_read_bytes = process->read_bytes;
|
||||
}
|
||||
if (process->previous_write_bytes == ULLONG_MAX) {
|
||||
process->previous_write_bytes = process->write_bytes;
|
||||
}
|
||||
|
||||
/* store the difference of the byte counts */
|
||||
read_bytes = process->read_bytes - process->previous_read_bytes;
|
||||
write_bytes = process->write_bytes - process->previous_write_bytes;
|
||||
|
||||
/* backup the counts for next time around */
|
||||
process->previous_read_bytes = process->read_bytes;
|
||||
process->previous_write_bytes = process->write_bytes;
|
||||
|
||||
/* store only the difference here... */
|
||||
process->read_bytes = read_bytes;
|
||||
process->write_bytes = write_bytes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* BUILD_IOSTATS */
|
||||
|
||||
/******************************************
|
||||
* Get process structure for process pid *
|
||||
******************************************/
|
||||
|
||||
/* This function seems to hog all of the CPU time.
|
||||
* I can't figure out why - it doesn't do much. */
|
||||
static int calculate_stats(struct process *process)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* compute each process cpu usage by reading /proc/<proc#>/stat */
|
||||
rc = process_parse_stat(process);
|
||||
if (rc) return 1;
|
||||
/* rc = process_parse_statm(process); if (rc) return 1; */
|
||||
|
||||
#ifdef BUILD_IOSTATS
|
||||
rc = process_parse_io(process);
|
||||
if (rc) return 1;
|
||||
#endif /* BUILD_IOSTATS */
|
||||
|
||||
/*
|
||||
* Check name against the exclusion list
|
||||
*/
|
||||
/* if (process->counted && exclusion_expression &&
|
||||
* !regexec(exclusion_expression, process->name, 0, 0, 0))
|
||||
* process->counted = 0; */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Update process table *
|
||||
******************************************/
|
||||
|
||||
static int update_process_table(void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
if (!(dir = opendir("/proc"))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
info.run_procs = 0;
|
||||
++g_time;
|
||||
|
||||
/* Get list of processes from /proc directory */
|
||||
while ((entry = readdir(dir))) {
|
||||
pid_t pid;
|
||||
|
||||
if (!entry) {
|
||||
/* Problem reading list of processes */
|
||||
closedir(dir);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sscanf(entry->d_name, "%d", &pid) > 0) {
|
||||
struct process *p;
|
||||
|
||||
p = find_process(pid);
|
||||
if (!p) {
|
||||
p = new_process(pid);
|
||||
}
|
||||
|
||||
/* compute each process cpu usage */
|
||||
calculate_stats(p);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Destroy and remove a process *
|
||||
******************************************/
|
||||
@ -513,79 +246,6 @@ static void process_cleanup(void)
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* 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 long calc_cpu_total(void)
|
||||
{
|
||||
unsigned long long total = 0;
|
||||
unsigned long long t = 0;
|
||||
int rc;
|
||||
int ps;
|
||||
char line[BUFFER_LEN] = { 0 };
|
||||
unsigned long long cpu = 0;
|
||||
unsigned long long niceval = 0;
|
||||
unsigned long long systemval = 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;
|
||||
const 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, template_, &cpu, &niceval, &systemval, &idle, &iowait, &irq,
|
||||
&softirq, &steal);
|
||||
total = cpu + niceval + systemval + idle + iowait + irq + softirq + steal;
|
||||
|
||||
t = total - previous_total;
|
||||
previous_total = total;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Calculate each processes cpu *
|
||||
******************************************/
|
||||
|
||||
inline static void calc_cpu_each(unsigned long long total)
|
||||
{
|
||||
struct process *p = first_process;
|
||||
|
||||
while (p) {
|
||||
p->amount = 100.0 * (cpu_separate ? info.cpu_count : 1) *
|
||||
(p->user_time + p->kernel_time) / (float) total;
|
||||
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BUILD_IOSTATS
|
||||
static void calc_io_each(void)
|
||||
{
|
||||
struct process *p;
|
||||
unsigned long long sum = 0;
|
||||
|
||||
for (p = first_process; p; p = p->next)
|
||||
sum += p->read_bytes + p->write_bytes;
|
||||
|
||||
if(sum == 0)
|
||||
sum = 1; /* to avoid having NANs if no I/O occured */
|
||||
for (p = first_process; p; p = p->next)
|
||||
p->io_perc = 100.0 * (p->read_bytes + p->write_bytes) / (float) sum;
|
||||
}
|
||||
#endif /* BUILD_IOSTATS */
|
||||
|
||||
/******************************************
|
||||
* Find the top processes *
|
||||
******************************************/
|
||||
@ -647,20 +307,18 @@ static int compare_io(void *va, void *vb)
|
||||
* Results are stored in the cpu,mem arrays in decreasing order[0-9]. *
|
||||
* ****************************************************************** */
|
||||
|
||||
void process_find_top(struct process **cpu, struct process **mem,
|
||||
static void process_find_top(struct process **cpu, struct process **mem,
|
||||
struct process **ptime
|
||||
#ifdef BUILD_IOSTATS
|
||||
, struct process **io
|
||||
#endif /* BUILD_IOSTATS */
|
||||
)
|
||||
{
|
||||
prio_queue_t cpu_queue, mem_queue, time_queue
|
||||
prio_queue_t cpu_queue, mem_queue, time_queue;
|
||||
#ifdef BUILD_IOSTATS
|
||||
, io_queue
|
||||
prio_queue_t io_queue;
|
||||
#endif
|
||||
;
|
||||
struct process *cur_proc = NULL;
|
||||
unsigned long long total = 0;
|
||||
int i;
|
||||
|
||||
if (!top_cpu && !top_mem && !top_time
|
||||
@ -690,13 +348,10 @@ void process_find_top(struct process **cpu, struct process **mem,
|
||||
pq_set_max_size(io_queue, MAX_SP);
|
||||
#endif
|
||||
|
||||
total = calc_cpu_total(); /* calculate the total of the processor */
|
||||
update_process_table(); /* update the table with process list */
|
||||
calc_cpu_each(total); /* and then the percentage for each task */
|
||||
/* OS-specific function updating process list */
|
||||
get_top_info();
|
||||
|
||||
process_cleanup(); /* cleanup list from exited processes */
|
||||
#ifdef BUILD_IOSTATS
|
||||
calc_io_each(); /* percentage of I/O for each task */
|
||||
#endif /* BUILD_IOSTATS */
|
||||
|
||||
cur_proc = first_process;
|
||||
|
||||
@ -738,6 +393,17 @@ void process_find_top(struct process **cpu, struct process **mem,
|
||||
#endif /* BUILD_IOSTATS */
|
||||
}
|
||||
|
||||
int update_top(void)
|
||||
{
|
||||
process_find_top(info.cpu, info.memu, info.time
|
||||
#ifdef BUILD_IOSTATS
|
||||
, info.io
|
||||
#endif
|
||||
);
|
||||
info.first_process = get_first_process();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *format_time(unsigned long timeval, const int width)
|
||||
{
|
||||
char buf[10];
|
||||
|
21
src/top.h
21
src/top.h
@ -74,10 +74,6 @@
|
||||
* and it'll take me a while to write a replacement. */
|
||||
#define BUFFER_LEN 1024
|
||||
|
||||
#define PROCFS_TEMPLATE "/proc/%d/stat"
|
||||
#define PROCFS_TEMPLATE_MEM "/proc/%d/statm"
|
||||
#define PROCFS_TEMPLATE_IO "/proc/%d/io"
|
||||
#define PROCFS_CMDLINE_TEMPLATE "/proc/%d/cmdline"
|
||||
#define MAX_SP 10 // number of elements to sort
|
||||
|
||||
enum top_field {
|
||||
@ -131,13 +127,6 @@ struct sorted_process {
|
||||
struct process *proc;
|
||||
};
|
||||
|
||||
/* Pointer to head of process list */
|
||||
void process_find_top(struct process **, struct process **, struct process **
|
||||
#ifdef BUILD_IOSTATS
|
||||
, struct process **
|
||||
#endif
|
||||
);
|
||||
|
||||
/* lookup a program by it's name */
|
||||
struct process *get_process_by_name(const char *);
|
||||
|
||||
@ -146,4 +135,14 @@ int parse_top_args(const char *s, const char *arg, struct text_object *obj);
|
||||
/* return zero on success, non-zero otherwise */
|
||||
int set_top_name_width(const char *);
|
||||
|
||||
int update_top(void);
|
||||
|
||||
void get_top_info(void);
|
||||
|
||||
extern struct process *first_process;
|
||||
extern unsigned long g_time;
|
||||
|
||||
struct process *find_process(pid_t pid);
|
||||
struct process *new_process(int p);
|
||||
|
||||
#endif /* _top_h_ */
|
||||
|
Loading…
Reference in New Issue
Block a user