perf: Remove the perf_patch
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 13 May 2016 16:44:40 +0000 (12:44 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 16 Jun 2016 15:48:36 +0000 (11:48 -0400)
We no longer need to patch Linux's perf.  We should be ABI compliant with
PERFILE2.  If not, it's a bug.

This also updates Documentation, at least where it is related to setup.
There's a lot more TODO here.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
Documentation/profiling.txt
tools/profile/perf/perf_patches/perf_patch.diff [deleted file]

index 91f6037..160a898 100644 (file)
@@ -1,78 +1,76 @@
 Akaros Profiling
 ===========================
-2015-07-15 Barret Rhoden (brho)
 
-Contents
----------------------------
-"Kprof"
+Contents:
 
-"Kprof"
----------------------------
-Akaros has a very basic sampling profiler, similar to oprofile.  The kernel
-generates traces, which you copy off the machine and process on Linux using
-Linux perf.
-First build the Akaros kernel:
+ (*) Perf
+     - Setup
+     - Example
+     - Somewhat Outdated Notes
 
-/ $ make && make xcc-headers-install && make apps-install
+ (*) Old Oprofile Notes
 
-To get started, make sure #K is mounted.  The basic ifconfig script will do
-this, as will:
 
-/ $ bind -a \#K /prof/
+===========================
+PERF
+===========================
+Akaros has limited support for perf_events.  perf is a tool which utilizes CPU
+performance counters for performance monitoring and troubleshooting.
 
-You control the profiler with the kpctl file.  The general style is to start
-the events that trigger a sample, such as a timer tick, then you start and stop
-the profiling.  The distinction between the two steps is that one actually
-fires the events (e.g. the timer IRQ), and the other enables *collection*
-of profiling info when those events occur.
-Aside from timer based sampling, the Akaros `perf` tool allows to sample by
-catching performance counter overflows.
-The profiler accepts a few configuration options.
-There is a queue size limit of 64MB by default, and it is used as circular
-buffer, so old data will be dropped.
-To change its value:
+Akaros has its own version of perf, similar in spirit to Linux's perf, that
+produces PERFILE2 ABI compliant perf.data files (if not, file a bug!).  The
+kernel generates traces, under the direction of perf.  You then copy the traces
+to a Linux host and process using Linux's perf.
 
-/ $ echo prof_qlimit SIZE_KB > /prof/kpctl
 
-This should be run before starting the profiler.
+SETUP
+--------------------
+To build Akaros's perf directly:
 
-It is possible to configure the timer period, which defaults to 1000us, though
-it is not suggested to move too far from the default:
+(linux)$ cd tools/profile/perf ; make ; cd -
 
-/ $ echo timer period 1000 > /prof/kpctl
+Or to build it along with all apps:
 
+(linux)$ make apps-install
 
-                    Timer Base Profiling
+You will also need suitable recent Linux perf for the reporting of the data
+(something that understands PERFILE2 format).  Unpatched Linux 4.5 perf did the
+trick.  You'll also want libelf and maybe other libraries.
 
-The timer command takes the core id (or "all"), followed by "on" or "off".
-As with all good devices, if you echo garbage, in, you should get the usage as
-an errstr.  That'll be kept up to date more than documentation.
+First, install libelf according to your distro.  On ubuntu:
+(linux) $ sudo apt-get install libelf-dev
 
-For profiling, besides the counters overflow sampling handled by the `perf`
-utility, you need to enable timers:
+Then try to just install perf using your Linux distro, and install any needed
+dependencies.  On ubuntu, you can install linux-tools-common and whatever else
+it asks for (something particular to your host kernel).
 
-/ $ echo timer all on > /prof/kpctl
+If you get the following error when running perf record:
 
-And then start the Akaros profiler system-wide.
+       incompatible file format (rerun with -v to learn more)
 
-/ $ echo start > /prof/kpctl
+Then you'll need a newer version of perf.  Download Linux source, then
 
-Run whatever command you want the sampling to be based on, then stop timers
-and profiler:
+(linux) $ cd tools/perf/
+(linux) $ make
 
-/ $ my_test_program ...
-/ $ echo timer all off > /prof/kpctl
-/ $ echo stop > /prof/kpctl
+Then use your new perf binary.  This all is just installing a recent perf - it
+has little to do with Akaros at this point.  If you run into incompatibilities
+between our perf.data format and the latest Linux, file a bug.
 
-The trace will be then available in the /prof/kpdata file.
-The data will be available until the next start of the profiler.
 
+BASIC EXAMPLE
+--------------------
+You should be able to do the following:
 
-                    Akaros Perf Tool
+/ $ perf record -e 0x13c:0,int=1,icount=10000 -- /bin/hello
 
-The Akaros `perf` is a tool which allows to both programming and reading
-the CPU performance counters, and enabling counter overflow interrupt based
-tracing.
+Then scp perf.data to Linux
+
+(linux) $ perf report --kallsyms=obj/kern/ksyms.map --symfs=kern/kfs
+
+
+SOMEWHAT OUTDATED NOTES
+--------------------
 Its help screen reads like:
 
 Use: perf {list,cpucaps,record} [-mkecxh] -- CMD [ARGS ...]
@@ -158,45 +156,59 @@ When the command run by `perf` exits, the configured counter values are shown.
 If used as counter overflow interrupt sampling, the tracing data will be in
 the usual /prof/kpdata file.
 
+===========================
+OLD OPROFILE (probably broken)
+===========================
+
+To get started, make sure #K is mounted.  The basic ifconfig script will do
+this, as will:
+
+/ $ bind -a \#K /prof/
+
+You control the profiler with the kpctl file.  The general style is to start
+the events that trigger a sample, such as a timer tick, then you start and stop
+the profiling.  The distinction between the two steps is that one actually
+fires the events (e.g. the timer IRQ), and the other enables *collection*
+of profiling info when those events occur.
 
+Aside from timer based sampling, the Akaros `perf` tool allows to sample by
+catching performance counter overflows.
 
-                    Analyzing Profiler Data
+The profiler accepts a few configuration options.  There is a queue size limit
+of 64MB by default, and it is used as circular buffer, so old data will be
+dropped.
 
-The profiler tracing data generated in the /prof/kpdata file, needs to be copied
-on your dev box.
-The easiest way is via 9p:
+To change its value:
 
-/ $ cp /prof/kpdata /mnt/
+/ $ echo prof_qlimit SIZE_KB > /prof/kpctl
 
-Or by using the simple netcat (snc) utility.
-On your dev box:
+This should be run before starting the profiler.
 
-/ $ nc -l PORT > kpdata.data
+It is possible to configure the timer period, which defaults to 1000us, though
+it is not suggested to move too far from the default:
 
-On Akaros:
+/ $ echo timer period 1000 > /prof/kpctl
 
-/ $ scn -s DEVBOX_IP -p PORT -i /prof/kpdata
 
-In order to process the Akaros kprof file, you need to convert it to the
-Linux perf one.
-You can do that, on your dev box, with:
+The timer command takes the core id (or "all"), followed by "on" or "off".
+As with all good devices, if you echo garbage, in, you should get the usage as
+an errstr.  That'll be kept up to date more than documentation.
 
-/ $ ./tools/profile/kprof2perf/kprof2perf-linux -k `pwd`/obj/kern/akaros-kernel-64b -i kpdata.data -o perf.data
+For profiling, besides the counters overflow sampling handled by the `perf`
+utility, you need to enable timers:
 
-You then need to build the Akaros specific Linux perf binary.
-First you need to install (if you have not already) libelf-dev:
+/ $ echo timer all on > /prof/kpctl
 
-\ $ sudo apt-get install libelf-dev
+And then start the Akaros profiler system-wide.
 
-Then pull the Linux kernel source code which is closer to the kernel
-version you are running in your dev box, and patch it:
+/ $ echo start > /prof/kpctl
 
-/ $ cd linux
-/ $ patch -p 1 < $AKAROS/tools/profile/kprof2perf/perf_patches/perf_patch.diff
-/ $ cd tools/perf
-/ $ make
+Run whatever command you want the sampling to be based on, then stop timers
+and profiler:
 
-Then you should be able to run Linux perf data analysis command on it:
-Example:
+/ $ my_test_program ...
+/ $ echo stop > /prof/kpctl
+/ $ echo timer all off > /prof/kpctl
 
-$ /PATH_TO/perf --root-dir $AKAROS/kern/kfs/ report -g -i perf.data
+The trace will be then available in the /prof/kpdata file.
+The data will be available until the next start of the profiler.
diff --git a/tools/profile/perf/perf_patches/perf_patch.diff b/tools/profile/perf/perf_patches/perf_patch.diff
deleted file mode 100644 (file)
index 6d0d6da..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-diff --git a/tools/perf/perf.c b/tools/perf/perf.c
-index 85e1aed..ecf04c1 100644
---- a/tools/perf/perf.c
-+++ b/tools/perf/perf.c
-@@ -15,9 +15,14 @@
- #include "util/parse-events.h"
- #include <lk/debugfs.h>
- #include <pthread.h>
-+#include <fcntl.h>
-+#include <stdio.h>
-+#include <errno.h>
-+#include <string.h>
-+#include <unistd.h>
- const char perf_usage_string[] =
--      "perf [--version] [--help] COMMAND [ARGS]";
-+      "perf [--version] [--help] [--root-dir DIR] COMMAND [ARGS]";
- const char perf_more_info_string[] =
-       "See 'perf help COMMAND' for more information on a specific command.";
-@@ -25,6 +30,7 @@ const char perf_more_info_string[] =
- int use_browser = -1;
- static int use_pager = -1;
- const char *input_name;
-+static const char *perf_root_dir;
- struct cmd_struct {
-       const char *cmd;
-@@ -76,6 +82,28 @@ static int pager_command_config(const char *var, const char *value, void *data)
-       return 0;
- }
-+const char *perf_resolve_binary(const char *path, char *rpath, size_t max_size)
-+{
-+      snprintf(rpath, max_size, "%s/%s", perf_root_dir, path);
-+
-+      return access(rpath, F_OK) == 0 ? rpath: path;
-+}
-+
-+int perf_open_binary(const char *path, int flags, int mode)
-+{
-+      if (perf_root_dir) {
-+              int fd;
-+              char rpath[4096];
-+
-+              snprintf(rpath, sizeof(rpath), "%s/%s", perf_root_dir, path);
-+              fd = open(rpath, flags, mode);
-+              if (fd >= 0)
-+                      return fd;
-+      }
-+
-+      return open(path, flags, mode);
-+}
-+
- /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
- int check_pager_config(const char *cmd)
- {
-@@ -199,6 +227,14 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
-                               *envchanged = 1;
-                       (*argv)++;
-                       (*argc)--;
-+              } else if (!strcmp(cmd, "--root-dir")) {
-+                      if (*argc < 2) {
-+                              fprintf(stderr, "No directory given for --root-dir.\n");
-+                              usage(perf_usage_string);
-+                      }
-+                      perf_root_dir = (*argv)[1];
-+                      (*argv)++;
-+                      (*argc)--;
-               } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
-                       perf_debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
-                       fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
-diff --git a/tools/perf/perf.h b/tools/perf/perf.h
-index 32bd102..36c34f3 100644
---- a/tools/perf/perf.h
-+++ b/tools/perf/perf.h
-@@ -198,6 +198,8 @@ extern bool perf_host, perf_guest;
- extern const char perf_version_string[];
- void pthread__unblock_sigwinch(void);
-+const char *perf_resolve_binary(const char *path, char *rpath, size_t max_size);
-+int perf_open_binary(const char *path, int flags, int mode);
- #include "util/target.h"
-diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
-index d102716..65260ba 100644
---- a/tools/perf/util/annotate.c
-+++ b/tools/perf/util/annotate.c
-@@ -15,6 +15,7 @@
- #include "debug.h"
- #include "annotate.h"
- #include "evsel.h"
-+#include "perf.h"
- #include <pthread.h>
- #include <linux/bitops.h>
-@@ -831,10 +832,12 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
-       struct dso *dso = map->dso;
-       char *filename = dso__build_id_filename(dso, NULL, 0);
-       bool free_filename = true;
-+      const char *dso_name;
-       char command[PATH_MAX * 2];
-       FILE *file;
-       int err = 0;
-       char symfs_filename[PATH_MAX];
-+      char dso_namebuf[PATH_MAX];
-       if (filename) {
-               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-@@ -864,6 +867,11 @@ fallback:
-               free_filename = false;
-       }
-+      dso_name = perf_resolve_binary(filename, dso_namebuf, sizeof(dso_namebuf));
-+      if (dso_name == dso_namebuf)
-+              snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-+                       symbol_conf.symfs, dso_name);
-+
-       if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) {
-               char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
-               char *build_id_msg = NULL;
-@@ -889,7 +897,7 @@ fallback:
-       }
-       pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
--               filename, sym->name, map->unmap_ip(map, sym->start),
-+               dso_name, sym->name, map->unmap_ip(map, sym->start),
-                map->unmap_ip(map, sym->end));
-       pr_debug("annotating [%p] %30s : [%p] %30s\n",
-@@ -899,14 +907,14 @@ fallback:
-                "%s %s%s --start-address=0x%016" PRIx64
-                " --stop-address=0x%016" PRIx64
-                " -d %s %s -C %s|grep -v %s|expand",
--               objdump_path ? objdump_path : "objdump",
-+               objdump_path ? objdump_path : "x86_64-ucb-akaros-objdump",
-                disassembler_style ? "-M " : "",
-                disassembler_style ? disassembler_style : "",
-                map__rip_2objdump(map, sym->start),
-                map__rip_2objdump(map, sym->end+1),
-                symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
-                symbol_conf.annotate_src ? "-S" : "",
--               symfs_filename, filename);
-+               symfs_filename, dso_name);
-       pr_debug("Executing: %s\n", command);
-diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
-index 4b12bf8..211972b 100644
---- a/tools/perf/util/symbol-elf.c
-+++ b/tools/perf/util/symbol-elf.c
-@@ -7,6 +7,7 @@
- #include "symbol.h"
- #include "debug.h"
-+#include "perf.h"
- #ifndef NT_GNU_BUILD_ID
- #define NT_GNU_BUILD_ID 3
-@@ -550,7 +551,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
-       Elf *elf;
-       int fd;
--      fd = open(name, O_RDONLY);
-+      fd = perf_open_binary(name, O_RDONLY, 0);
-       if (fd < 0)
-               return -1;
-@@ -624,6 +625,11 @@ out_close:
-       return err;
- }
-+static int dso__is_kernel_mmap(struct map *map)
-+{
-+      return map->start >= 0xffffffffc0000000;
-+}
-+
- int dso__load_sym(struct dso *dso, struct map *map,
-                 struct symsrc *syms_ss, struct symsrc *runtime_ss,
-                 symbol_filter_t filter, int kmodule)
-@@ -633,6 +639,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
-       struct dso *curr_dso = dso;
-       Elf_Data *symstrs, *secstrs;
-       uint32_t nr_syms;
-+      int is_kernel_map = dso__is_kernel_mmap(map);
-       int err = -1;
-       uint32_t idx;
-       GElf_Ehdr ehdr;
-@@ -793,8 +800,9 @@ int dso__load_sym(struct dso *dso, struct map *map,
-                       goto new_symbol;
-               }
--              if ((used_opd && runtime_ss->adjust_symbols)
--                              || (!used_opd && syms_ss->adjust_symbols)) {
-+              if (!is_kernel_map &&
-+                  ((used_opd && runtime_ss->adjust_symbols)
-+                   || (!used_opd && syms_ss->adjust_symbols))) {
-                       pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " "
-                                 "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__,
-                                 (u64)sym.st_value, (u64)shdr.sh_addr,