Subject: bin/18235: increase resolution of times in top
To: None <gnats-bugs@gnats.netbsd.org>
From: None <dsl@l8s.co.uk>
List: netbsd-bugs
Date: 09/08/2002 19:26:59
>Number: 18235
>Category: bin
>Synopsis: increase resolution of times in top
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Sun Sep 08 11:24:01 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator: David Laight
>Release: NetBSD 1.6H
>Organization:
no
>Environment:
System: NetBSD snowdrop 1.6H NetBSD 1.6H (GENERIC) #164: Sat Sep 7 14:19:53 BST 2002
dsl@snowdrop:/oldroot/usr/bsd-current/src/sys/arch/i386/compile/GENERIC i386
Architecture: i386
Machine: i386
>Description:
The 'TIME' field reported by top is 0:00 for most processes because
fractions of a second are not displayed.
Additionally when the list is sorted by 'time' only whole seconds are used.
(Actually I do wonder if child time should be included, as this would
give a true idea of why the system is busy.)
>How-To-Repeat:
inspection
>Fix:
Apply following patch:
output then looks like:
PID USERNAME PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND
14141 dsl 69 4 12K 80K RUN 5h39 88.04% 88.04% x
346 root 2 0 13M 29M select 87.34 7.47% 7.47% XFree86
562 dsl 2 0 22M 46M select 1:57 2.93% 2.93% mozilla-bin
8 root 18 0 0K 29M RUN 43.72 0.05% 0.05% [ioflush]
Index: m_netbsd15.c
===================================================================
RCS file: /cvsroot/basesrc/usr.bin/top/machine/m_netbsd15.c,v
retrieving revision 1.16
diff -u -r1.16 m_netbsd15.c
--- m_netbsd15.c 2002/03/23 01:28:11 1.16
+++ m_netbsd15.c 2002/09/08 12:17:24
@@ -64,8 +64,8 @@
#include "loadavg.h"
void percentages64 __P((int, int *, u_int64_t *, u_int64_t *, u_int64_t *));
+static char *time_format(ulong, ulong);
-
/* get_process_info passes back a handle. This is what it looks like: */
struct handle {
@@ -459,7 +459,6 @@
char *(*get_userid) __P((int));
{
struct kinfo_proc2 *pp;
- long cputime;
double pct;
struct handle *hp;
const char *statep;
@@ -497,13 +496,6 @@
comm[COMSIZ - 1] = '\0';
}
-#if 0
- /* This does not produce the correct results */
- cputime = pp->p_uticks + pp->p_sticks + pp->p_iticks;
-#else
- cputime = pp->p_rtime_sec; /* This does not count interrupts */
-#endif
-
/* calculate the base for cpu percentages */
pct = pctdouble(pp->p_pctcpu);
@@ -537,7 +529,7 @@
format_k(pagetok(PROCSIZE(pp))),
format_k(pagetok(pp->p_vm_rssize)),
statep,
- format_time(cputime),
+ time_format(pp->p_rtime_sec, pp->p_rtime_usec),
100.0 * weighted_cpu(pct, pp),
100.0 * pct,
printable(pp->p_comm));
@@ -571,9 +563,8 @@
(result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
#define ORDERKEY_CPTICKS \
- if (lresult = (pctcpu)(p2)->p_rtime_sec \
- - (pctcpu)(p1)->p_rtime_sec,\
- (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
+ if ((result = (p2)->p_rtime_sec - (p1)->p_rtime_sec) == 0) \
+ if ((result = (p2)->p_rtime_usec - (p1)->p_rtime_usec) == 0)
#define ORDERKEY_STATE \
if ((result = sorted_state[(int)(p2)->p_stat] - \
@@ -835,4 +827,81 @@
half_total = total_change / 2;
for (i = 0; i < cnt; i++)
*out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
+}
+
+/* Explanation:
+ This is a rewrite of the version in utils.c to give greater precision.
+ We want to keep the output within 6 characters.
+ for values below 100 seconds nn.nn (seconds and fractions thereof)
+ for values that exceed 100 seconds nn:nn (minutes and seconds)
+ for values that exceed 100 minutes nnhnn (hours and minutes)
+ for values that exceed 100 hours nndnn (days and hours)
+ for values that exceed 100 days nnnnnd (days)
+ for values that exceed 99999 days "???"
+ */
+
+struct time_info {
+ uint lim;
+ uint base;
+ uint round;
+ char *fmt;
+};
+
+static char *
+time_format(ulong units, ulong fraction)
+{
+ static char result[10];
+ ulong new;
+
+ static struct time_info time_info[] = {
+ { 99, 60, 50, "%d.%.2d" },
+ { 99, 60, 30, "%d:%.2d" },
+ { 99, 24, 30, "%dh%.2d" },
+ { 999, 1, 12, "%dd%.2d" },
+ { 99999, 1, 0, "%dd" },
+ { 0, 0, 0, "???" },
+ };
+ struct time_info *ti;
+
+ /* We could output n.nnnnn for small values, but it isn't really
+ needed, and stops this nice loop" */
+
+ /* Convert usecs to hundredths */
+ fraction = (fraction + 5000) / 10000;
+ if (fraction >= 100) {
+ fraction -= 100;
+ units++;
+ }
+
+ for (ti = time_info; ti->lim; ti++) {
+ if (units <= ti->lim)
+ break;
+ if (fraction > ti->round)
+ units++;
+ /* Divide by constant is lots faster than by variable,
+ especially on systems without hw divide.
+ (and without a rather foul optimisation). */
+ switch (ti->base) {
+ case 1:
+ new = units;
+ fraction = 0;
+ break;
+ case 60:
+ new = units / 60;
+ fraction = units - new * 60;
+ break;
+ case 24:
+ new = units / 24;
+ fraction = units - new * 24;
+ break;
+ default:
+ new = units / ti->base;
+ fraction = units - new * ti->base;
+ break;
+ }
+ units = new;
+ }
+
+ snprintf( result, sizeof result, ti->fmt, units, fraction );
+ return result;
}
>Release-Note:
>Audit-Trail:
>Unformatted: