hwclock: size optimizations
libbb/time.c: new file, introducing monotonic_us()
pscan, traceroute, arping: use it instead of gettimeofday
ping, zcip: TODO

function                                             old     new   delta
monotonic_us                                           -      89     +89
find_pair                                            164     180     +16
.rodata                                           129747  129763     +16
refresh                                             1144    1152      +8
............
timeout                                                8       4      -4
static.start                                           8       4      -4
last                                                   8       4      -4
parse_conf                                          1303    1284     -19
time_main                                           1149    1124     -25
gettimeofday_us                                       39       -     -39
arping_main                                         2042    1969     -73
hwclock_main                                         594     501     -93
catcher                                              485     380    -105
traceroute_main                                     4300    4117    -183
------------------------------------------------------------------------------
(add/remove: 2/1 grow/shrink: 8/11 up/down: 157/-562)        Total: -405 bytes

diff --git a/miscutils/time.c b/miscutils/time.c
index 705123c..578cb35 100644
--- a/miscutils/time.c
+++ b/miscutils/time.c
@@ -11,28 +11,16 @@
 
 #include "libbb.h"
 
-#define TV_MSEC tv_usec / 1000
-
 /* Information on the resources used by a child process.  */
 typedef struct {
 	int waitstatus;
 	struct rusage ru;
-	struct timeval start, elapsed;	/* Wallclock time of process.  */
+	unsigned elapsed_ms;	/* Wallclock time of process.  */
 } resource_t;
 
 /* msec = milliseconds = 1/1,000 (1*10e-3) second.
    usec = microseconds = 1/1,000,000 (1*10e-6) second.  */
 
-#ifndef TICKS_PER_SEC
-#define TICKS_PER_SEC 100
-#endif
-
-/* The number of milliseconds in one `tick' used by the `rusage' structure.  */
-#define MSEC_PER_TICK (1000 / TICKS_PER_SEC)
-
-/* Return the number of clock ticks that occur in M milliseconds.  */
-#define MSEC_TO_TICKS(m) ((m) / MSEC_PER_TICK)
-
 #define UL unsigned long
 
 static const char default_format[] = "real\t%E\nuser\t%u\nsys\t%T";
@@ -76,7 +64,6 @@
 static int resuse_end(pid_t pid, resource_t * resp)
 {
 	int status;
-
 	pid_t caught;
 
 	/* Ignore signals, but don't ignore the children.  When wait3
@@ -85,18 +72,8 @@
 		if (caught == -1)
 			return 0;
 	}
-
-	gettimeofday(&resp->elapsed, (struct timezone *) 0);
-	resp->elapsed.tv_sec -= resp->start.tv_sec;
-	if (resp->elapsed.tv_usec < resp->start.tv_usec) {
-		/* Manually carry a one from the seconds field.  */
-		resp->elapsed.tv_usec += 1000000;
-		--resp->elapsed.tv_sec;
-	}
-	resp->elapsed.tv_usec -= resp->start.tv_usec;
-
+	resp->elapsed_ms = (monotonic_us() / 1000) - resp->elapsed_ms;
 	resp->waitstatus = status;
-
 	return 1;
 }
 
@@ -181,30 +158,30 @@
    COMMAND is the command and args that are being summarized.
    RESP is resource information on the command.  */
 
+#ifndef TICKS_PER_SEC
+#define TICKS_PER_SEC 100
+#endif
+
 static void summarize(const char *fmt, char **command, resource_t * resp)
 {
-	unsigned long r;	/* Elapsed real milliseconds.  */
-	unsigned long v;	/* Elapsed virtual (CPU) milliseconds.  */
+	unsigned vv_ms;     /* Elapsed virtual (CPU) milliseconds */
+	unsigned cpu_ticks; /* Same, in "CPU ticks" */
 
 	if (WIFSTOPPED(resp->waitstatus))
-		printf("Command stopped by signal %d\n",
+		printf("Command stopped by signal %u\n",
 				WSTOPSIG(resp->waitstatus));
 	else if (WIFSIGNALED(resp->waitstatus))
-		printf("Command terminated by signal %d\n",
+		printf("Command terminated by signal %u\n",
 				WTERMSIG(resp->waitstatus));
 	else if (WIFEXITED(resp->waitstatus) && WEXITSTATUS(resp->waitstatus))
-		printf("Command exited with non-zero status %d\n",
+		printf("Command exited with non-zero status %u\n",
 				WEXITSTATUS(resp->waitstatus));
 
-	/* Convert all times to milliseconds.  Occasionally, one of these values
-	   comes out as zero.  Dividing by zero causes problems, so we first
-	   check the time value.  If it is zero, then we take `evasive action'
-	   instead of calculating a value.  */
+	vv_ms = (resp->ru.ru_utime.tv_sec + resp->ru.ru_stime.tv_sec) * 1000
+	      + (resp->ru.ru_utime.tv_usec + resp->ru.ru_stime.tv_usec) / 1000;
 
-	r = resp->elapsed.tv_sec * 1000 + resp->elapsed.tv_usec / 1000;
-
-	v = resp->ru.ru_utime.tv_sec * 1000 + resp->ru.ru_utime.TV_MSEC +
-		resp->ru.ru_stime.tv_sec * 1000 + resp->ru.ru_stime.TV_MSEC;
+	cpu_ticks = vv_ms * TICKS_PER_SEC / 1000;
+	if (!cpu_ticks) cpu_ticks = 1; /* we divide by it, must be nonzero */
 
 	/* putchar() != putc(stdout) in glibc! */
 
@@ -245,127 +222,122 @@
 				break;
 			case 'D':	/* Average unshared data size.  */
 				printf("%lu",
-						MSEC_TO_TICKS(v) == 0 ? 0 :
-						ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) +
-						ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v));
+						ptok((UL) resp->ru.ru_idrss) / cpu_ticks +
+						ptok((UL) resp->ru.ru_isrss) / cpu_ticks);
 				break;
-			case 'E':	/* Elapsed real (wall clock) time.  */
-				if (resp->elapsed.tv_sec >= 3600)	/* One hour -> h:m:s.  */
-					printf("%ldh %ldm %02lds",
-							resp->elapsed.tv_sec / 3600,
-							(resp->elapsed.tv_sec % 3600) / 60,
-							resp->elapsed.tv_sec % 60);
+			case 'E': {	/* Elapsed real (wall clock) time.  */
+				unsigned seconds = resp->elapsed_ms / 1000;
+				if (seconds >= 3600)	/* One hour -> h:m:s.  */
+					printf("%uh %um %02us",
+							seconds / 3600,
+							(seconds % 3600) / 60,
+							seconds % 60);
 				else
-					printf("%ldm %ld.%02lds",	/* -> m:s.  */
-							resp->elapsed.tv_sec / 60,
-							resp->elapsed.tv_sec % 60,
-							resp->elapsed.tv_usec / 10000);
+					printf("%um %u.%02us",	/* -> m:s.  */
+							seconds / 60,
+							seconds % 60,
+							(unsigned)(resp->elapsed_ms / 10) % 100);
 				break;
+			}
 			case 'F':	/* Major page faults.  */
-				printf("%ld", resp->ru.ru_majflt);
+				printf("%lu", resp->ru.ru_majflt);
 				break;
 			case 'I':	/* Inputs.  */
-				printf("%ld", resp->ru.ru_inblock);
+				printf("%lu", resp->ru.ru_inblock);
 				break;
 			case 'K':	/* Average mem usage == data+stack+text.  */
 				printf("%lu",
-						MSEC_TO_TICKS(v) == 0 ? 0 :
-						ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v) +
-						ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v) +
-						ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v));
+						ptok((UL) resp->ru.ru_idrss) / cpu_ticks +
+						ptok((UL) resp->ru.ru_isrss) / cpu_ticks +
+						ptok((UL) resp->ru.ru_ixrss) / cpu_ticks);
 				break;
 			case 'M':	/* Maximum resident set size.  */
 				printf("%lu", ptok((UL) resp->ru.ru_maxrss));
 				break;
 			case 'O':	/* Outputs.  */
-				printf("%ld", resp->ru.ru_oublock);
+				printf("%lu", resp->ru.ru_oublock);
 				break;
 			case 'P':	/* Percent of CPU this job got.  */
 				/* % cpu is (total cpu time)/(elapsed time).  */
-				if (r > 0)
-					printf("%lu%%", (v * 100 / r));
+				if (resp->elapsed_ms > 0)
+					printf("%u%%", (unsigned)(vv_ms * 100 / resp->elapsed_ms));
 				else
 					printf("?%%");
 				break;
 			case 'R':	/* Minor page faults (reclaims).  */
-				printf("%ld", resp->ru.ru_minflt);
+				printf("%lu", resp->ru.ru_minflt);
 				break;
 			case 'S':	/* System time.  */
-				printf("%ld.%02ld",
-						resp->ru.ru_stime.tv_sec,
-						resp->ru.ru_stime.TV_MSEC / 10);
+				printf("%u.%02u",
+						(unsigned)resp->ru.ru_stime.tv_sec,
+						(unsigned)(resp->ru.ru_stime.tv_usec / 10000));
 				break;
 			case 'T':	/* System time.  */
 				if (resp->ru.ru_stime.tv_sec >= 3600) /* One hour -> h:m:s.  */
-					printf("%ldh %ldm %02lds",
-							resp->ru.ru_stime.tv_sec / 3600,
-							(resp->ru.ru_stime.tv_sec % 3600) / 60,
-							resp->ru.ru_stime.tv_sec % 60);
+					printf("%uh %um %02us",
+							(unsigned)(resp->ru.ru_stime.tv_sec / 3600),
+							(unsigned)(resp->ru.ru_stime.tv_sec % 3600) / 60,
+							(unsigned)(resp->ru.ru_stime.tv_sec % 60));
 				else
-					printf("%ldm %ld.%02lds",	/* -> m:s.  */
-							resp->ru.ru_stime.tv_sec / 60,
-							resp->ru.ru_stime.tv_sec % 60,
-							resp->ru.ru_stime.tv_usec / 10000);
+					printf("%um %u.%02us",	/* -> m:s.  */
+							(unsigned)(resp->ru.ru_stime.tv_sec / 60),
+							(unsigned)(resp->ru.ru_stime.tv_sec % 60),
+							(unsigned)(resp->ru.ru_stime.tv_usec / 10000));
 				break;
 			case 'U':	/* User time.  */
-				printf("%ld.%02ld",
-						resp->ru.ru_utime.tv_sec,
-						resp->ru.ru_utime.TV_MSEC / 10);
+				printf("%u.%02u",
+						(unsigned)resp->ru.ru_utime.tv_sec,
+						(unsigned)(resp->ru.ru_utime.tv_usec / 10000));
 				break;
 			case 'u':	/* User time.  */
 				if (resp->ru.ru_utime.tv_sec >= 3600) /* One hour -> h:m:s.  */
-					printf("%ldh %ldm %02lds",
-							resp->ru.ru_utime.tv_sec / 3600,
-							(resp->ru.ru_utime.tv_sec % 3600) / 60,
-							resp->ru.ru_utime.tv_sec % 60);
+					printf("%uh %um %02us",
+							(unsigned)(resp->ru.ru_utime.tv_sec / 3600),
+							(unsigned)(resp->ru.ru_utime.tv_sec % 3600) / 60,
+							(unsigned)(resp->ru.ru_utime.tv_sec % 60));
 				else
-					printf("%ldm %ld.%02lds",	/* -> m:s.  */
-							resp->ru.ru_utime.tv_sec / 60,
-							resp->ru.ru_utime.tv_sec % 60,
-							resp->ru.ru_utime.tv_usec / 10000);
+					printf("%um %u.%02us",	/* -> m:s.  */
+							(unsigned)(resp->ru.ru_utime.tv_sec / 60),
+							(unsigned)(resp->ru.ru_utime.tv_sec % 60),
+							(unsigned)(resp->ru.ru_utime.tv_usec / 10000));
 				break;
 			case 'W':	/* Times swapped out.  */
-				printf("%ld", resp->ru.ru_nswap);
+				printf("%lu", resp->ru.ru_nswap);
 				break;
 			case 'X':	/* Average shared text size.  */
-				printf("%lu",
-						MSEC_TO_TICKS(v) == 0 ? 0 :
-						ptok((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS(v));
+				printf("%lu", ptok((UL) resp->ru.ru_ixrss) / cpu_ticks);
 				break;
 			case 'Z':	/* Page size.  */
-				printf("%d", getpagesize());
+				printf("%u", getpagesize());
 				break;
 			case 'c':	/* Involuntary context switches.  */
-				printf("%ld", resp->ru.ru_nivcsw);
+				printf("%lu", resp->ru.ru_nivcsw);
 				break;
 			case 'e':	/* Elapsed real time in seconds.  */
-				printf("%ld.%02ld",
-						resp->elapsed.tv_sec, resp->elapsed.tv_usec / 10000);
+				printf("%u.%02u",
+						(unsigned)resp->elapsed_ms / 1000,
+						(unsigned)(resp->elapsed_ms / 10) % 100);
 				break;
 			case 'k':	/* Signals delivered.  */
-				printf("%ld", resp->ru.ru_nsignals);
+				printf("%lu", resp->ru.ru_nsignals);
 				break;
 			case 'p':	/* Average stack segment.  */
-				printf("%lu",
-						MSEC_TO_TICKS(v) == 0 ? 0 :
-						ptok((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS(v));
+				printf("%lu", ptok((UL) resp->ru.ru_isrss) / cpu_ticks);
 				break;
 			case 'r':	/* Incoming socket messages received.  */
-				printf("%ld", resp->ru.ru_msgrcv);
+				printf("%lu", resp->ru.ru_msgrcv);
 				break;
 			case 's':	/* Outgoing socket messages sent.  */
-				printf("%ld", resp->ru.ru_msgsnd);
+				printf("%lu", resp->ru.ru_msgsnd);
 				break;
 			case 't':	/* Average resident set size.  */
-				printf("%lu",
-						MSEC_TO_TICKS(v) == 0 ? 0 :
-						ptok((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS(v));
+				printf("%lu", ptok((UL) resp->ru.ru_idrss) / cpu_ticks);
 				break;
 			case 'w':	/* Voluntary context switches.  */
-				printf("%ld", resp->ru.ru_nvcsw);
+				printf("%lu", resp->ru.ru_nvcsw);
 				break;
 			case 'x':	/* Exit status.  */
-				printf("%d", WEXITSTATUS(resp->waitstatus));
+				printf("%u", WEXITSTATUS(resp->waitstatus));
 				break;
 			}
 			break;
@@ -403,7 +375,7 @@
 	pid_t pid;			/* Pid of child.  */
 	__sighandler_t interrupt_signal, quit_signal;
 
-	gettimeofday(&resp->start, (struct timezone *) 0);
+	resp->elapsed_ms = monotonic_us() / 1000;
 	pid = vfork();		/* Run CMD as child process.  */
 	if (pid < 0)
 		bb_error_msg_and_die("cannot fork");