[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