]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
perf trace: Introduce --errno-summary
authorArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 14 Oct 2019 18:32:40 +0000 (15:32 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 15 Oct 2019 16:03:49 +0000 (13:03 -0300)
To be used with -S or -s, using just this new option implies -s,
examples:

  # perf trace --errno-summary sleep 1

   Summary of events:

   sleep (10793), 80 events, 93.0%

     syscall            calls  errors  total       min       avg       max       stddev
                                       (msec)    (msec)    (msec)    (msec)        (%)
     --------------- --------  ------ -------- --------- --------- ---------     ------
     nanosleep              1      0  1000.427  1000.427  1000.427  1000.427      0.00%
     mmap                   8      0     0.026     0.002     0.003     0.005      9.18%
     close                  5      0     0.018     0.001     0.004     0.009     48.97%
     mprotect               4      0     0.017     0.003     0.004     0.006     16.49%
     openat                 3      0     0.012     0.003     0.004     0.005      9.41%
     munmap                 1      0     0.010     0.010     0.010     0.010      0.00%
     brk                    4      0     0.005     0.001     0.001     0.002     22.77%
     read                   4      0     0.005     0.001     0.001     0.002     22.33%
     access                 1      1     0.004     0.004     0.004     0.004      0.00%
   ENOENT: 1
     fstat                  3      0     0.004     0.001     0.001     0.002     17.18%
     lseek                  3      0     0.003     0.001     0.001     0.001     11.62%
     arch_prctl             2      1     0.002     0.001     0.001     0.001      3.32%
   EINVAL: 1
     execve                 1      0     0.000     0.000     0.000     0.000      0.00%

  #

Works as well together with --failure and -S, i.e. collect the stats and
show just the syscalls that failed:

  # perf trace --failure -S --errno-summary sleep 1
       0.032 arch_prctl(option: 0x3001, arg2: 0x7fffdb11b580) = -1 EINVAL (Invalid argument)
       0.045 access(filename: "/etc/ld.so.preload", mode: R) = -1 ENOENT (No such file or directory)

   Summary of events:

   sleep (10806), 80 events, 93.0%

     syscall            calls  errors  total       min       avg       max       stddev
                                       (msec)    (msec)    (msec)    (msec)        (%)
     --------------- --------  ------ -------- --------- --------- ---------     ------
     nanosleep              1      0  1000.094  1000.094  1000.094  1000.094      0.00%
     mmap                   8      0     0.026     0.002     0.003     0.005      9.06%
     close                  5      0     0.018     0.001     0.004     0.010     49.58%
     mprotect               4      0     0.017     0.003     0.004     0.006     17.56%
     openat                 3      0     0.014     0.004     0.005     0.006     12.29%
     munmap                 1      0     0.010     0.010     0.010     0.010      0.00%
     brk                    4      0     0.005     0.001     0.001     0.002     22.75%
     read                   4      0     0.005     0.001     0.001     0.002     17.19%
     access                 1      1     0.005     0.005     0.005     0.005      0.00%
   ENOENT: 1
     fstat                  3      0     0.004     0.001     0.001     0.002     21.66%
     lseek                  3      0     0.003     0.001     0.001     0.001     11.71%
     arch_prctl             2      1     0.002     0.001     0.001     0.001      2.66%
   EINVAL: 1
     execve                 1      0     0.000     0.000     0.000     0.000      0.00%

  #

Suggested-by: Andi Kleen <ak@linux.intel.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Luis Cláudio Gonçalves <lclaudio@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lkml.kernel.org/n/tip-l0mjwczkpouov7lss5zn8d9h@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-trace.txt
tools/perf/builtin-trace.c

index 3bb89c2e90209e672c2a1531b78e805f45561715..abc9b5d833128c2bc803fd344308ff3059ea1a12 100644 (file)
@@ -146,6 +146,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
        Show all syscalls followed by a summary by thread with min, max, and
     average times (in msec) and relative stddev.
 
+--errno-summary::
+       To be used with -s or -S, to show stats for the errnos experienced by
+       syscalls, using only this option will trigger --summary.
+
 --tool_stats::
        Show tool stats such as number of times fd->pathname was discovered thru
        hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc.
index 56f2d72104a55132ddc4914940e8a294d3f23b09..467e18e6f8ec3cfadd88e2474094aed96f4056bd 100644 (file)
@@ -175,6 +175,7 @@ struct trace {
        bool                    multiple_threads;
        bool                    summary;
        bool                    summary_only;
+       bool                    errno_summary;
        bool                    failure_only;
        bool                    show_comm;
        bool                    print_sample;
@@ -1961,10 +1962,12 @@ static struct syscall *trace__syscall_info(struct trace *trace,
 struct syscall_stats {
        struct stats stats;
        u64          nr_failures;
+       int          max_errno;
+       u32          *errnos;
 };
 
-static void thread__update_stats(struct thread_trace *ttrace,
-                                int id, struct perf_sample *sample, long err)
+static void thread__update_stats(struct thread *thread, struct thread_trace *ttrace,
+                                int id, struct perf_sample *sample, long err, bool errno_summary)
 {
        struct int_node *inode;
        struct syscall_stats *stats;
@@ -1981,6 +1984,8 @@ static void thread__update_stats(struct thread_trace *ttrace,
                        return;
 
                stats->nr_failures = 0;
+               stats->max_errno   = 0;
+               stats->errnos      = NULL;
                init_stats(&stats->stats);
                inode->priv = stats;
        }
@@ -1990,8 +1995,30 @@ static void thread__update_stats(struct thread_trace *ttrace,
 
        update_stats(&stats->stats, duration);
 
-       if (err < 0)
+       if (err < 0) {
                ++stats->nr_failures;
+
+               if (!errno_summary)
+                       return;
+
+               err = -err;
+               if (err > stats->max_errno) {
+                       u32 *new_errnos = realloc(stats->errnos, err * sizeof(u32));
+
+                       if (new_errnos) {
+                               memset(new_errnos + stats->max_errno, 0, (err - stats->max_errno) * sizeof(u32));
+                       } else {
+                               pr_debug("Not enough memory for errno stats for thread \"%s\"(%d/%d), results will be incomplete\n",
+                                        thread__comm_str(thread), thread->pid_, thread->tid);
+                               return;
+                       }
+
+                       stats->errnos = new_errnos;
+                       stats->max_errno = err;
+               }
+
+               ++stats->errnos[err - 1];
+       }
 }
 
 static int trace__printf_interrupted_entry(struct trace *trace)
@@ -2239,7 +2266,7 @@ static int trace__sys_exit(struct trace *trace, struct evsel *evsel,
        ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
 
        if (trace->summary)
-               thread__update_stats(ttrace, id, sample, ret);
+               thread__update_stats(thread, ttrace, id, sample, ret, trace->errno_summary);
 
        if (!trace->fd_path_disabled && sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
                trace__set_fd_pathname(thread, ret, ttrace->filename.name);
@@ -4073,6 +4100,16 @@ static size_t thread__dump_stats(struct thread_trace *ttrace,
                        printed += fprintf(fp, " %8" PRIu64 " %6" PRIu64 " %9.3f %9.3f %9.3f",
                                           n, stats->nr_failures, syscall_stats_entry->msecs, min, avg);
                        printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
+
+                       if (trace->errno_summary && stats->nr_failures) {
+                               const char *arch_name = perf_env__arch(trace->host->env);
+                               int e;
+
+                               for (e = 0; e < stats->max_errno; ++e) {
+                                       if (stats->errnos[e] != 0)
+                                               fprintf(fp, "\t\t\t\t%s: %d\n", arch_syscalls__strerrno(arch_name, e + 1), stats->errnos[e]);
+                               }
+                       }
                }
        }
 
@@ -4511,6 +4548,8 @@ int cmd_trace(int argc, const char **argv)
                    "Show only syscall summary with statistics"),
        OPT_BOOLEAN('S', "with-summary", &trace.summary,
                    "Show all syscalls and summary with statistics"),
+       OPT_BOOLEAN(0, "errno-summary", &trace.errno_summary,
+                   "Show errno stats per syscall, use with -s or -S"),
        OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
                     "Trace pagefaults", parse_pagefaults, "maj"),
        OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
@@ -4816,6 +4855,10 @@ int cmd_trace(int argc, const char **argv)
        if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
                return trace__record(&trace, argc-1, &argv[1]);
 
+       /* Using just --errno-summary will trigger --summary */
+       if (trace.errno_summary && !trace.summary && !trace.summary_only)
+               trace.summary_only = true;
+
        /* summary_only implies summary option, but don't overwrite summary if set */
        if (trace.summary_only)
                trace.summary = trace.summary_only;