[PATCH] time options for ps

Detlef Vollmann dv at vollmann.ch
Fri Jan 4 06:58:40 PST 2008


Hello,

the attached patch adds 'time' and 'etime' for ps.
It adds more than 2k (but only for CONFIG_DESKTOP) because of
the expensive computation of HZ.
If we omit support for pre-2.4 Linux, the space addition would go
way done.

  Detlef

-- 
Detlef Vollmann   vollmann engineering gmbh
Linux and C++ for Embedded Systems    http://www.vollmann.ch/
-------------- next part --------------
diff -Nupr busybox-1.9.0-orig/include/libbb.h busybox-1.9.0/include/libbb.h
--- busybox-1.9.0-orig/include/libbb.h	Fri Dec 21 23:00:31 2007
+++ busybox-1.9.0/include/libbb.h	Thu Jan  3 21:59:37 2008
@@ -982,6 +982,7 @@ typedef struct procps_status_t {
 	 * it is memset(0) for each process in procps_scan() */
 	unsigned long vsz, rss; /* we round it to kbytes */
 	unsigned long stime, utime;
+	unsigned long start_time;
 	unsigned pid;
 	unsigned ppid;
 	unsigned pgid;
@@ -1024,11 +1025,12 @@ enum {
 	PSSCAN_SMAPS	= (1 << 15) * ENABLE_FEATURE_TOPMEM,
 	PSSCAN_ARGVN    = (1 << 16) * (ENABLE_PGREP | ENABLE_PKILL),
 	USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,)
+	PSSCAN_START_TIME = 1 << 18,
 	/* These are all retrieved from proc/NN/stat in one go: */
 	PSSCAN_STAT     = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID
 	                | PSSCAN_COMM | PSSCAN_STATE
 	                | PSSCAN_VSZ | PSSCAN_RSS
-			| PSSCAN_STIME | PSSCAN_UTIME
+			| PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME
 			| PSSCAN_TTY,
 };
 procps_status_t* alloc_procps_scan(int flags);
@@ -1040,6 +1042,11 @@ void read_cmdline(char *buf, int col, un
 pid_t *find_pid_by_name(const char* procName);
 pid_t *pidlist_reverse(pid_t *pidList);
 
+#if ENABLE_DESKTOP
+extern unsigned long Hertz;
+extern unsigned long seconds_since_boot;
+void init_hertz(void);
+#endif
 
 extern const char bb_uuenc_tbl_base64[];
 extern const char bb_uuenc_tbl_std[];
diff -Nupr busybox-1.9.0-orig/libbb/procps.c busybox-1.9.0/libbb/procps.c
--- busybox-1.9.0-orig/libbb/procps.c	Fri Dec 21 23:00:29 2007
+++ busybox-1.9.0/libbb/procps.c	Thu Jan  3 22:52:59 2008
@@ -243,7 +243,8 @@ procps_status_t *procps_scan(procps_stat
 				"%lu %lu "             /* utime, stime */
 				"%*s %*s %*s "         /* cutime, cstime, priority */
 				"%ld "                 /* nice */
-				"%*s %*s %*s "         /* timeout, it_real_value, start_time */
+				"%*s %*s "             /* timeout, it_real_value */
+				"%lu "                 /* start_time */
 				"%lu "                 /* vsize */
 				"%lu "                 /* rss */
 			/*	"%lu %lu %lu %lu %lu %lu " rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
@@ -254,6 +255,7 @@ procps_status_t *procps_scan(procps_stat
 				&sp->pgid, &sp->sid, &tty,
 				&sp->utime, &sp->stime,
 				&tasknice,
+				&sp->start_time,
 				&vsz,
 				&rss);
 			if (n != 10)
@@ -280,7 +282,8 @@ procps_status_t *procps_scan(procps_stat
 			sp->stime = fast_strtoul_10(&cp);
 			cp = skip_fields(cp, 3); /* cutime, cstime, priority */
 			tasknice = fast_strtoul_10(&cp);
-			cp = skip_fields(cp, 3); /* timeout, it_real_value, start_time */
+			cp = skip_fields(cp, 2); /* timeout, it_real_value */
+			sp->start_time = fast_strtoul_10(&cp);
 			/* vsz is in bytes and we want kb */
 			sp->vsz = fast_strtoul_10(&cp) >> 10;
 			/* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
diff -Nupr busybox-1.9.0-orig/procps/Kbuild busybox-1.9.0/procps/Kbuild
--- busybox-1.9.0-orig/procps/Kbuild	Fri Dec 21 23:00:32 2007
+++ busybox-1.9.0/procps/Kbuild	Thu Jan  3 15:58:11 2008
@@ -14,6 +14,7 @@ lib-$(CONFIG_PGREP)	+= pgrep.o
 lib-$(CONFIG_PKILL)	+= pgrep.o
 lib-$(CONFIG_PIDOF)	+= pidof.o
 lib-$(CONFIG_PS)	+= ps.o
+lib-$(CONFIG_PS)	+= sysinfo.o
 lib-$(CONFIG_RENICE)	+= renice.o
 lib-$(CONFIG_BB_SYSCTL)	+= sysctl.o
 lib-$(CONFIG_TOP)	+= top.o
diff -Nupr busybox-1.9.0-orig/procps/ps.c busybox-1.9.0/procps/ps.c
--- busybox-1.9.0-orig/procps/ps.c	Fri Dec 21 23:00:32 2007
+++ busybox-1.9.0/procps/ps.c	Thu Jan  3 22:54:16 2008
@@ -73,6 +73,30 @@ static void func_tty(char *buf, int size
 		snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor);
 }
 
+static void func_etime(char *buf, int size, const procps_status_t *ps)
+{
+	/* elapsed time [[dd-]hh:]mm:ss; here only mm:ss */
+	unsigned long mm;
+	unsigned ss;
+
+	mm = seconds_since_boot - (unsigned long)(ps->start_time / Hertz);
+	ss = mm % 60;
+	mm /= 60;
+	snprintf(buf, size+1, "%3lu:%02u", mm, ss);
+}
+
+static void func_time(char *buf, int size, const procps_status_t *ps)
+{
+	/* cumulative time [[dd-]hh:]mm:ss; here only mm:ss */
+	unsigned long mm;
+	unsigned ss;
+
+	mm = (ps->utime + ps->stime) / Hertz;
+	ss = mm % 60;
+	mm /= 60;
+	snprintf(buf, size+1, "%3lu:%02u", mm, ss);
+}
+
 #if ENABLE_SELINUX
 static void func_label(char *buf, int size, const procps_status_t *ps)
 {
@@ -86,16 +110,6 @@ static void func_nice(char *buf, int siz
 	ps->???
 }
 
-static void func_etime(char *buf, int size, const procps_status_t *ps)
-{
-	elapled time [[dd-]hh:]mm:ss
-}
-
-static void func_time(char *buf, int size, const procps_status_t *ps)
-{
-	cumulative time [[dd-]hh:]mm:ss
-}
-
 static void func_pcpu(char *buf, int size, const procps_status_t *ps)
 {
 }
@@ -117,13 +131,13 @@ static const ps_out_t out_spec[] = {
 	{ 5                  , "pid"   ,"PID"    ,func_pid   ,PSSCAN_PID     },
 	{ 5                  , "ppid"  ,"PPID"   ,func_ppid  ,PSSCAN_PPID    },
 	{ 5                  , "pgid"  ,"PGID"   ,func_pgid  ,PSSCAN_PGID    },
-//	{ sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_        },
+	{ sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME },
 //	{ sizeof("GROUP"  )-1, "group" ,"GROUP"  ,func_group ,PSSCAN_UIDGID  },
 //	{ sizeof("NI"     )-1, "nice"  ,"NI"     ,func_nice  ,PSSCAN_        },
 //	{ sizeof("%CPU"   )-1, "pcpu"  ,"%CPU"   ,func_pcpu  ,PSSCAN_        },
 //	{ sizeof("RGROUP" )-1, "rgroup","RGROUP" ,func_rgroup,PSSCAN_UIDGID  },
 //	{ sizeof("RUSER"  )-1, "ruser" ,"RUSER"  ,func_ruser ,PSSCAN_UIDGID  },
-//	{ sizeof("TIME"   )-1, "time"  ,"TIME"   ,func_time  ,PSSCAN_        },
+	{ 6                  , "time"  ,"TIME"   ,func_time  ,PSSCAN_STIME | PSSCAN_UTIME },
 	{ 6                  , "tty"   ,"TT"     ,func_tty   ,PSSCAN_TTY     },
 	{ 4                  , "vsz"   ,"VSZ"    ,func_vsz   ,PSSCAN_VSZ     },
 // Not mandated by POSIX, but useful:
@@ -137,7 +151,7 @@ static const ps_out_t out_spec[] = {
 #define SELINIX_O_PREFIX "label,"
 #define DEFAULT_O_STR    SELINIX_O_PREFIX "pid,user" /* TODO: ,vsz,stat */ ",args"
 #else
-#define DEFAULT_O_STR    "pid,user" /* TODO: ,vsz,stat */ ",args"
+#define DEFAULT_O_STR    "pid,user,time" /* TODO: ,vsz,stat */ ",args"
 #endif
 
 struct globals {
@@ -317,6 +331,7 @@ int ps_main(int argc, char **argv)
 		parse_o(default_o);
 	}
 	post_process();
+	init_hertz();
 
 	/* Was INT_MAX, but some libc's go belly up with printf("%.*s")
 	 * and such large widths */
diff -Nupr busybox-1.9.0-orig/procps/sysinfo.c busybox-1.9.0/procps/sysinfo.c
--- busybox-1.9.0-orig/procps/sysinfo.c	Thu Jan  1 01:00:00 1970
+++ busybox-1.9.0/procps/sysinfo.c	Fri Jan  4 15:04:46 2008
@@ -0,0 +1,247 @@
+// sysinfo.c - compute the Hertz value (HZ inside the kernel)
+// taken from procps-3.2.7
+//
+// adaption for busybox by Detlef Vollmann, Siemens, January 2008
+// original copyright notices:
+// Copyright (C) 1992-1998 by Michael K. Johnson, johnsonm at redhat.com
+// Copyright 1998-2003 Albert Cahalan
+//
+// This file is placed under the conditions of the GNU Library
+// General Public License, version 2, or any later version.
+// See file COPYING for information on distribution conditions.
+//
+
+#if ENABLE_DESKTOP
+#include "libbb.h"
+
+#ifndef HZ
+#include <netinet/in.h>	/* htons */
+#endif
+
+#define BAD_OPEN_MESSAGE "Error: /proc must be mounted\n"
+
+#define STAT_FILE    "/proc/stat"
+#define UPTIME_FILE  "/proc/uptime"
+
+#define PROCPS_BUF_SIZE 1024
+
+
+/************** this part taken from version.c of procps-3.2.7 *********
+ * Linux kernel version information for procps utilities
+ * Copyright (c) 1996 Charles Blake <cblake at bbn.com>
+ */
+#include <sys/utsname.h>
+
+#define LINUX_VERSION(x,y,z)   (0x10000*(x) + 0x100*(y) + z)
+
+static int linux_version_code;
+
+static void init_Linux_version(void)
+{
+	static struct utsname uts;
+	int x = 0, y = 0, z = 0;	/* cleared in case sscanf() < 3 */
+
+	if (uname(&uts) == -1) {	/* failure implies impending death */
+		exit(1);
+	}
+	if (sscanf(uts.release, "%d.%d.%d", &x, &y, &z) < 3) {
+		fprintf(stderr,	/* *very* unlikely to happen by accident */
+				"Non-standard uts for running kernel:\n"
+				"release %s=%d.%d.%d gives version code %d\n",
+				uts.release, x, y, z, LINUX_VERSION(x, y, z));
+	}
+	linux_version_code = LINUX_VERSION(x, y, z);
+}
+
+/*********************** end version.c part ****************************/
+
+/***********************************************************************
+ * Some values in /proc are expressed in units of 1/HZ seconds, where HZ
+ * is the kernel clock tick rate. One of these units is called a jiffy.
+ * The HZ value used in the kernel may vary according to hacker desire.
+ * According to Linus Torvalds, this is not true. He considers the values
+ * in /proc as being in architecture-dependant units that have no relation
+ * to the kernel clock tick rate. Examination of the kernel source code
+ * reveals that opinion as wishful thinking.
+ *
+ * In any case, we need the HZ constant as used in /proc. (the real HZ value
+ * may differ, but we don't care) There are several ways we could get HZ:
+ *
+ * 1. Include the kernel header file. If it changes, recompile this library.
+ * 2. Use the sysconf() function. When HZ changes, recompile the C library!
+ * 3. Ask the kernel. This is obviously correct...
+ *
+ * Linus Torvalds won't let us ask the kernel, because he thinks we should
+ * not know the HZ value. Oh well, we don't have to listen to him.
+ * Someone smuggled out the HZ value. :-)
+ *
+ * This code should work fine, even if Linus fixes the kernel to match his
+ * stated behavior. The code only fails in case of a partial conversion.
+ *
+ * Recent update: on some architectures, the 2.4 kernel provides an
+ * ELF note to indicate HZ. This may be for ARM or user-mode Linux
+ * support. This ought to be investigated. Note that sysconf() is still
+ * unreliable, because it doesn't return an error code when it is
+ * used with a kernel that doesn't support the ELF note. On some other
+ * architectures there may be a system call or sysctl() that will work.
+ */
+
+unsigned long Hertz = 0;
+unsigned long seconds_since_boot = 0;
+static long smp_num_cpus = 0;
+
+static inline void file_to_buf(char const *filename, char *buf)
+{
+	if (open_read_close(filename, buf, sizeof(buf)) < 0) {
+		bb_error_msg_and_die(BAD_OPEN_MESSAGE);
+	}
+}
+
+static void old_Hertz_hack(void)
+{
+	char buf[PROCPS_BUF_SIZE];
+	unsigned long long user_j, nice_j, sys_j, other_j;	/* jiffies (clock ticks) */
+	double up_1, up_2, seconds;
+	unsigned long long jiffies;
+	unsigned h;
+
+	if (smp_num_cpus == 0) {
+		smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+		if (smp_num_cpus < 1) {
+			smp_num_cpus = 1;	/* SPARC glibc is buggy */
+		}
+	}
+#if ENABLE_LOCALE_SUPPORT
+	char *restrict savelocale;
+
+	savelocale = setlocale(LC_NUMERIC, NULL);
+	setlocale(LC_NUMERIC, "C");
+#endif
+	do {
+		file_to_buf(UPTIME_FILE, buf);
+		sscanf(buf, "%lf", &up_1);
+		file_to_buf(STAT_FILE, buf);
+		sscanf(buf, "cpu %Lu %Lu %Lu %Lu", &user_j, &nice_j, &sys_j,
+			   &other_j);
+		file_to_buf(UPTIME_FILE, buf);
+		sscanf(buf, "%lf", &up_2);
+	} while ((long long) ((up_2 - up_1) * 1000.0 / up_1));	/* want under 0.1% error */
+#if ENABLE_LOCALE_SUPPORT
+	setlocale(LC_NUMERIC, savelocale);
+#endif
+	jiffies = user_j + nice_j + sys_j + other_j;
+	seconds = (up_1 + up_2) / 2;
+	h = (unsigned) ((double) jiffies / seconds / smp_num_cpus);
+	/* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */
+	switch (h) {
+	case 9 ... 11:
+		Hertz = 10;		/* S/390 (sometimes) */
+		break;
+	case 18 ... 22:
+		Hertz = 20;		/* user-mode Linux */
+		break;
+	case 30 ... 34:
+		Hertz = 32;		/* ia64 emulator */
+		break;
+	case 48 ... 52:
+		Hertz = 50;
+		break;
+	case 58 ... 61:
+		Hertz = 60;
+		break;
+	case 62 ... 65:
+		Hertz = 64;		/* StrongARM /Shark */
+		break;
+	case 95 ... 105:
+		Hertz = 100;	/* normal Linux */
+		break;
+	case 124 ... 132:
+		Hertz = 128;	/* MIPS, ARM */
+		break;
+	case 195 ... 204:
+		Hertz = 200;	/* normal << 1 */
+		break;
+	case 253 ... 260:
+		Hertz = 256;
+		break;
+	case 393 ... 408:
+		Hertz = 400;	/* normal << 2 */
+		break;
+	case 790 ... 808:
+		Hertz = 800;	/* normal << 3 */
+		break;
+	case 990 ... 1010:
+		Hertz = 1000;	/* ARM */
+		break;
+	case 1015 ... 1035:
+		Hertz = 1024;	/* Alpha, ia64 */
+		break;
+	case 1180 ... 1220:
+		Hertz = 1200;	/* Alpha */
+		break;
+	default:
+#ifdef HZ
+		Hertz = (unsigned long long) HZ;	/* <asm/param.h> */
+#else
+		/* If 32-bit or big-endian (not Alpha or ia64), assume HZ is 100. */
+		Hertz = (sizeof(long) == sizeof(int)
+				 || htons(999) == 999) ? 100UL : 1024UL;
+#endif
+		fprintf(stderr, "Unknown HZ value! (%d) Assume %ld.\n", h, Hertz);
+	}
+	seconds_since_boot = seconds;
+}
+
+static void get_uptime(void)
+{
+	char buf[PROCPS_BUF_SIZE];
+
+#if ENABLE_LOCALE_SUPPORT
+	char *restrict savelocale;
+
+	savelocale = setlocale(LC_NUMERIC, NULL);
+	setlocale(LC_NUMERIC, "C");
+#endif
+
+	file_to_buf(UPTIME_FILE, buf);
+	sscanf(buf, "%lu", &seconds_since_boot);
+
+#if ENABLE_LOCALE_SUPPORT
+	setlocale(LC_NUMERIC, savelocale);
+#endif
+}
+
+#ifndef AT_CLKTCK
+#define AT_CLKTCK       17	// frequency of times()
+#endif
+#define NOTE_NOT_FOUND 42
+
+/* for ELF executables, notes are pushed before environment and args */
+static unsigned long find_elf_note(unsigned long findme)
+{
+	unsigned long *ep = (unsigned long *) environ;
+
+	while (*ep++);
+	while (*ep) {
+		if (ep[0] == findme) {
+			return ep[1];
+		}
+		ep += 2;
+	}
+	return NOTE_NOT_FOUND;
+}
+
+void init_hertz(void)
+{
+	init_Linux_version();
+	if (linux_version_code > LINUX_VERSION(2, 4, 0)) {
+		Hertz = find_elf_note(AT_CLKTCK);
+		if (Hertz != NOTE_NOT_FOUND) {
+			get_uptime();
+			return;
+		}
+		fputs("2.4+ kernel w/o ELF notes? -- report this\n", stderr);
+	}
+	old_Hertz_hack();
+}
+#endif /* ENABLE_DESKTOP */


More information about the busybox mailing list