]> granicus.if.org Git - strace/blobdiff - count.c
tests: fix format warnings on x32
[strace] / count.c
diff --git a/count.c b/count.c
index a374bad024e7d703ac26824bc392059236081b39..a1cdf8235ee34d3db1ab300698f9b353e5af337e 100644 (file)
--- a/count.c
+++ b/count.c
@@ -8,30 +8,10 @@
  *                    <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
  * Copyright (c) 2004 Roland McGrath <roland@redhat.com>
  * Copyright (c) 2006 Dmitry V. Levin <ldv@altlinux.org>
- * Copyright (c) 2006-2017 The strace developers.
+ * Copyright (c) 2006-2018 The strace developers.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
  */
 
 #include "defs.h"
 /* Per-syscall stats structure */
 struct call_counts {
        /* time may be total latency or system time */
-       struct timeval time;
+       struct timespec time;
        unsigned int calls, errors;
 };
 
 static struct call_counts *countv[SUPPORTED_PERSONALITIES];
 #define counts (countv[current_personality])
 
-static struct timeval shortest = { 1000000, 0 };
+static const struct timespec zero_ts;
+
+static struct timespec overhead;
 
 void
-count_syscall(struct tcb *tcp, const struct timeval *syscall_exiting_tv)
+count_syscall(struct tcb *tcp, const struct timespec *syscall_exiting_ts)
 {
-       struct timeval wtv;
-       struct timeval *tv = &wtv;
-       struct call_counts *cc;
-
        if (!scno_in_range(tcp->scno))
                return;
 
        if (!counts)
                counts = xcalloc(nsyscalls, sizeof(*counts));
-       cc = &counts[tcp->scno];
+       struct call_counts *cc = &counts[tcp->scno];
 
        cc->calls++;
        if (syserror(tcp))
                cc->errors++;
 
-       /* tv = wall clock time spent while in syscall */
-       tv_sub(tv, syscall_exiting_tv, &tcp->etime);
-
-       /* Spent more wall clock time than spent system time? (usually yes) */
-       if (tv_cmp(tv, &tcp->dtime) > 0) {
-               static struct timeval one_tick = { -1, 0 };
-
-               if (one_tick.tv_sec == -1) {
-                       /* 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;
-//FIXME: this hack doesn't work (tested on linux-3.6.11): one_tick = 0.000000
-//tprintf(" one_tick.tv_usec:%u\n", (unsigned)one_tick.tv_usec);
-               }
-
-               if (tv_nz(&tcp->dtime))
-                       /* tv = system time spent, if it isn't 0 */
-                       tv = &tcp->dtime;
-               else if (tv_cmp(tv, &one_tick) > 0) {
-                       /* tv = smallest "sane" time interval */
-                       if (tv_cmp(&shortest, &one_tick) < 0)
-                               tv = &shortest;
-                       else
-                               tv = &one_tick;
-               }
+       struct timespec wts;
+       if (count_wallclock) {
+               /* wall clock time spent while in syscall */
+               ts_sub(&wts, syscall_exiting_ts, &tcp->etime);
+       } else {
+               /* system CPU time spent while in syscall */
+               ts_sub(&wts, &tcp->stime, &tcp->ltime);
        }
-       if (tv_cmp(tv, &shortest) < 0)
-               shortest = *tv;
-       tv_add(&cc->time, &cc->time, count_wallclock ? &wtv : tv);
+
+       ts_sub(&wts, &wts, &overhead);
+       ts_add(&cc->time, &cc->time, ts_max(&wts, &zero_ts));
 }
 
 static int
-time_cmp(void *a, void *b)
+time_cmp(const void *a, const void *b)
 {
-       return -tv_cmp(&counts[*((int *) a)].time,
-                      &counts[*((int *) b)].time);
+       const unsigned int *a_int = a;
+       const unsigned int *b_int = b;
+       return -ts_cmp(&counts[*a_int].time, &counts[*b_int].time);
 }
 
 static int
-syscall_cmp(void *a, void *b)
+syscall_cmp(const void *a, const void *b)
 {
-       const char *a_name = sysent[*((int *) a)].sys_name;
-       const char *b_name = sysent[*((int *) b)].sys_name;
+       const unsigned int *a_int = a;
+       const unsigned int *b_int = b;
+       const char *a_name = sysent[*a_int].sys_name;
+       const char *b_name = sysent[*b_int].sys_name;
        return strcmp(a_name ? a_name : "", b_name ? b_name : "");
 }
 
 static int
-count_cmp(void *a, void *b)
+count_cmp(const void *a, const void *b)
 {
-       int     m = counts[*((int *) a)].calls;
-       int     n = counts[*((int *) b)].calls;
+       const unsigned int *a_int = a;
+       const unsigned int *b_int = b;
+       unsigned int m = counts[*a_int].calls;
+       unsigned int n = counts[*b_int].calls;
 
        return (m < n) ? 1 : (m > n) ? -1 : 0;
 }
 
-static int (*sortfun)();
-static struct timeval overhead = { -1, -1 };
+static int
+error_cmp(const void *a, const void *b)
+{
+       const unsigned int *a_int = a;
+       const unsigned int *b_int = b;
+       unsigned int m = counts[*a_int].errors;
+       unsigned int n = counts[*b_int].errors;
+
+       return (m < n) ? 1 : (m > n) ? -1 : 0;
+}
+
+static int (*sortfun)(const void *, const void *);
 
 void
 set_sortby(const 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 {
-               error_msg_and_help("invalid sortby: '%s'", sortby);
+       static const struct {
+               int (*fn)(const void *, const void *);
+               const char *name;
+       } sort_fns[] = {
+               { time_cmp,     "time" },
+               { time_cmp,     "time_total" },
+               { time_cmp,     "total_time" },
+               { count_cmp,    "calls" },
+               { count_cmp,    "count" },
+               { error_cmp,    "error" },
+               { error_cmp,    "errors" },
+               { syscall_cmp,  "name" },
+               { syscall_cmp,  "syscall" },
+               { syscall_cmp,  "syscall_name" },
+               { NULL,         "none" },
+               { NULL,         "nothing" },
+       };
+
+       for (size_t i = 0; i < ARRAY_SIZE(sort_fns); ++i) {
+               if (!strcmp(sort_fns[i].name, sortby)) {
+                       sortfun = sort_fns[i].fn;
+                       return;
+               }
        }
+
+       error_msg_and_help("invalid sortby: '%s'", sortby);
 }
 
-void set_overhead(int n)
+int
+set_overhead(const char *str)
 {
-       overhead.tv_sec = n / 1000000;
-       overhead.tv_usec = n % 1000000;
+       return parse_ts(str, &overhead);
 }
 
 static void
@@ -161,7 +146,7 @@ call_summary_pers(FILE *outf)
 
        unsigned int i;
        unsigned int call_cum, error_cum;
-       struct timeval tv_cum, dtv;
+       struct timespec tv_cum, dtv;
        double  float_tv_cum;
        double  percent;
        unsigned int *sorted_count;
@@ -172,22 +157,16 @@ call_summary_pers(FILE *outf)
        fprintf(outf, header, dashes, dashes, dashes, dashes, dashes, dashes);
 
        sorted_count = xcalloc(sizeof(sorted_count[0]), nsyscalls);
-       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);
-       }
+       call_cum = error_cum = tv_cum.tv_sec = tv_cum.tv_nsec = 0;
        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);
+               ts_add(&tv_cum, &tv_cum, &counts[i].time);
        }
-       float_tv_cum = tv_float(&tv_cum);
+       float_tv_cum = ts_float(&tv_cum);
        if (counts) {
                if (sortfun)
                        qsort((void *) sorted_count, nsyscalls,
@@ -198,17 +177,16 @@ call_summary_pers(FILE *outf)
                        struct call_counts *cc = &counts[idx];
                        if (cc->calls == 0)
                                continue;
-                       tv_div(&dtv, &cc->time, cc->calls);
-                       float_syscall_time = tv_float(&cc->time);
+                       ts_div(&dtv, &cc->time, cc->calls);
+                       float_syscall_time = ts_float(&cc->time);
                        percent = (100.0 * float_syscall_time);
                        if (percent != 0.0)
                                   percent /= float_tv_cum;
                        /* else: float_tv_cum can be 0.0 too and we get 0/0 = NAN */
                        fprintf(outf, data,
                                percent, float_syscall_time,
-                               (long) (1000000 * dtv.tv_sec + dtv.tv_usec),
-                               cc->calls,
-                               cc->errors, sysent[idx].sys_name);
+                               (long) (1000000 * dtv.tv_sec + dtv.tv_nsec / 1000),
+                               cc->calls, cc->errors, sysent[idx].sys_name);
                }
        }
        free(sorted_count);