2006-12-21  Dmitry V. Levin <ldv@altlinux.org>

	Move counts code to separate file.
	* count.c: New file.
	* Makefile.am (strace_SOURCES): Add count.c.
	* syscall.c (call_counts, countv, counts, shortest, time_cmp,
	syscall_cmp, count_cmp, sortfun, overhead, set_sortby,
	set_overhead, call_summary_pers, call_summary): Move to count.c
	* count.c (count_syscall): New function.
	* defs.h (count_syscall): Declare it.
	* syscall.c (trace_syscall): Use it.
diff --git a/syscall.c b/syscall.c
index 6bc0618..dabdd76 100644
--- a/syscall.c
+++ b/syscall.c
@@ -249,16 +249,6 @@
 }
 
 
-struct call_counts {
-	struct timeval time;
-	int calls, errors;
-};
-
-static struct call_counts *countv[SUPPORTED_PERSONALITIES];
-#define counts (countv[current_personality])
-
-static struct timeval shortest = { 1000000, 0 };
-
 static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
 
 static const struct qual_options {
@@ -2240,8 +2230,7 @@
 }
 
 int
-trace_syscall(tcp)
-struct tcb *tcp;
+trace_syscall(struct tcb *tcp)
 {
 	int sys_res;
 	struct timeval tv;
@@ -2282,50 +2271,8 @@
 			tprintf(" resumed> ");
 		}
 
-		if (cflag && tcp->scno < nsyscalls && tcp->scno >= 0) {
-			if (counts == NULL) {
-				counts = calloc(sizeof *counts, nsyscalls);
-				if (counts == NULL) {
-					fprintf(stderr, "\
-strace: out of memory for call counts\n");
-					exit(1);
-				}
-			}
-
-			counts[tcp->scno].calls++;
-			if (tcp->u_error)
-				counts[tcp->scno].errors++;
-			tv_sub(&tv, &tv, &tcp->etime);
-#ifdef LINUX
-			if (tv_cmp(&tv, &tcp->dtime) > 0) {
-				static struct timeval one_tick;
-				if (one_tick.tv_usec == 0) {
-					/* Initialize it.  */
-					struct itimerval it;
-					memset(&it, 0, sizeof it);
-					it.it_interval.tv_usec = 1;
-					setitimer(ITIMER_REAL, &it, NULL);
-					getitimer(ITIMER_REAL, &it);
-					one_tick = it.it_interval;
-				}
-
-				if (tv_nz(&tcp->dtime))
-					tv = tcp->dtime;
-				else if (tv_cmp(&tv, &one_tick) > 0) {
-					if (tv_cmp(&shortest, &one_tick) < 0)
-						tv = shortest;
-					else
-						tv = one_tick;
-				}
-			}
-#endif /* LINUX */
-			if (tv_cmp(&tv, &shortest) < 0)
-				shortest = tv;
-			tv_add(&counts[tcp->scno].time,
-				&counts[tcp->scno].time, &tv);
-			tcp->flags &= ~TCB_INSYSCALL;
-			return 0;
-		}
+		if (cflag)
+			return count_syscall(tcp, &tv);
 
 		if (tcp->scno >= nsyscalls || tcp->scno < 0
 		    || (qual_flags[tcp->scno] & QUAL_RAW))
@@ -2650,149 +2597,3 @@
 	return 0;
 }
 #endif /* SUNOS4 */
-
-static int
-time_cmp(a, b)
-void *a;
-void *b;
-{
-	return -tv_cmp(&counts[*((int *) a)].time, &counts[*((int *) b)].time);
-}
-
-static int
-syscall_cmp(a, b)
-void *a;
-void *b;
-{
-	return strcmp(sysent[*((int *) a)].sys_name,
-		sysent[*((int *) b)].sys_name);
-}
-
-static int
-count_cmp(a, b)
-void *a;
-void *b;
-{
-	int m = counts[*((int *) a)].calls, n = counts[*((int *) b)].calls;
-
-	return (m < n) ? 1 : (m > n) ? -1 : 0;
-}
-
-static int (*sortfun)();
-static struct timeval overhead = { -1, -1 };
-
-void
-set_sortby(sortby)
-char *sortby;
-{
-	if (strcmp(sortby, "time") == 0)
-		sortfun = time_cmp;
-	else if (strcmp(sortby, "calls") == 0)
-		sortfun = count_cmp;
-	else if (strcmp(sortby, "name") == 0)
-		sortfun = syscall_cmp;
-	else if (strcmp(sortby, "nothing") == 0)
-		sortfun = NULL;
-	else {
-		fprintf(stderr, "invalid sortby: `%s'\n", sortby);
-		exit(1);
-	}
-}
-
-void set_overhead(n)
-int n;
-{
-	overhead.tv_sec = n / 1000000;
-	overhead.tv_usec = n % 1000000;
-}
-
-static void
-call_summary_pers(FILE *outf)
-{
-	int i, j;
-	int call_cum, error_cum;
-	struct timeval tv_cum, dtv;
-	double percent;
-	char *dashes = "-------------------------";
-	char error_str[16];
-
-	int *sorted_count = malloc(nsyscalls * sizeof(int));
-
-	call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_usec = 0;
-	if (overhead.tv_sec == -1) {
-		tv_mul(&overhead, &shortest, 8);
-		tv_div(&overhead, &overhead, 10);
-	}
-	for (i = 0; i < nsyscalls; i++) {
-		sorted_count[i] = i;
-		if (counts == NULL || counts[i].calls == 0)
-			continue;
-		tv_mul(&dtv, &overhead, counts[i].calls);
-		tv_sub(&counts[i].time, &counts[i].time, &dtv);
-		call_cum += counts[i].calls;
-		error_cum += counts[i].errors;
-		tv_add(&tv_cum, &tv_cum, &counts[i].time);
-	}
-	if (counts && sortfun)
-		qsort((void *) sorted_count, nsyscalls, sizeof(int), sortfun);
-	fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %s\n",
-		"% time", "seconds", "usecs/call",
-		"calls", "errors", "syscall");
-	fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
-		dashes, dashes, dashes, dashes, dashes, dashes);
-	if (counts) {
-		for (i = 0; i < nsyscalls; i++) {
-			j = sorted_count[i];
-			if (counts[j].calls == 0)
-				continue;
-			tv_div(&dtv, &counts[j].time, counts[j].calls);
-			if (counts[j].errors)
-				sprintf(error_str, "%d", counts[j].errors);
-			else
-				error_str[0] = '\0';
-			percent = (100.0 * tv_float(&counts[j].time)
-				   / tv_float(&tv_cum));
-			fprintf(outf, "%6.2f %4ld.%06ld %11ld %9d %9.9s %s\n",
-				percent, (long) counts[j].time.tv_sec,
-				(long) counts[j].time.tv_usec,
-				(long) 1000000 * dtv.tv_sec + dtv.tv_usec,
-				counts[j].calls,
-				error_str, sysent[j].sys_name);
-		}
-	}
-	free(sorted_count);
-
-	fprintf(outf, "%6.6s %11.11s %11.11s %9.9s %9.9s %-16.16s\n",
-		dashes, dashes, dashes, dashes, dashes, dashes);
-	if (error_cum)
-		sprintf(error_str, "%d", error_cum);
-	else
-		error_str[0] = '\0';
-	fprintf(outf, "%6.6s %4ld.%06ld %11.11s %9d %9.9s %s\n",
-		"100.00", (long) tv_cum.tv_sec, (long) tv_cum.tv_usec, "",
-		call_cum, error_str, "total");
-
-}
-
-void
-call_summary(FILE *outf)
-{
-	int     i, old_pers = current_personality;
-
-	for (i = 0; i < SUPPORTED_PERSONALITIES; ++i)
-	{
-		if (!countv[i])
-			continue;
-
-		if (current_personality != i)
-			set_personality(i);
-		if (i)
-			fprintf(outf,
-				"System call usage summary for %u bit mode:\n",
-				personality_wordsize[current_personality] * 8);
-		call_summary_pers(outf);
-	}
-
-	if (old_pers != current_personality)
-		set_personality(old_pers);
-}