Index: machine.c =================================================================== --- machine.c (revision 266773) +++ machine.c (working copy) @@ -201,8 +201,13 @@ static struct kinfo_proc **pref; static struct kinfo_proc *previous_procs; static struct kinfo_proc **previous_pref; +static struct timespec proc_uptime; +static struct timeval proc_wall_time; +static struct timeval previous_wall_time; +static uint64_t previous_interval = 0; static int previous_proc_count = 0; static int previous_proc_count_max = 0; +static int previous_thread; static int arc_enabled; /* total number of io operations */ @@ -650,6 +655,51 @@ } /* + * If there was a previous update, use the delta in ki_runtime over + * the previous interval to recalculate ki_pctcpu. + */ +static void +proc_update_pctcpu(struct kinfo_proc *pp) +{ + const struct kinfo_proc *oldp; + + if (previous_interval != 0) { + oldp = get_old_proc(pp); + if (oldp != NULL) + pp->ki_pctcpu = ((pp->ki_runtime - oldp->ki_runtime) << + FSHIFT) / previous_interval; + + /* + * If this process/thread was created during the previous + * interval, charge it's total runtime to the previous + * interval. + */ + else if (pp->ki_start.tv_sec > previous_wall_time.tv_sec || + (pp->ki_start.tv_sec == previous_wall_time.tv_sec && + pp->ki_start.tv_usec >= previous_wall_time.tv_usec)) + pp->ki_pctcpu = (pp->ki_runtime << FSHIFT) / + previous_interval; + } +} + +/* + * Return true if this process has used any CPU time since the + * previous update. + */ +static int +proc_used_cpu(struct kinfo_proc *pp) +{ + const struct kinfo_proc *oldp; + + oldp = get_old_proc(pp); + if (oldp == NULL) + return (pp->ki_pctcpu != 0); + return (pp->ki_runtime != oldp->ki_runtime || + RU(pp)->ru_nvcsw != RU(oldp)->ru_nvcsw || + RU(pp)->ru_nivcsw != RU(oldp)->ru_nivcsw); +} + +/* * Return the total number of block in/out and faults by a process. */ long @@ -670,9 +720,11 @@ int total_procs; long p_io; long p_inblock, p_oublock, p_majflt, p_vcsw, p_ivcsw; + long nsec; int active_procs; struct kinfo_proc **prefp; struct kinfo_proc *pp; + struct timespec previous_proc_uptime; /* these are copied out of sel for speed */ int show_idle; @@ -684,6 +736,13 @@ int show_kidle; /* + * If thread state was toggled, don't cache the previous processes. + */ + if (previous_thread != sel->thread) + nproc = 0; + previous_thread = sel->thread; + + /* * Save the previous process info. */ if (previous_proc_count_max < nproc) { @@ -705,9 +764,26 @@ ps.thread ? compare_tid : compare_pid); } previous_proc_count = nproc; + previous_proc_uptime = proc_uptime; + previous_wall_time = proc_wall_time; + previous_interval = 0; pbase = kvm_getprocs(kd, sel->thread ? KERN_PROC_ALL : KERN_PROC_PROC, 0, &nproc); + (void)gettimeofday(&proc_wall_time, NULL); + if (clock_gettime(CLOCK_UPTIME, &proc_uptime) != 0) + memset(&proc_uptime, 0, sizeof(proc_uptime)); + else if (previous_proc_uptime.tv_sec != 0 && + previous_proc_uptime.tv_nsec != 0) { + previous_interval = (proc_uptime.tv_sec - + previous_proc_uptime.tv_sec) * 1000000; + nsec = proc_uptime.tv_nsec - previous_proc_uptime.tv_nsec; + if (nsec < 0) { + previous_interval -= 1000000; + nsec += 1000000000; + } + previous_interval += nsec / 1000; + } if (nproc > onproc) pref = realloc(pref, sizeof(*pref) * (onproc = nproc)); if (pref == NULL || pbase == NULL) { @@ -764,8 +840,9 @@ /* skip kernel idle process */ continue; + proc_update_pctcpu(pp); if (displaymode == DISP_CPU && !show_idle && - (pp->ki_pctcpu == 0 || + (!proc_used_cpu(pp) || pp->ki_stat == SSTOP || pp->ki_stat == SIDL)) /* skip idle or non-running processes */ continue;