perf trace: Improve messages related to /proc/sys/kernel/perf_event_paranoid
authorArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 17 Oct 2013 20:38:29 +0000 (17:38 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 17 Oct 2013 20:38:29 +0000 (17:38 -0300)
kernel/events/core.c has:

  /*
   * perf event paranoia level:
   *  -1 - not paranoid at all
   *   0 - disallow raw tracepoint access for unpriv
   *   1 - disallow cpu events for unpriv
   *   2 - disallow kernel profiling for unpriv
   */
  int sysctl_perf_event_paranoid __read_mostly = 1;

So, with the default being 1, a non-root user can trace his stuff:

  [acme@zoo ~]$ cat /proc/sys/kernel/perf_event_paranoid
  1
  [acme@zoo ~]$ yes > /dev/null &
  [1] 15338
  [acme@zoo ~]$ trace -p 15338 | head -5
       0.005 ( 0.005 ms): write(fd: 1</dev/null>, buf: 0x7fe6db765000, count: 4096 ) = 4096
       0.045 ( 0.001 ms): write(fd: 1</dev/null>, buf: 0x7fe6db765000, count: 4096 ) = 4096
       0.085 ( 0.001 ms): write(fd: 1</dev/null>, buf: 0x7fe6db765000, count: 4096 ) = 4096
       0.125 ( 0.001 ms): write(fd: 1</dev/null>, buf: 0x7fe6db765000, count: 4096 ) = 4096
       0.165 ( 0.001 ms): write(fd: 1</dev/null>, buf: 0x7fe6db765000, count: 4096 ) = 4096
  [acme@zoo ~]$
  [acme@zoo ~]$ trace --duration 1 sleep 1
    1002.148 (1001.218 ms): nanosleep(rqtp: 0x7fff46c79250                           ) = 0
  [acme@zoo ~]$
  [acme@zoo ~]$ trace -- usleep 1 | tail -5
       0.905 ( 0.002 ms): brk(                                                     ) = 0x1c82000
       0.910 ( 0.003 ms): brk(brk: 0x1ca3000                                       ) = 0x1ca3000
       0.913 ( 0.001 ms): brk(                                                     ) = 0x1ca3000
       0.990 ( 0.059 ms): nanosleep(rqtp: 0x7fffe31a3280                           ) = 0
       0.995 ( 0.000 ms): exit_group(
  [acme@zoo ~]$

But can't do system wide tracing:

  [acme@zoo ~]$ trace
  Error: Operation not permitted.
  Hint: Check /proc/sys/kernel/perf_event_paranoid setting.
  Hint: For system wide tracing it needs to be set to -1.
  Hint: The current value is 1.
  [acme@zoo ~]$

  [acme@zoo ~]$ trace --cpu 0
  Error: Operation not permitted.
  Hint: Check /proc/sys/kernel/perf_event_paranoid setting.
  Hint: For system wide tracing it needs to be set to -1.
  Hint: The current value is 1.
  [acme@zoo ~]$

If the paranoid level is >= 2, i.e. turn this perf stuff off for !root users:

  [acme@zoo ~]$ sudo sh -c 'echo 2 > /proc/sys/kernel/perf_event_paranoid'
  [acme@zoo ~]$ cat /proc/sys/kernel/perf_event_paranoid
  2
  [acme@zoo ~]$
  [acme@zoo ~]$ trace usleep 1
  Error: Permission denied.
  Hint: Check /proc/sys/kernel/perf_event_paranoid setting.
  Hint: For your workloads it needs to be <= 1
  Hint: For system wide tracing it needs to be set to -1.
  Hint: The current value is 2.
  [acme@zoo ~]$
  [acme@zoo ~]$ trace
  Error: Permission denied.
  Hint: Check /proc/sys/kernel/perf_event_paranoid setting.
  Hint: For your workloads it needs to be <= 1
  Hint: For system wide tracing it needs to be set to -1.
  Hint: The current value is 2.
  [acme@zoo ~]$
  [acme@zoo ~]$ trace --cpu 1
  Error: Permission denied.
  Hint: Check /proc/sys/kernel/perf_event_paranoid setting.
  Hint: For your workloads it needs to be <= 1
  Hint: For system wide tracing it needs to be set to -1.
  Hint: The current value is 2.
  [acme@zoo ~]$

If the user manages to get what he/she wants, convincing root not
to be paranoid at all...

  [root@zoo ~]# echo -1 > /proc/sys/kernel/perf_event_paranoid
  [root@zoo ~]# cat /proc/sys/kernel/perf_event_paranoid
  -1
  [root@zoo ~]#

  [acme@zoo ~]$ ps -eo user,pid,comm | grep Xorg
  root       729 Xorg
  [acme@zoo ~]$
  [acme@zoo ~]$ trace -a --duration 0.001 -e \!select,ioctl,writev | grep Xorg  | head -5
      23.143 ( 0.003 ms): Xorg/729 setitimer(which: REAL, value: 0x7fffaadf16e0 ) = 0
      23.152 ( 0.004 ms): Xorg/729 read(fd: 31, buf: 0x2544af0, count: 4096     ) = 8
      23.161 ( 0.002 ms): Xorg/729 read(fd: 31, buf: 0x2544af0, count: 4096     ) = -1 EAGAIN Resource temporarily unavailable
      23.175 ( 0.002 ms): Xorg/729 setitimer(which: REAL, value: 0x7fffaadf16e0 ) = 0
      23.235 ( 0.002 ms): Xorg/729 setitimer(which: REAL, value: 0x7fffaadf16e0 ) = 0
  [acme@zoo ~]$

Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-di28olfwd28rvkox7v3hqhu1@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-trace.c
tools/perf/util/evlist.c
tools/perf/util/evlist.h

index 78b0d6a5fdff2a51fdb6f4436406464669bd4fae..db959ac3d46ede9ad1e5e18600f5a7f1abc91de4 100644 (file)
@@ -1713,10 +1713,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
        }
 
        err = perf_evlist__open(evlist);
-       if (err < 0) {
-               fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
-               goto out_delete_maps;
-       }
+       if (err < 0)
+               goto out_error_open;
 
        err = perf_evlist__mmap(evlist, UINT_MAX, false);
        if (err < 0) {
@@ -1813,14 +1811,21 @@ out_delete_evlist:
 out:
        trace->live = false;
        return err;
-out_error_tp:
 {
        char errbuf[BUFSIZ];
+
+out_error_tp:
        perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
+       goto out_error;
+
+out_error_open:
+       perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
+
+out_error:
        fprintf(trace->output, "%s\n", errbuf);
-}
        goto out_delete_evlist;
 }
+}
 
 static int trace__replay(struct trace *trace)
 {
index 6737420891cd00ac7a9e04c23a34be2e29aa04d5..0b5425b4d8d64619266137df2c9a2be49b208c91 100644 (file)
@@ -1153,3 +1153,39 @@ int perf_evlist__strerror_tp(struct perf_evlist *evlist __maybe_unused,
 
        return 0;
 }
+
+int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
+                              int err, char *buf, size_t size)
+{
+       int printed, value;
+       char sbuf[128], *emsg = strerror_r(err, sbuf, sizeof(sbuf));
+
+       switch (err) {
+       case EACCES:
+       case EPERM:
+               printed = scnprintf(buf, size,
+                                   "Error:\t%s.\n"
+                                   "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg);
+
+               if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value))
+                       break;
+
+               printed += scnprintf(buf + printed, size - printed, "\nHint:\t");
+
+               if (value >= 2) {
+                       printed += scnprintf(buf + printed, size - printed,
+                                            "For your workloads it needs to be <= 1\nHint:\t");
+               }
+               printed += scnprintf(buf + printed, size - printed,
+                                    "For system wide tracing it needs to be set to -1");
+
+               printed += scnprintf(buf + printed, size - printed,
+                                   ".\nHint:\tThe current value is %d.", value);
+               break;
+       default:
+               scnprintf(buf, size, "%s", emsg);
+               break;
+       }
+
+       return 0;
+}
index 386de1036442669056f9ddd056b7f90ceab45fa0..7f8f1aeb9cfe66a03985c0977688be636990cf3b 100644 (file)
@@ -169,6 +169,7 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
 size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
 
 int perf_evlist__strerror_tp(struct perf_evlist *evlist, int err, char *buf, size_t size);
+int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size);
 
 static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
 {