* <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
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;
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,
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);