Date: Fri, 30 May 2014 21:18:53 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r266906 - head/usr.bin/top Message-ID: <201405302118.s4ULIrAa084309@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jhb Date: Fri May 30 21:18:53 2014 New Revision: 266906 URL: http://svnweb.freebsd.org/changeset/base/266906 Log: Rework the notion of CPU used in top. In particular, for subsequent displays after a pause, use the difference in runtime divided by the length of the pause as the percentage of CPU used instead of the value calculated by the kernel. In addition, when determing if a process or thread is idle or not, treat any process or thread that has used any runtime or performed any context switches during the interval as busy. Note that the percent CPU is calculated as a double and stored in an array to avoid recalculating the value multiple times in the comparison method used to sort processes in the CPU display. Tested by: Jamie Landeg-Jones <jamie@dyslexicfish.net> Reviewed by: emaste (earlier version) MFC after: 1 week Modified: head/usr.bin/top/machine.c Modified: head/usr.bin/top/machine.c ============================================================================== --- head/usr.bin/top/machine.c Fri May 30 20:58:32 2014 (r266905) +++ head/usr.bin/top/machine.c Fri May 30 21:18:53 2014 (r266906) @@ -96,6 +96,7 @@ struct handle { #define RUTOT(pp) \ (RU(pp)->ru_inblock + RU(pp)->ru_oublock + RU(pp)->ru_majflt) +#define PCTCPU(pp) (pcpu[pp - pbase]) /* definitions for indices in the nlist array */ @@ -203,7 +204,14 @@ static struct kinfo_proc *previous_procs static struct kinfo_proc **previous_pref; static int previous_proc_count = 0; static int previous_proc_count_max = 0; -static int arc_enabled; +static int previous_thread; + +/* data used for recalculating pctcpu */ +static double *pcpu; +static struct timespec proc_uptime; +static struct timeval proc_wall_time; +static struct timeval previous_wall_time; +static uint64_t previous_interval = 0; /* total number of io operations */ static long total_inblock; @@ -212,6 +220,7 @@ static long total_majflt; /* these are for getting the memory statistics */ +static int arc_enabled; static int pageshift; /* log base 2 of the pagesize */ /* define pagetok in terms of pageshift */ @@ -329,6 +338,7 @@ machine_init(struct statics *statics, ch pbase = NULL; pref = NULL; + pcpu = NULL; nproc = 0; onproc = -1; @@ -650,6 +660,52 @@ get_io_stats(struct kinfo_proc *pp, long } /* + * If there was a previous update, use the delta in ki_runtime over + * the previous interval to calculate pctcpu. Otherwise, fall back + * to using the kernel's ki_pctcpu. + */ +static double +proc_calc_pctcpu(struct kinfo_proc *pp) +{ + const struct kinfo_proc *oldp; + + if (previous_interval != 0) { + oldp = get_old_proc(pp); + if (oldp != NULL) + return ((double)(pp->ki_runtime - oldp->ki_runtime) + / 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)) + return ((double)pp->ki_runtime / previous_interval); + } + return (pctdouble(pp->ki_pctcpu)); +} + +/* + * 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 (PCTCPU(pp) != 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 +726,11 @@ get_process_info(struct system_info *si, 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 +742,13 @@ get_process_info(struct system_info *si, 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,12 +770,32 @@ get_process_info(struct system_info *si, 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); - if (nproc > onproc) - pref = realloc(pref, sizeof(*pref) * (onproc = nproc)); - if (pref == NULL || pbase == NULL) { + (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) * nproc); + pcpu = realloc(pcpu, sizeof(*pcpu) * nproc); + onproc = nproc; + } + if (pref == NULL || pbase == NULL || pcpu == NULL) { (void) fprintf(stderr, "top: Out of memory.\n"); quit(23); } @@ -763,9 +848,10 @@ get_process_info(struct system_info *si, if (!show_kidle && pp->ki_tdflags & TDF_IDLETD) /* skip kernel idle process */ continue; - + + PCTCPU(pp) = proc_calc_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; @@ -848,7 +934,7 @@ format_next_process(caddr_t handle, char cputime = (pp->ki_runtime + 500000) / 1000000; /* calculate the base for cpu percentages */ - pct = pctdouble(pp->ki_pctcpu); + pct = PCTCPU(pp); /* generate "STATE" field */ switch (state = pp->ki_stat) { @@ -1169,14 +1255,12 @@ static int sorted_state[] = { #define ORDERKEY_PCTCPU(a, b) do { \ - long diff; \ + double diff; \ if (ps.wcpu) \ - diff = floor(1.0E6 * weighted_cpu(pctdouble((b)->ki_pctcpu), \ - (b))) - \ - floor(1.0E6 * weighted_cpu(pctdouble((a)->ki_pctcpu), \ - (a))); \ + diff = weighted_cpu(PCTCPU((b)), (b)) - \ + weighted_cpu(PCTCPU((a)), (a)); \ else \ - diff = (long)(b)->ki_pctcpu - (long)(a)->ki_pctcpu; \ + diff = PCTCPU((b)) - PCTCPU((a)); \ if (diff != 0) \ return (diff > 0 ? 1 : -1); \ } while (0)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405302118.s4ULIrAa084309>