| .. SPDX-License-Identifier: CC-BY-SA-2.0-UK | 
 | .. highlight:: shell | 
 |  | 
 | *************************************************************** | 
 | Basic Usage (with examples) for each of the Yocto Tracing Tools | 
 | *************************************************************** | 
 |  | 
 | | | 
 |  | 
 | This chapter presents basic usage examples for each of the tracing | 
 | tools. | 
 |  | 
 | perf | 
 | ==== | 
 |  | 
 | The 'perf' tool is the profiling and tracing tool that comes bundled | 
 | with the Linux kernel. | 
 |  | 
 | Don't let the fact that it's part of the kernel fool you into thinking | 
 | that it's only for tracing and profiling the kernel --- you can indeed use | 
 | it to trace and profile just the kernel, but you can also use it to | 
 | profile specific applications separately (with or without kernel | 
 | context), and you can also use it to trace and profile the kernel and | 
 | all applications on the system simultaneously to gain a system-wide view | 
 | of what's going on. | 
 |  | 
 | In many ways, perf aims to be a superset of all the tracing and | 
 | profiling tools available in Linux today, including all the other tools | 
 | covered in this HOWTO. The past couple of years have seen perf subsume a | 
 | lot of the functionality of those other tools and, at the same time, | 
 | those other tools have removed large portions of their previous | 
 | functionality and replaced it with calls to the equivalent functionality | 
 | now implemented by the perf subsystem. Extrapolation suggests that at | 
 | some point those other tools will simply become completely redundant and | 
 | go away; until then, we'll cover those other tools in these pages and in | 
 | many cases show how the same things can be accomplished in perf and the | 
 | other tools when it seems useful to do so. | 
 |  | 
 | The coverage below details some of the most common ways you'll likely | 
 | want to apply the tool; full documentation can be found either within | 
 | the tool itself or in the man pages at | 
 | `perf(1) <https://linux.die.net/man/1/perf>`__. | 
 |  | 
 | Perf Setup | 
 | ---------- | 
 |  | 
 | For this section, we'll assume you've already performed the basic setup | 
 | outlined in the ":ref:`profile-manual/intro:General Setup`" section. | 
 |  | 
 | In particular, you'll get the most mileage out of perf if you profile an | 
 | image built with the following in your ``local.conf`` file:: | 
 |  | 
 |    INHIBIT_PACKAGE_STRIP = "1" | 
 |  | 
 | perf runs on the target system for the most part. You can archive | 
 | profile data and copy it to the host for analysis, but for the rest of | 
 | this document we assume you've ssh'ed to the host and will be running | 
 | the perf commands on the target. | 
 |  | 
 | Basic Perf Usage | 
 | ---------------- | 
 |  | 
 | The perf tool is pretty much self-documenting. To remind yourself of the | 
 | available commands, simply type 'perf', which will show you basic usage | 
 | along with the available perf subcommands:: | 
 |  | 
 |    root@crownbay:~# perf | 
 |  | 
 |    usage: perf [--version] [--help] COMMAND [ARGS] | 
 |  | 
 |    The most commonly used perf commands are: | 
 |      annotate        Read perf.data (created by perf record) and display annotated code | 
 |      archive         Create archive with object files with build-ids found in perf.data file | 
 |      bench           General framework for benchmark suites | 
 |      buildid-cache   Manage build-id cache. | 
 |      buildid-list    List the buildids in a perf.data file | 
 |      diff            Read two perf.data files and display the differential profile | 
 |      evlist          List the event names in a perf.data file | 
 |      inject          Filter to augment the events stream with additional information | 
 |      kmem            Tool to trace/measure kernel memory(slab) properties | 
 |      kvm             Tool to trace/measure kvm guest os | 
 |      list            List all symbolic event types | 
 |      lock            Analyze lock events | 
 |      probe           Define new dynamic tracepoints | 
 |      record          Run a command and record its profile into perf.data | 
 |      report          Read perf.data (created by perf record) and display the profile | 
 |      sched           Tool to trace/measure scheduler properties (latencies) | 
 |      script          Read perf.data (created by perf record) and display trace output | 
 |      stat            Run a command and gather performance counter statistics | 
 |      test            Runs sanity tests. | 
 |      timechart       Tool to visualize total system behavior during a workload | 
 |      top             System profiling tool. | 
 |  | 
 |    See 'perf help COMMAND' for more information on a specific command. | 
 |  | 
 |  | 
 | Using perf to do Basic Profiling | 
 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
 |  | 
 | As a simple test case, we'll profile the 'wget' of a fairly large file, | 
 | which is a minimally interesting case because it has both file and | 
 | network I/O aspects, and at least in the case of standard Yocto images, | 
 | it's implemented as part of BusyBox, so the methods we use to analyze it | 
 | can be used in a very similar way to the whole host of supported BusyBox | 
 | applets in Yocto. :: | 
 |  | 
 |    root@crownbay:~# rm linux-2.6.19.2.tar.bz2; \ | 
 |                     wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2 | 
 |  | 
 | The quickest and easiest way to get some basic overall data about what's | 
 | going on for a particular workload is to profile it using 'perf stat'. | 
 | 'perf stat' basically profiles using a few default counters and displays | 
 | the summed counts at the end of the run:: | 
 |  | 
 |    root@crownbay:~# perf stat wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2 | 
 |    Connecting to downloads.yoctoproject.org (140.211.169.59:80) | 
 |    linux-2.6.19.2.tar.b 100% |***************************************************| 41727k  0:00:00 ETA | 
 |  | 
 |    Performance counter stats for 'wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2': | 
 |  | 
 |          4597.223902 task-clock                #    0.077 CPUs utilized | 
 |                23568 context-switches          #    0.005 M/sec | 
 |                   68 CPU-migrations            #    0.015 K/sec | 
 |                  241 page-faults               #    0.052 K/sec | 
 |           3045817293 cycles                    #    0.663 GHz | 
 |      <not supported> stalled-cycles-frontend | 
 |      <not supported> stalled-cycles-backend | 
 |            858909167 instructions              #    0.28  insns per cycle | 
 |            165441165 branches                  #   35.987 M/sec | 
 |             19550329 branch-misses             #   11.82% of all branches | 
 |  | 
 |         59.836627620 seconds time elapsed | 
 |  | 
 | Many times such a simple-minded test doesn't yield much of | 
 | interest, but sometimes it does (see Real-world Yocto bug (slow | 
 | loop-mounted write speed)). | 
 |  | 
 | Also, note that 'perf stat' isn't restricted to a fixed set of counters | 
 | - basically any event listed in the output of 'perf list' can be tallied | 
 | by 'perf stat'. For example, suppose we wanted to see a summary of all | 
 | the events related to kernel memory allocation/freeing along with cache | 
 | hits and misses:: | 
 |  | 
 |    root@crownbay:~# perf stat -e kmem:* -e cache-references -e cache-misses wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2 | 
 |    Connecting to downloads.yoctoproject.org (140.211.169.59:80) | 
 |    linux-2.6.19.2.tar.b 100% |***************************************************| 41727k  0:00:00 ETA | 
 |  | 
 |    Performance counter stats for 'wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2': | 
 |  | 
 |                 5566 kmem:kmalloc | 
 |               125517 kmem:kmem_cache_alloc | 
 |                    0 kmem:kmalloc_node | 
 |                    0 kmem:kmem_cache_alloc_node | 
 |                34401 kmem:kfree | 
 |                69920 kmem:kmem_cache_free | 
 |                  133 kmem:mm_page_free | 
 |                   41 kmem:mm_page_free_batched | 
 |                11502 kmem:mm_page_alloc | 
 |                11375 kmem:mm_page_alloc_zone_locked | 
 |                    0 kmem:mm_page_pcpu_drain | 
 |                    0 kmem:mm_page_alloc_extfrag | 
 |             66848602 cache-references | 
 |              2917740 cache-misses              #    4.365 % of all cache refs | 
 |  | 
 |         44.831023415 seconds time elapsed | 
 |  | 
 | So 'perf stat' gives us a nice easy | 
 | way to get a quick overview of what might be happening for a set of | 
 | events, but normally we'd need a little more detail in order to | 
 | understand what's going on in a way that we can act on in a useful way. | 
 |  | 
 | To dive down into a next level of detail, we can use 'perf record'/'perf | 
 | report' which will collect profiling data and present it to use using an | 
 | interactive text-based UI (or simply as text if we specify ``--stdio`` to | 
 | 'perf report'). | 
 |  | 
 | As our first attempt at profiling this workload, we'll simply run 'perf | 
 | record', handing it the workload we want to profile (everything after | 
 | 'perf record' and any perf options we hand it --- here none, will be | 
 | executed in a new shell). perf collects samples until the process exits | 
 | and records them in a file named 'perf.data' in the current working | 
 | directory. :: | 
 |  | 
 |    root@crownbay:~# perf record wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2 | 
 |  | 
 |    Connecting to downloads.yoctoproject.org (140.211.169.59:80) | 
 |    linux-2.6.19.2.tar.b 100% |************************************************| 41727k  0:00:00 ETA | 
 |    [ perf record: Woken up 1 times to write data ] | 
 |    [ perf record: Captured and wrote 0.176 MB perf.data (~7700 samples) ] | 
 |  | 
 | To see the results in a | 
 | 'text-based UI' (tui), simply run 'perf report', which will read the | 
 | perf.data file in the current working directory and display the results | 
 | in an interactive UI:: | 
 |  | 
 |    root@crownbay:~# perf report | 
 |  | 
 | .. image:: figures/perf-wget-flat-stripped.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | The above screenshot displays a 'flat' profile, one entry for each | 
 | 'bucket' corresponding to the functions that were profiled during the | 
 | profiling run, ordered from the most popular to the least (perf has | 
 | options to sort in various orders and keys as well as display entries | 
 | only above a certain threshold and so on --- see the perf documentation | 
 | for details). Note that this includes both userspace functions (entries | 
 | containing a [.]) and kernel functions accounted to the process (entries | 
 | containing a [k]). (perf has command-line modifiers that can be used to | 
 | restrict the profiling to kernel or userspace, among others). | 
 |  | 
 | Notice also that the above report shows an entry for 'busybox', which is | 
 | the executable that implements 'wget' in Yocto, but that instead of a | 
 | useful function name in that entry, it displays a not-so-friendly hex | 
 | value instead. The steps below will show how to fix that problem. | 
 |  | 
 | Before we do that, however, let's try running a different profile, one | 
 | which shows something a little more interesting. The only difference | 
 | between the new profile and the previous one is that we'll add the -g | 
 | option, which will record not just the address of a sampled function, | 
 | but the entire callchain to the sampled function as well:: | 
 |  | 
 |    root@crownbay:~# perf record -g wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2 | 
 |    Connecting to downloads.yoctoproject.org (140.211.169.59:80) | 
 |    linux-2.6.19.2.tar.b 100% |************************************************| 41727k  0:00:00 ETA | 
 |    [ perf record: Woken up 3 times to write data ] | 
 |    [ perf record: Captured and wrote 0.652 MB perf.data (~28476 samples) ] | 
 |  | 
 |  | 
 |    root@crownbay:~# perf report | 
 |  | 
 | .. image:: figures/perf-wget-g-copy-to-user-expanded-stripped.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | Using the callgraph view, we can actually see not only which functions | 
 | took the most time, but we can also see a summary of how those functions | 
 | were called and learn something about how the program interacts with the | 
 | kernel in the process. | 
 |  | 
 | Notice that each entry in the above screenshot now contains a '+' on the | 
 | left-hand side. This means that we can expand the entry and drill down | 
 | into the callchains that feed into that entry. Pressing 'enter' on any | 
 | one of them will expand the callchain (you can also press 'E' to expand | 
 | them all at the same time or 'C' to collapse them all). | 
 |  | 
 | In the screenshot above, we've toggled the ``__copy_to_user_ll()`` entry | 
 | and several subnodes all the way down. This lets us see which callchains | 
 | contributed to the profiled ``__copy_to_user_ll()`` function which | 
 | contributed 1.77% to the total profile. | 
 |  | 
 | As a bit of background explanation for these callchains, think about | 
 | what happens at a high level when you run wget to get a file out on the | 
 | network. Basically what happens is that the data comes into the kernel | 
 | via the network connection (socket) and is passed to the userspace | 
 | program 'wget' (which is actually a part of BusyBox, but that's not | 
 | important for now), which takes the buffers the kernel passes to it and | 
 | writes it to a disk file to save it. | 
 |  | 
 | The part of this process that we're looking at in the above call stacks | 
 | is the part where the kernel passes the data it has read from the socket | 
 | down to wget i.e. a copy-to-user. | 
 |  | 
 | Notice also that here there's also a case where the hex value is | 
 | displayed in the callstack, here in the expanded ``sys_clock_gettime()`` | 
 | function. Later we'll see it resolve to a userspace function call in | 
 | busybox. | 
 |  | 
 | .. image:: figures/perf-wget-g-copy-from-user-expanded-stripped.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | The above screenshot shows the other half of the journey for the data - | 
 | from the wget program's userspace buffers to disk. To get the buffers to | 
 | disk, the wget program issues a ``write(2)``, which does a ``copy-from-user`` to | 
 | the kernel, which then takes care via some circuitous path (probably | 
 | also present somewhere in the profile data), to get it safely to disk. | 
 |  | 
 | Now that we've seen the basic layout of the profile data and the basics | 
 | of how to extract useful information out of it, let's get back to the | 
 | task at hand and see if we can get some basic idea about where the time | 
 | is spent in the program we're profiling, wget. Remember that wget is | 
 | actually implemented as an applet in BusyBox, so while the process name | 
 | is 'wget', the executable we're actually interested in is BusyBox. So | 
 | let's expand the first entry containing BusyBox: | 
 |  | 
 | .. image:: figures/perf-wget-busybox-expanded-stripped.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | Again, before we expanded we saw that the function was labeled with a | 
 | hex value instead of a symbol as with most of the kernel entries. | 
 | Expanding the BusyBox entry doesn't make it any better. | 
 |  | 
 | The problem is that perf can't find the symbol information for the | 
 | busybox binary, which is actually stripped out by the Yocto build | 
 | system. | 
 |  | 
 | One way around that is to put the following in your ``local.conf`` file | 
 | when you build the image:: | 
 |  | 
 |    INHIBIT_PACKAGE_STRIP = "1" | 
 |  | 
 | However, we already have an image with the binaries stripped, so | 
 | what can we do to get perf to resolve the symbols? Basically we need to | 
 | install the debuginfo for the BusyBox package. | 
 |  | 
 | To generate the debug info for the packages in the image, we can add | 
 | ``dbg-pkgs`` to :term:`EXTRA_IMAGE_FEATURES` in ``local.conf``. For example:: | 
 |  | 
 |    EXTRA_IMAGE_FEATURES = "debug-tweaks tools-profile dbg-pkgs" | 
 |  | 
 | Additionally, in order to generate the type of debuginfo that perf | 
 | understands, we also need to set | 
 | :term:`PACKAGE_DEBUG_SPLIT_STYLE` | 
 | in the ``local.conf`` file:: | 
 |  | 
 |    PACKAGE_DEBUG_SPLIT_STYLE = 'debug-file-directory' | 
 |  | 
 | Once we've done that, we can install the | 
 | debuginfo for BusyBox. The debug packages once built can be found in | 
 | ``build/tmp/deploy/rpm/*`` on the host system. Find the busybox-dbg-...rpm | 
 | file and copy it to the target. For example:: | 
 |  | 
 |    [trz@empanada core2]$ scp /home/trz/yocto/crownbay-tracing-dbg/build/tmp/deploy/rpm/core2_32/busybox-dbg-1.20.2-r2.core2_32.rpm root@192.168.1.31: | 
 |    busybox-dbg-1.20.2-r2.core2_32.rpm                     100% 1826KB   1.8MB/s   00:01 | 
 |  | 
 | Now install the debug rpm on the target:: | 
 |  | 
 |    root@crownbay:~# rpm -i busybox-dbg-1.20.2-r2.core2_32.rpm | 
 |  | 
 | Now that the debuginfo is installed, we see that the BusyBox entries now display | 
 | their functions symbolically: | 
 |  | 
 | .. image:: figures/perf-wget-busybox-debuginfo.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | If we expand one of the entries and press 'enter' on a leaf node, we're | 
 | presented with a menu of actions we can take to get more information | 
 | related to that entry: | 
 |  | 
 | .. image:: figures/perf-wget-busybox-dso-zoom-menu.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | One of these actions allows us to show a view that displays a | 
 | busybox-centric view of the profiled functions (in this case we've also | 
 | expanded all the nodes using the 'E' key): | 
 |  | 
 | .. image:: figures/perf-wget-busybox-dso-zoom.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | Finally, we can see that now that the BusyBox debuginfo is installed, | 
 | the previously unresolved symbol in the ``sys_clock_gettime()`` entry | 
 | mentioned previously is now resolved, and shows that the | 
 | sys_clock_gettime system call that was the source of 6.75% of the | 
 | copy-to-user overhead was initiated by the ``handle_input()`` BusyBox | 
 | function: | 
 |  | 
 | .. image:: figures/perf-wget-g-copy-to-user-expanded-debuginfo.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | At the lowest level of detail, we can dive down to the assembly level | 
 | and see which instructions caused the most overhead in a function. | 
 | Pressing 'enter' on the 'udhcpc_main' function, we're again presented | 
 | with a menu: | 
 |  | 
 | .. image:: figures/perf-wget-busybox-annotate-menu.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | Selecting 'Annotate udhcpc_main', we get a detailed listing of | 
 | percentages by instruction for the udhcpc_main function. From the | 
 | display, we can see that over 50% of the time spent in this function is | 
 | taken up by a couple tests and the move of a constant (1) to a register: | 
 |  | 
 | .. image:: figures/perf-wget-busybox-annotate-udhcpc.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | As a segue into tracing, let's try another profile using a different | 
 | counter, something other than the default 'cycles'. | 
 |  | 
 | The tracing and profiling infrastructure in Linux has become unified in | 
 | a way that allows us to use the same tool with a completely different | 
 | set of counters, not just the standard hardware counters that | 
 | traditional tools have had to restrict themselves to (of course the | 
 | traditional tools can also make use of the expanded possibilities now | 
 | available to them, and in some cases have, as mentioned previously). | 
 |  | 
 | We can get a list of the available events that can be used to profile a | 
 | workload via 'perf list':: | 
 |  | 
 |    root@crownbay:~# perf list | 
 |  | 
 |    List of pre-defined events (to be used in -e): | 
 |     cpu-cycles OR cycles                               [Hardware event] | 
 |     stalled-cycles-frontend OR idle-cycles-frontend    [Hardware event] | 
 |     stalled-cycles-backend OR idle-cycles-backend      [Hardware event] | 
 |     instructions                                       [Hardware event] | 
 |     cache-references                                   [Hardware event] | 
 |     cache-misses                                       [Hardware event] | 
 |     branch-instructions OR branches                    [Hardware event] | 
 |     branch-misses                                      [Hardware event] | 
 |     bus-cycles                                         [Hardware event] | 
 |     ref-cycles                                         [Hardware event] | 
 |  | 
 |     cpu-clock                                          [Software event] | 
 |     task-clock                                         [Software event] | 
 |     page-faults OR faults                              [Software event] | 
 |     minor-faults                                       [Software event] | 
 |     major-faults                                       [Software event] | 
 |     context-switches OR cs                             [Software event] | 
 |     cpu-migrations OR migrations                       [Software event] | 
 |     alignment-faults                                   [Software event] | 
 |     emulation-faults                                   [Software event] | 
 |  | 
 |     L1-dcache-loads                                    [Hardware cache event] | 
 |     L1-dcache-load-misses                              [Hardware cache event] | 
 |     L1-dcache-prefetch-misses                          [Hardware cache event] | 
 |     L1-icache-loads                                    [Hardware cache event] | 
 |     L1-icache-load-misses                              [Hardware cache event] | 
 |     . | 
 |     . | 
 |     . | 
 |     rNNN                                               [Raw hardware event descriptor] | 
 |     cpu/t1=v1[,t2=v2,t3 ...]/modifier                  [Raw hardware event descriptor] | 
 |      (see 'perf list --help' on how to encode it) | 
 |  | 
 |     mem:<addr>[:access]                                [Hardware breakpoint] | 
 |  | 
 |     sunrpc:rpc_call_status                             [Tracepoint event] | 
 |     sunrpc:rpc_bind_status                             [Tracepoint event] | 
 |     sunrpc:rpc_connect_status                          [Tracepoint event] | 
 |     sunrpc:rpc_task_begin                              [Tracepoint event] | 
 |     skb:kfree_skb                                      [Tracepoint event] | 
 |     skb:consume_skb                                    [Tracepoint event] | 
 |     skb:skb_copy_datagram_iovec                        [Tracepoint event] | 
 |     net:net_dev_xmit                                   [Tracepoint event] | 
 |     net:net_dev_queue                                  [Tracepoint event] | 
 |     net:netif_receive_skb                              [Tracepoint event] | 
 |     net:netif_rx                                       [Tracepoint event] | 
 |     napi:napi_poll                                     [Tracepoint event] | 
 |     sock:sock_rcvqueue_full                            [Tracepoint event] | 
 |     sock:sock_exceed_buf_limit                         [Tracepoint event] | 
 |     udp:udp_fail_queue_rcv_skb                         [Tracepoint event] | 
 |     hda:hda_send_cmd                                   [Tracepoint event] | 
 |     hda:hda_get_response                               [Tracepoint event] | 
 |     hda:hda_bus_reset                                  [Tracepoint event] | 
 |     scsi:scsi_dispatch_cmd_start                       [Tracepoint event] | 
 |     scsi:scsi_dispatch_cmd_error                       [Tracepoint event] | 
 |     scsi:scsi_eh_wakeup                                [Tracepoint event] | 
 |     drm:drm_vblank_event                               [Tracepoint event] | 
 |     drm:drm_vblank_event_queued                        [Tracepoint event] | 
 |     drm:drm_vblank_event_delivered                     [Tracepoint event] | 
 |     random:mix_pool_bytes                              [Tracepoint event] | 
 |     random:mix_pool_bytes_nolock                       [Tracepoint event] | 
 |     random:credit_entropy_bits                         [Tracepoint event] | 
 |     gpio:gpio_direction                                [Tracepoint event] | 
 |     gpio:gpio_value                                    [Tracepoint event] | 
 |     block:block_rq_abort                               [Tracepoint event] | 
 |     block:block_rq_requeue                             [Tracepoint event] | 
 |     block:block_rq_issue                               [Tracepoint event] | 
 |     block:block_bio_bounce                             [Tracepoint event] | 
 |     block:block_bio_complete                           [Tracepoint event] | 
 |     block:block_bio_backmerge                          [Tracepoint event] | 
 |     . | 
 |     . | 
 |     writeback:writeback_wake_thread                    [Tracepoint event] | 
 |     writeback:writeback_wake_forker_thread             [Tracepoint event] | 
 |     writeback:writeback_bdi_register                   [Tracepoint event] | 
 |     . | 
 |     . | 
 |     writeback:writeback_single_inode_requeue           [Tracepoint event] | 
 |     writeback:writeback_single_inode                   [Tracepoint event] | 
 |     kmem:kmalloc                                       [Tracepoint event] | 
 |     kmem:kmem_cache_alloc                              [Tracepoint event] | 
 |     kmem:mm_page_alloc                                 [Tracepoint event] | 
 |     kmem:mm_page_alloc_zone_locked                     [Tracepoint event] | 
 |     kmem:mm_page_pcpu_drain                            [Tracepoint event] | 
 |     kmem:mm_page_alloc_extfrag                         [Tracepoint event] | 
 |     vmscan:mm_vmscan_kswapd_sleep                      [Tracepoint event] | 
 |     vmscan:mm_vmscan_kswapd_wake                       [Tracepoint event] | 
 |     vmscan:mm_vmscan_wakeup_kswapd                     [Tracepoint event] | 
 |     vmscan:mm_vmscan_direct_reclaim_begin              [Tracepoint event] | 
 |     . | 
 |     . | 
 |     module:module_get                                  [Tracepoint event] | 
 |     module:module_put                                  [Tracepoint event] | 
 |     module:module_request                              [Tracepoint event] | 
 |     sched:sched_kthread_stop                           [Tracepoint event] | 
 |     sched:sched_wakeup                                 [Tracepoint event] | 
 |     sched:sched_wakeup_new                             [Tracepoint event] | 
 |     sched:sched_process_fork                           [Tracepoint event] | 
 |     sched:sched_process_exec                           [Tracepoint event] | 
 |     sched:sched_stat_runtime                           [Tracepoint event] | 
 |     rcu:rcu_utilization                                [Tracepoint event] | 
 |     workqueue:workqueue_queue_work                     [Tracepoint event] | 
 |     workqueue:workqueue_execute_end                    [Tracepoint event] | 
 |     signal:signal_generate                             [Tracepoint event] | 
 |     signal:signal_deliver                              [Tracepoint event] | 
 |     timer:timer_init                                   [Tracepoint event] | 
 |     timer:timer_start                                  [Tracepoint event] | 
 |     timer:hrtimer_cancel                               [Tracepoint event] | 
 |     timer:itimer_state                                 [Tracepoint event] | 
 |     timer:itimer_expire                                [Tracepoint event] | 
 |     irq:irq_handler_entry                              [Tracepoint event] | 
 |     irq:irq_handler_exit                               [Tracepoint event] | 
 |     irq:softirq_entry                                  [Tracepoint event] | 
 |     irq:softirq_exit                                   [Tracepoint event] | 
 |     irq:softirq_raise                                  [Tracepoint event] | 
 |     printk:console                                     [Tracepoint event] | 
 |     task:task_newtask                                  [Tracepoint event] | 
 |     task:task_rename                                   [Tracepoint event] | 
 |     syscalls:sys_enter_socketcall                      [Tracepoint event] | 
 |     syscalls:sys_exit_socketcall                       [Tracepoint event] | 
 |     . | 
 |     . | 
 |     . | 
 |     syscalls:sys_enter_unshare                         [Tracepoint event] | 
 |     syscalls:sys_exit_unshare                          [Tracepoint event] | 
 |     raw_syscalls:sys_enter                             [Tracepoint event] | 
 |     raw_syscalls:sys_exit                              [Tracepoint event] | 
 |  | 
 | .. admonition:: Tying it Together | 
 |  | 
 |    These are exactly the same set of events defined by the trace event | 
 |    subsystem and exposed by ftrace/tracecmd/kernelshark as files in | 
 |    /sys/kernel/debug/tracing/events, by SystemTap as | 
 |    kernel.trace("tracepoint_name") and (partially) accessed by LTTng. | 
 |  | 
 | Only a subset of these would be of interest to us when looking at this | 
 | workload, so let's choose the most likely subsystems (identified by the | 
 | string before the colon in the Tracepoint events) and do a 'perf stat' | 
 | run using only those wildcarded subsystems:: | 
 |  | 
 |    root@crownbay:~# perf stat -e skb:* -e net:* -e napi:* -e sched:* -e workqueue:* -e irq:* -e syscalls:* wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2 | 
 |    Performance counter stats for 'wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2': | 
 |  | 
 |                23323 skb:kfree_skb | 
 |                    0 skb:consume_skb | 
 |                49897 skb:skb_copy_datagram_iovec | 
 |                 6217 net:net_dev_xmit | 
 |                 6217 net:net_dev_queue | 
 |                 7962 net:netif_receive_skb | 
 |                    2 net:netif_rx | 
 |                 8340 napi:napi_poll | 
 |                    0 sched:sched_kthread_stop | 
 |                    0 sched:sched_kthread_stop_ret | 
 |                 3749 sched:sched_wakeup | 
 |                    0 sched:sched_wakeup_new | 
 |                    0 sched:sched_switch | 
 |                   29 sched:sched_migrate_task | 
 |                    0 sched:sched_process_free | 
 |                    1 sched:sched_process_exit | 
 |                    0 sched:sched_wait_task | 
 |                    0 sched:sched_process_wait | 
 |                    0 sched:sched_process_fork | 
 |                    1 sched:sched_process_exec | 
 |                    0 sched:sched_stat_wait | 
 |        2106519415641 sched:sched_stat_sleep | 
 |                    0 sched:sched_stat_iowait | 
 |            147453613 sched:sched_stat_blocked | 
 |          12903026955 sched:sched_stat_runtime | 
 |                    0 sched:sched_pi_setprio | 
 |                 3574 workqueue:workqueue_queue_work | 
 |                 3574 workqueue:workqueue_activate_work | 
 |                    0 workqueue:workqueue_execute_start | 
 |                    0 workqueue:workqueue_execute_end | 
 |                16631 irq:irq_handler_entry | 
 |                16631 irq:irq_handler_exit | 
 |                28521 irq:softirq_entry | 
 |                28521 irq:softirq_exit | 
 |                28728 irq:softirq_raise | 
 |                    1 syscalls:sys_enter_sendmmsg | 
 |                    1 syscalls:sys_exit_sendmmsg | 
 |                    0 syscalls:sys_enter_recvmmsg | 
 |                    0 syscalls:sys_exit_recvmmsg | 
 |                   14 syscalls:sys_enter_socketcall | 
 |                   14 syscalls:sys_exit_socketcall | 
 |                      . | 
 |                      . | 
 |                      . | 
 |                16965 syscalls:sys_enter_read | 
 |                16965 syscalls:sys_exit_read | 
 |                12854 syscalls:sys_enter_write | 
 |                12854 syscalls:sys_exit_write | 
 |                      . | 
 |                      . | 
 |                      . | 
 |  | 
 |         58.029710972 seconds time elapsed | 
 |  | 
 |  | 
 |  | 
 | Let's pick one of these tracepoints | 
 | and tell perf to do a profile using it as the sampling event:: | 
 |  | 
 |    root@crownbay:~# perf record -g -e sched:sched_wakeup wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2 | 
 |  | 
 | .. image:: figures/sched-wakeup-profile.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | The screenshot above shows the results of running a profile using | 
 | sched:sched_switch tracepoint, which shows the relative costs of various | 
 | paths to sched_wakeup (note that sched_wakeup is the name of the | 
 | tracepoint --- it's actually defined just inside ttwu_do_wakeup(), which | 
 | accounts for the function name actually displayed in the profile: | 
 |  | 
 | .. code-block:: c | 
 |  | 
 |      /* | 
 |       * Mark the task runnable and perform wakeup-preemption. | 
 |       */ | 
 |      static void | 
 |      ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags) | 
 |      { | 
 |           trace_sched_wakeup(p, true); | 
 |           . | 
 |           . | 
 |           . | 
 |      } | 
 |  | 
 | A couple of the more interesting | 
 | callchains are expanded and displayed above, basically some network | 
 | receive paths that presumably end up waking up wget (busybox) when | 
 | network data is ready. | 
 |  | 
 | Note that because tracepoints are normally used for tracing, the default | 
 | sampling period for tracepoints is 1 i.e. for tracepoints perf will | 
 | sample on every event occurrence (this can be changed using the -c | 
 | option). This is in contrast to hardware counters such as for example | 
 | the default 'cycles' hardware counter used for normal profiling, where | 
 | sampling periods are much higher (in the thousands) because profiling | 
 | should have as low an overhead as possible and sampling on every cycle | 
 | would be prohibitively expensive. | 
 |  | 
 | Using perf to do Basic Tracing | 
 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
 |  | 
 | Profiling is a great tool for solving many problems or for getting a | 
 | high-level view of what's going on with a workload or across the system. | 
 | It is however by definition an approximation, as suggested by the most | 
 | prominent word associated with it, 'sampling'. On the one hand, it | 
 | allows a representative picture of what's going on in the system to be | 
 | cheaply taken, but on the other hand, that cheapness limits its utility | 
 | when that data suggests a need to 'dive down' more deeply to discover | 
 | what's really going on. In such cases, the only way to see what's really | 
 | going on is to be able to look at (or summarize more intelligently) the | 
 | individual steps that go into the higher-level behavior exposed by the | 
 | coarse-grained profiling data. | 
 |  | 
 | As a concrete example, we can trace all the events we think might be | 
 | applicable to our workload:: | 
 |  | 
 |    root@crownbay:~# perf record -g -e skb:* -e net:* -e napi:* -e sched:sched_switch -e sched:sched_wakeup -e irq:* | 
 |     -e syscalls:sys_enter_read -e syscalls:sys_exit_read -e syscalls:sys_enter_write -e syscalls:sys_exit_write | 
 |     wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2 | 
 |  | 
 | We can look at the raw trace output using 'perf script' with no | 
 | arguments:: | 
 |  | 
 |    root@crownbay:~# perf script | 
 |  | 
 |          perf  1262 [000] 11624.857082: sys_exit_read: 0x0 | 
 |          perf  1262 [000] 11624.857193: sched_wakeup: comm=migration/0 pid=6 prio=0 success=1 target_cpu=000 | 
 |          wget  1262 [001] 11624.858021: softirq_raise: vec=1 [action=TIMER] | 
 |          wget  1262 [001] 11624.858074: softirq_entry: vec=1 [action=TIMER] | 
 |          wget  1262 [001] 11624.858081: softirq_exit: vec=1 [action=TIMER] | 
 |          wget  1262 [001] 11624.858166: sys_enter_read: fd: 0x0003, buf: 0xbf82c940, count: 0x0200 | 
 |          wget  1262 [001] 11624.858177: sys_exit_read: 0x200 | 
 |          wget  1262 [001] 11624.858878: kfree_skb: skbaddr=0xeb248d80 protocol=0 location=0xc15a5308 | 
 |          wget  1262 [001] 11624.858945: kfree_skb: skbaddr=0xeb248000 protocol=0 location=0xc15a5308 | 
 |          wget  1262 [001] 11624.859020: softirq_raise: vec=1 [action=TIMER] | 
 |          wget  1262 [001] 11624.859076: softirq_entry: vec=1 [action=TIMER] | 
 |          wget  1262 [001] 11624.859083: softirq_exit: vec=1 [action=TIMER] | 
 |          wget  1262 [001] 11624.859167: sys_enter_read: fd: 0x0003, buf: 0xb7720000, count: 0x0400 | 
 |          wget  1262 [001] 11624.859192: sys_exit_read: 0x1d7 | 
 |          wget  1262 [001] 11624.859228: sys_enter_read: fd: 0x0003, buf: 0xb7720000, count: 0x0400 | 
 |          wget  1262 [001] 11624.859233: sys_exit_read: 0x0 | 
 |          wget  1262 [001] 11624.859573: sys_enter_read: fd: 0x0003, buf: 0xbf82c580, count: 0x0200 | 
 |          wget  1262 [001] 11624.859584: sys_exit_read: 0x200 | 
 |          wget  1262 [001] 11624.859864: sys_enter_read: fd: 0x0003, buf: 0xb7720000, count: 0x0400 | 
 |          wget  1262 [001] 11624.859888: sys_exit_read: 0x400 | 
 |          wget  1262 [001] 11624.859935: sys_enter_read: fd: 0x0003, buf: 0xb7720000, count: 0x0400 | 
 |          wget  1262 [001] 11624.859944: sys_exit_read: 0x400 | 
 |  | 
 | This gives us a detailed timestamped sequence of events that occurred within the | 
 | workload with respect to those events. | 
 |  | 
 | In many ways, profiling can be viewed as a subset of tracing - | 
 | theoretically, if you have a set of trace events that's sufficient to | 
 | capture all the important aspects of a workload, you can derive any of | 
 | the results or views that a profiling run can. | 
 |  | 
 | Another aspect of traditional profiling is that while powerful in many | 
 | ways, it's limited by the granularity of the underlying data. Profiling | 
 | tools offer various ways of sorting and presenting the sample data, | 
 | which make it much more useful and amenable to user experimentation, but | 
 | in the end it can't be used in an open-ended way to extract data that | 
 | just isn't present as a consequence of the fact that conceptually, most | 
 | of it has been thrown away. | 
 |  | 
 | Full-blown detailed tracing data does however offer the opportunity to | 
 | manipulate and present the information collected during a tracing run in | 
 | an infinite variety of ways. | 
 |  | 
 | Another way to look at it is that there are only so many ways that the | 
 | 'primitive' counters can be used on their own to generate interesting | 
 | output; to get anything more complicated than simple counts requires | 
 | some amount of additional logic, which is typically very specific to the | 
 | problem at hand. For example, if we wanted to make use of a 'counter' | 
 | that maps to the value of the time difference between when a process was | 
 | scheduled to run on a processor and the time it actually ran, we | 
 | wouldn't expect such a counter to exist on its own, but we could derive | 
 | one called say 'wakeup_latency' and use it to extract a useful view of | 
 | that metric from trace data. Likewise, we really can't figure out from | 
 | standard profiling tools how much data every process on the system reads | 
 | and writes, along with how many of those reads and writes fail | 
 | completely. If we have sufficient trace data, however, we could with the | 
 | right tools easily extract and present that information, but we'd need | 
 | something other than pre-canned profiling tools to do that. | 
 |  | 
 | Luckily, there is a general-purpose way to handle such needs, called | 
 | 'programming languages'. Making programming languages easily available | 
 | to apply to such problems given the specific format of data is called a | 
 | 'programming language binding' for that data and language. Perf supports | 
 | two programming language bindings, one for Python and one for Perl. | 
 |  | 
 | .. admonition:: Tying it Together | 
 |  | 
 |    Language bindings for manipulating and aggregating trace data are of | 
 |    course not a new idea. One of the first projects to do this was IBM's | 
 |    DProbes dpcc compiler, an ANSI C compiler which targeted a low-level | 
 |    assembly language running on an in-kernel interpreter on the target | 
 |    system. This is exactly analogous to what Sun's DTrace did, except | 
 |    that DTrace invented its own language for the purpose. Systemtap, | 
 |    heavily inspired by DTrace, also created its own one-off language, | 
 |    but rather than running the product on an in-kernel interpreter, | 
 |    created an elaborate compiler-based machinery to translate its | 
 |    language into kernel modules written in C. | 
 |  | 
 | Now that we have the trace data in perf.data, we can use 'perf script | 
 | -g' to generate a skeleton script with handlers for the read/write | 
 | entry/exit events we recorded:: | 
 |  | 
 |    root@crownbay:~# perf script -g python | 
 |    generated Python script: perf-script.py | 
 |  | 
 | The skeleton script simply creates a Python function for each event type in the | 
 | perf.data file. The body of each function simply prints the event name along | 
 | with its parameters. For example: | 
 |  | 
 | .. code-block:: python | 
 |  | 
 |    def net__netif_rx(event_name, context, common_cpu, | 
 |           common_secs, common_nsecs, common_pid, common_comm, | 
 |           skbaddr, len, name): | 
 |                   print_header(event_name, common_cpu, common_secs, common_nsecs, | 
 |                           common_pid, common_comm) | 
 |  | 
 |                   print "skbaddr=%u, len=%u, name=%s\n" % (skbaddr, len, name), | 
 |  | 
 | We can run that script directly to print all of the events contained in the | 
 | perf.data file:: | 
 |  | 
 |    root@crownbay:~# perf script -s perf-script.py | 
 |  | 
 |    in trace_begin | 
 |    syscalls__sys_exit_read     0 11624.857082795     1262 perf                  nr=3, ret=0 | 
 |    sched__sched_wakeup      0 11624.857193498     1262 perf                  comm=migration/0, pid=6, prio=0,      success=1, target_cpu=0 | 
 |    irq__softirq_raise       1 11624.858021635     1262 wget                  vec=TIMER | 
 |    irq__softirq_entry       1 11624.858074075     1262 wget                  vec=TIMER | 
 |    irq__softirq_exit        1 11624.858081389     1262 wget                  vec=TIMER | 
 |    syscalls__sys_enter_read     1 11624.858166434     1262 wget                  nr=3, fd=3, buf=3213019456,      count=512 | 
 |    syscalls__sys_exit_read     1 11624.858177924     1262 wget                  nr=3, ret=512 | 
 |    skb__kfree_skb           1 11624.858878188     1262 wget                  skbaddr=3945041280,           location=3243922184, protocol=0 | 
 |    skb__kfree_skb           1 11624.858945608     1262 wget                  skbaddr=3945037824,      location=3243922184, protocol=0 | 
 |    irq__softirq_raise       1 11624.859020942     1262 wget                  vec=TIMER | 
 |    irq__softirq_entry       1 11624.859076935     1262 wget                  vec=TIMER | 
 |    irq__softirq_exit        1 11624.859083469     1262 wget                  vec=TIMER | 
 |    syscalls__sys_enter_read     1 11624.859167565     1262 wget                  nr=3, fd=3, buf=3077701632,      count=1024 | 
 |    syscalls__sys_exit_read     1 11624.859192533     1262 wget                  nr=3, ret=471 | 
 |    syscalls__sys_enter_read     1 11624.859228072     1262 wget                  nr=3, fd=3, buf=3077701632,      count=1024 | 
 |    syscalls__sys_exit_read     1 11624.859233707     1262 wget                  nr=3, ret=0 | 
 |    syscalls__sys_enter_read     1 11624.859573008     1262 wget                  nr=3, fd=3, buf=3213018496,      count=512 | 
 |    syscalls__sys_exit_read     1 11624.859584818     1262 wget                  nr=3, ret=512 | 
 |    syscalls__sys_enter_read     1 11624.859864562     1262 wget                  nr=3, fd=3, buf=3077701632,      count=1024 | 
 |    syscalls__sys_exit_read     1 11624.859888770     1262 wget                  nr=3, ret=1024 | 
 |    syscalls__sys_enter_read     1 11624.859935140     1262 wget                  nr=3, fd=3, buf=3077701632,      count=1024 | 
 |    syscalls__sys_exit_read     1 11624.859944032     1262 wget                  nr=3, ret=1024 | 
 |  | 
 | That in itself isn't very useful; after all, we can accomplish pretty much the | 
 | same thing by simply running 'perf script' without arguments in the same | 
 | directory as the perf.data file. | 
 |  | 
 | We can however replace the print statements in the generated function | 
 | bodies with whatever we want, and thereby make it infinitely more | 
 | useful. | 
 |  | 
 | As a simple example, let's just replace the print statements in the | 
 | function bodies with a simple function that does nothing but increment a | 
 | per-event count. When the program is run against a perf.data file, each | 
 | time a particular event is encountered, a tally is incremented for that | 
 | event. For example: | 
 |  | 
 | .. code-block:: python | 
 |  | 
 |    def net__netif_rx(event_name, context, common_cpu, | 
 |           common_secs, common_nsecs, common_pid, common_comm, | 
 |           skbaddr, len, name): | 
 |               inc_counts(event_name) | 
 |  | 
 | Each event handler function in the generated code | 
 | is modified to do this. For convenience, we define a common function | 
 | called inc_counts() that each handler calls; inc_counts() simply tallies | 
 | a count for each event using the 'counts' hash, which is a specialized | 
 | hash function that does Perl-like autovivification, a capability that's | 
 | extremely useful for kinds of multi-level aggregation commonly used in | 
 | processing traces (see perf's documentation on the Python language | 
 | binding for details): | 
 |  | 
 | .. code-block:: python | 
 |  | 
 |      counts = autodict() | 
 |  | 
 |      def inc_counts(event_name): | 
 |             try: | 
 |                     counts[event_name] += 1 | 
 |             except TypeError: | 
 |                     counts[event_name] = 1 | 
 |  | 
 | Finally, at the end of the trace processing run, we want to print the | 
 | result of all the per-event tallies. For that, we use the special | 
 | 'trace_end()' function: | 
 |  | 
 | .. code-block:: python | 
 |  | 
 |      def trace_end(): | 
 |             for event_name, count in counts.iteritems(): | 
 |                     print "%-40s %10s\n" % (event_name, count) | 
 |  | 
 | The end result is a summary of all the events recorded in the trace:: | 
 |  | 
 |    skb__skb_copy_datagram_iovec                  13148 | 
 |    irq__softirq_entry                             4796 | 
 |    irq__irq_handler_exit                          3805 | 
 |    irq__softirq_exit                              4795 | 
 |    syscalls__sys_enter_write                      8990 | 
 |    net__net_dev_xmit                               652 | 
 |    skb__kfree_skb                                 4047 | 
 |    sched__sched_wakeup                            1155 | 
 |    irq__irq_handler_entry                         3804 | 
 |    irq__softirq_raise                             4799 | 
 |    net__net_dev_queue                              652 | 
 |    syscalls__sys_enter_read                      17599 | 
 |    net__netif_receive_skb                         1743 | 
 |    syscalls__sys_exit_read                       17598 | 
 |    net__netif_rx                                     2 | 
 |    napi__napi_poll                                1877 | 
 |    syscalls__sys_exit_write                       8990 | 
 |  | 
 | Note that this is | 
 | pretty much exactly the same information we get from 'perf stat', which | 
 | goes a little way to support the idea mentioned previously that given | 
 | the right kind of trace data, higher-level profiling-type summaries can | 
 | be derived from it. | 
 |  | 
 | Documentation on using the `'perf script' Python | 
 | binding <https://linux.die.net/man/1/perf-script-python>`__. | 
 |  | 
 | System-Wide Tracing and Profiling | 
 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
 |  | 
 | The examples so far have focused on tracing a particular program or | 
 | workload --- in other words, every profiling run has specified the program | 
 | to profile in the command-line e.g. 'perf record wget ...'. | 
 |  | 
 | It's also possible, and more interesting in many cases, to run a | 
 | system-wide profile or trace while running the workload in a separate | 
 | shell. | 
 |  | 
 | To do system-wide profiling or tracing, you typically use the -a flag to | 
 | 'perf record'. | 
 |  | 
 | To demonstrate this, open up one window and start the profile using the | 
 | -a flag (press Ctrl-C to stop tracing):: | 
 |  | 
 |    root@crownbay:~# perf record -g -a | 
 |    ^C[ perf record: Woken up 6 times to write data ] | 
 |    [ perf record: Captured and wrote 1.400 MB perf.data (~61172 samples) ] | 
 |  | 
 | In another window, run the wget test:: | 
 |  | 
 |    root@crownbay:~# wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2 | 
 |    Connecting to downloads.yoctoproject.org (140.211.169.59:80) | 
 |    linux-2.6.19.2.tar.b 100% \|*******************************\| 41727k 0:00:00 ETA | 
 |  | 
 | Here we see entries not only for our wget load, but for | 
 | other processes running on the system as well: | 
 |  | 
 | .. image:: figures/perf-systemwide.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | In the snapshot above, we can see callchains that originate in libc, and | 
 | a callchain from Xorg that demonstrates that we're using a proprietary X | 
 | driver in userspace (notice the presence of 'PVR' and some other | 
 | unresolvable symbols in the expanded Xorg callchain). | 
 |  | 
 | Note also that we have both kernel and userspace entries in the above | 
 | snapshot. We can also tell perf to focus on userspace but providing a | 
 | modifier, in this case 'u', to the 'cycles' hardware counter when we | 
 | record a profile:: | 
 |  | 
 |    root@crownbay:~# perf record -g -a -e cycles:u | 
 |    ^C[ perf record: Woken up 2 times to write data ] | 
 |    [ perf record: Captured and wrote 0.376 MB perf.data (~16443 samples) ] | 
 |  | 
 | .. image:: figures/perf-report-cycles-u.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | Notice in the screenshot above, we see only userspace entries ([.]) | 
 |  | 
 | Finally, we can press 'enter' on a leaf node and select the 'Zoom into | 
 | DSO' menu item to show only entries associated with a specific DSO. In | 
 | the screenshot below, we've zoomed into the 'libc' DSO which shows all | 
 | the entries associated with the libc-xxx.so DSO. | 
 |  | 
 | .. image:: figures/perf-systemwide-libc.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | We can also use the system-wide -a switch to do system-wide tracing. | 
 | Here we'll trace a couple of scheduler events:: | 
 |  | 
 |    root@crownbay:~# perf record -a -e sched:sched_switch -e sched:sched_wakeup | 
 |    ^C[ perf record: Woken up 38 times to write data ] | 
 |    [ perf record: Captured and wrote 9.780 MB perf.data (~427299 samples) ] | 
 |  | 
 | We can look at the raw output using 'perf script' with no arguments:: | 
 |  | 
 |    root@crownbay:~# perf script | 
 |  | 
 |               perf  1383 [001]  6171.460045: sched_wakeup: comm=kworker/1:1 pid=21 prio=120 success=1 target_cpu=001 | 
 |               perf  1383 [001]  6171.460066: sched_switch: prev_comm=perf prev_pid=1383 prev_prio=120 prev_state=R+ ==> next_comm=kworker/1:1 next_pid=21 next_prio=120 | 
 |        kworker/1:1    21 [001]  6171.460093: sched_switch: prev_comm=kworker/1:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=perf next_pid=1383 next_prio=120 | 
 |            swapper     0 [000]  6171.468063: sched_wakeup: comm=kworker/0:3 pid=1209 prio=120 success=1 target_cpu=000 | 
 |            swapper     0 [000]  6171.468107: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/0:3 next_pid=1209 next_prio=120 | 
 |        kworker/0:3  1209 [000]  6171.468143: sched_switch: prev_comm=kworker/0:3 prev_pid=1209 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120 | 
 |               perf  1383 [001]  6171.470039: sched_wakeup: comm=kworker/1:1 pid=21 prio=120 success=1 target_cpu=001 | 
 |               perf  1383 [001]  6171.470058: sched_switch: prev_comm=perf prev_pid=1383 prev_prio=120 prev_state=R+ ==> next_comm=kworker/1:1 next_pid=21 next_prio=120 | 
 |        kworker/1:1    21 [001]  6171.470082: sched_switch: prev_comm=kworker/1:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=perf next_pid=1383 next_prio=120 | 
 |               perf  1383 [001]  6171.480035: sched_wakeup: comm=kworker/1:1 pid=21 prio=120 success=1 target_cpu=001 | 
 |  | 
 | Filtering | 
 | ^^^^^^^^^ | 
 |  | 
 | Notice that there are a lot of events that don't really have anything to | 
 | do with what we're interested in, namely events that schedule 'perf' | 
 | itself in and out or that wake perf up. We can get rid of those by using | 
 | the '--filter' option --- for each event we specify using -e, we can add a | 
 | --filter after that to filter out trace events that contain fields with | 
 | specific values:: | 
 |  | 
 |    root@crownbay:~# perf record -a -e sched:sched_switch --filter 'next_comm != perf && prev_comm != perf' -e sched:sched_wakeup --filter 'comm != perf' | 
 |    ^C[ perf record: Woken up 38 times to write data ] | 
 |    [ perf record: Captured and wrote 9.688 MB perf.data (~423279 samples) ] | 
 |  | 
 |  | 
 |    root@crownbay:~# perf script | 
 |  | 
 |            swapper     0 [000]  7932.162180: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/0:3 next_pid=1209 next_prio=120 | 
 |        kworker/0:3  1209 [000]  7932.162236: sched_switch: prev_comm=kworker/0:3 prev_pid=1209 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120 | 
 |               perf  1407 [001]  7932.170048: sched_wakeup: comm=kworker/1:1 pid=21 prio=120 success=1 target_cpu=001 | 
 |               perf  1407 [001]  7932.180044: sched_wakeup: comm=kworker/1:1 pid=21 prio=120 success=1 target_cpu=001 | 
 |               perf  1407 [001]  7932.190038: sched_wakeup: comm=kworker/1:1 pid=21 prio=120 success=1 target_cpu=001 | 
 |               perf  1407 [001]  7932.200044: sched_wakeup: comm=kworker/1:1 pid=21 prio=120 success=1 target_cpu=001 | 
 |               perf  1407 [001]  7932.210044: sched_wakeup: comm=kworker/1:1 pid=21 prio=120 success=1 target_cpu=001 | 
 |               perf  1407 [001]  7932.220044: sched_wakeup: comm=kworker/1:1 pid=21 prio=120 success=1 target_cpu=001 | 
 |            swapper     0 [001]  7932.230111: sched_wakeup: comm=kworker/1:1 pid=21 prio=120 success=1 target_cpu=001 | 
 |            swapper     0 [001]  7932.230146: sched_switch: prev_comm=swapper/1 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/1:1 next_pid=21 next_prio=120 | 
 |        kworker/1:1    21 [001]  7932.230205: sched_switch: prev_comm=kworker/1:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=swapper/1 next_pid=0 next_prio=120 | 
 |            swapper     0 [000]  7932.326109: sched_wakeup: comm=kworker/0:3 pid=1209 prio=120 success=1 target_cpu=000 | 
 |            swapper     0 [000]  7932.326171: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/0:3 next_pid=1209 next_prio=120 | 
 |        kworker/0:3  1209 [000]  7932.326214: sched_switch: prev_comm=kworker/0:3 prev_pid=1209 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120 | 
 |  | 
 | In this case, we've filtered out all events that have | 
 | 'perf' in their 'comm' or 'comm_prev' or 'comm_next' fields. Notice that | 
 | there are still events recorded for perf, but notice that those events | 
 | don't have values of 'perf' for the filtered fields. To completely | 
 | filter out anything from perf will require a bit more work, but for the | 
 | purpose of demonstrating how to use filters, it's close enough. | 
 |  | 
 | .. admonition:: Tying it Together | 
 |  | 
 |    These are exactly the same set of event filters defined by the trace | 
 |    event subsystem. See the ftrace/tracecmd/kernelshark section for more | 
 |    discussion about these event filters. | 
 |  | 
 | .. admonition:: Tying it Together | 
 |  | 
 |    These event filters are implemented by a special-purpose | 
 |    pseudo-interpreter in the kernel and are an integral and | 
 |    indispensable part of the perf design as it relates to tracing. | 
 |    kernel-based event filters provide a mechanism to precisely throttle | 
 |    the event stream that appears in user space, where it makes sense to | 
 |    provide bindings to real programming languages for postprocessing the | 
 |    event stream. This architecture allows for the intelligent and | 
 |    flexible partitioning of processing between the kernel and user | 
 |    space. Contrast this with other tools such as SystemTap, which does | 
 |    all of its processing in the kernel and as such requires a special | 
 |    project-defined language in order to accommodate that design, or | 
 |    LTTng, where everything is sent to userspace and as such requires a | 
 |    super-efficient kernel-to-userspace transport mechanism in order to | 
 |    function properly. While perf certainly can benefit from for instance | 
 |    advances in the design of the transport, it doesn't fundamentally | 
 |    depend on them. Basically, if you find that your perf tracing | 
 |    application is causing buffer I/O overruns, it probably means that | 
 |    you aren't taking enough advantage of the kernel filtering engine. | 
 |  | 
 | Using Dynamic Tracepoints | 
 | ~~~~~~~~~~~~~~~~~~~~~~~~~ | 
 |  | 
 | perf isn't restricted to the fixed set of static tracepoints listed by | 
 | 'perf list'. Users can also add their own 'dynamic' tracepoints anywhere | 
 | in the kernel. For instance, suppose we want to define our own | 
 | tracepoint on do_fork(). We can do that using the 'perf probe' perf | 
 | subcommand:: | 
 |  | 
 |    root@crownbay:~# perf probe do_fork | 
 |    Added new event: | 
 |      probe:do_fork        (on do_fork) | 
 |  | 
 |    You can now use it in all perf tools, such as: | 
 |  | 
 |      perf record -e probe:do_fork -aR sleep 1 | 
 |  | 
 | Adding a new tracepoint via | 
 | 'perf probe' results in an event with all the expected files and format | 
 | in /sys/kernel/debug/tracing/events, just the same as for static | 
 | tracepoints (as discussed in more detail in the trace events subsystem | 
 | section:: | 
 |  | 
 |    root@crownbay:/sys/kernel/debug/tracing/events/probe/do_fork# ls -al | 
 |    drwxr-xr-x    2 root     root             0 Oct 28 11:42 . | 
 |    drwxr-xr-x    3 root     root             0 Oct 28 11:42 .. | 
 |    -rw-r--r--    1 root     root             0 Oct 28 11:42 enable | 
 |    -rw-r--r--    1 root     root             0 Oct 28 11:42 filter | 
 |    -r--r--r--    1 root     root             0 Oct 28 11:42 format | 
 |    -r--r--r--    1 root     root             0 Oct 28 11:42 id | 
 |  | 
 |    root@crownbay:/sys/kernel/debug/tracing/events/probe/do_fork# cat format | 
 |    name: do_fork | 
 |    ID: 944 | 
 |    format: | 
 |            field:unsigned short common_type;	offset:0;	size:2;	signed:0; | 
 |            field:unsigned char common_flags;	offset:2;	size:1;	signed:0; | 
 |            field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0; | 
 |            field:int common_pid;	offset:4;	size:4;	signed:1; | 
 |            field:int common_padding;	offset:8;	size:4;	signed:1; | 
 |  | 
 |            field:unsigned long __probe_ip;	offset:12;	size:4;	signed:0; | 
 |  | 
 |    print fmt: "(%lx)", REC->__probe_ip | 
 |  | 
 | We can list all dynamic tracepoints currently in | 
 | existence:: | 
 |  | 
 |    root@crownbay:~# perf probe -l | 
 |     probe:do_fork (on do_fork) | 
 |     probe:schedule (on schedule) | 
 |  | 
 | Let's record system-wide ('sleep 30' is a | 
 | trick for recording system-wide but basically do nothing and then wake | 
 | up after 30 seconds):: | 
 |  | 
 |    root@crownbay:~# perf record -g -a -e probe:do_fork sleep 30 | 
 |    [ perf record: Woken up 1 times to write data ] | 
 |    [ perf record: Captured and wrote 0.087 MB perf.data (~3812 samples) ] | 
 |  | 
 | Using 'perf script' we can see each do_fork event that fired:: | 
 |  | 
 |    root@crownbay:~# perf script | 
 |  | 
 |    # ======== | 
 |    # captured on: Sun Oct 28 11:55:18 2012 | 
 |    # hostname : crownbay | 
 |    # os release : 3.4.11-yocto-standard | 
 |    # perf version : 3.4.11 | 
 |    # arch : i686 | 
 |    # nrcpus online : 2 | 
 |    # nrcpus avail : 2 | 
 |    # cpudesc : Intel(R) Atom(TM) CPU E660 @ 1.30GHz | 
 |    # cpuid : GenuineIntel,6,38,1 | 
 |    # total memory : 1017184 kB | 
 |    # cmdline : /usr/bin/perf record -g -a -e probe:do_fork sleep 30 | 
 |    # event : name = probe:do_fork, type = 2, config = 0x3b0, config1 = 0x0, config2 = 0x0, excl_usr = 0, excl_kern | 
 |     = 0, id = { 5, 6 } | 
 |    # HEADER_CPU_TOPOLOGY info available, use -I to display | 
 |    # ======== | 
 |    # | 
 |     matchbox-deskto  1197 [001] 34211.378318: do_fork: (c1028460) | 
 |     matchbox-deskto  1295 [001] 34211.380388: do_fork: (c1028460) | 
 |             pcmanfm  1296 [000] 34211.632350: do_fork: (c1028460) | 
 |             pcmanfm  1296 [000] 34211.639917: do_fork: (c1028460) | 
 |     matchbox-deskto  1197 [001] 34217.541603: do_fork: (c1028460) | 
 |     matchbox-deskto  1299 [001] 34217.543584: do_fork: (c1028460) | 
 |              gthumb  1300 [001] 34217.697451: do_fork: (c1028460) | 
 |              gthumb  1300 [001] 34219.085734: do_fork: (c1028460) | 
 |              gthumb  1300 [000] 34219.121351: do_fork: (c1028460) | 
 |              gthumb  1300 [001] 34219.264551: do_fork: (c1028460) | 
 |             pcmanfm  1296 [000] 34219.590380: do_fork: (c1028460) | 
 |     matchbox-deskto  1197 [001] 34224.955965: do_fork: (c1028460) | 
 |     matchbox-deskto  1306 [001] 34224.957972: do_fork: (c1028460) | 
 |     matchbox-termin  1307 [000] 34225.038214: do_fork: (c1028460) | 
 |     matchbox-termin  1307 [001] 34225.044218: do_fork: (c1028460) | 
 |     matchbox-termin  1307 [000] 34225.046442: do_fork: (c1028460) | 
 |     matchbox-deskto  1197 [001] 34237.112138: do_fork: (c1028460) | 
 |     matchbox-deskto  1311 [001] 34237.114106: do_fork: (c1028460) | 
 |                gaku  1312 [000] 34237.202388: do_fork: (c1028460) | 
 |  | 
 | And using 'perf report' on the same file, we can see the | 
 | callgraphs from starting a few programs during those 30 seconds: | 
 |  | 
 | .. image:: figures/perf-probe-do_fork-profile.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | .. admonition:: Tying it Together | 
 |  | 
 |    The trace events subsystem accommodate static and dynamic tracepoints | 
 |    in exactly the same way --- there's no difference as far as the | 
 |    infrastructure is concerned. See the ftrace section for more details | 
 |    on the trace event subsystem. | 
 |  | 
 | .. admonition:: Tying it Together | 
 |  | 
 |    Dynamic tracepoints are implemented under the covers by kprobes and | 
 |    uprobes. kprobes and uprobes are also used by and in fact are the | 
 |    main focus of SystemTap. | 
 |  | 
 | Perf Documentation | 
 | ------------------ | 
 |  | 
 | Online versions of the man pages for the commands discussed in this | 
 | section can be found here: | 
 |  | 
 | -  The `'perf stat' manpage <https://linux.die.net/man/1/perf-stat>`__. | 
 |  | 
 | -  The `'perf record' | 
 |    manpage <https://linux.die.net/man/1/perf-record>`__. | 
 |  | 
 | -  The `'perf report' | 
 |    manpage <https://linux.die.net/man/1/perf-report>`__. | 
 |  | 
 | -  The `'perf probe' manpage <https://linux.die.net/man/1/perf-probe>`__. | 
 |  | 
 | -  The `'perf script' | 
 |    manpage <https://linux.die.net/man/1/perf-script>`__. | 
 |  | 
 | -  Documentation on using the `'perf script' Python | 
 |    binding <https://linux.die.net/man/1/perf-script-python>`__. | 
 |  | 
 | -  The top-level `perf(1) manpage <https://linux.die.net/man/1/perf>`__. | 
 |  | 
 | Normally, you should be able to invoke the man pages via perf itself | 
 | e.g. 'perf help' or 'perf help record'. | 
 |  | 
 | To have the perf manpages installed on your target, modify your | 
 | configuration as follows:: | 
 |  | 
 |    IMAGE_INSTALL:append = " perf perf-doc" | 
 |    DISTRO_FEATURES:append = " api-documentation" | 
 |  | 
 | The man pages in text form, along with some other files, such as a set | 
 | of examples, can also be found in the 'perf' directory of the kernel tree:: | 
 |  | 
 |    tools/perf/Documentation | 
 |  | 
 | There's also a nice perf tutorial on the perf | 
 | wiki that goes into more detail than we do here in certain areas: `Perf | 
 | Tutorial <https://perf.wiki.kernel.org/index.php/Tutorial>`__ | 
 |  | 
 | ftrace | 
 | ====== | 
 |  | 
 | 'ftrace' literally refers to the 'ftrace function tracer' but in reality | 
 | this encompasses a number of related tracers along with the | 
 | infrastructure that they all make use of. | 
 |  | 
 | ftrace Setup | 
 | ------------ | 
 |  | 
 | For this section, we'll assume you've already performed the basic setup | 
 | outlined in the ":ref:`profile-manual/intro:General Setup`" section. | 
 |  | 
 | ftrace, trace-cmd, and kernelshark run on the target system, and are | 
 | ready to go out-of-the-box --- no additional setup is necessary. For the | 
 | rest of this section we assume you've ssh'ed to the host and will be | 
 | running ftrace on the target. kernelshark is a GUI application and if | 
 | you use the '-X' option to ssh you can have the kernelshark GUI run on | 
 | the target but display remotely on the host if you want. | 
 |  | 
 | Basic ftrace usage | 
 | ------------------ | 
 |  | 
 | 'ftrace' essentially refers to everything included in the /tracing | 
 | directory of the mounted debugfs filesystem (Yocto follows the standard | 
 | convention and mounts it at /sys/kernel/debug). Here's a listing of all | 
 | the files found in /sys/kernel/debug/tracing on a Yocto system:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing# ls | 
 |    README                      kprobe_events               trace | 
 |    available_events            kprobe_profile              trace_clock | 
 |    available_filter_functions  options                     trace_marker | 
 |    available_tracers           per_cpu                     trace_options | 
 |    buffer_size_kb              printk_formats              trace_pipe | 
 |    buffer_total_size_kb        saved_cmdlines              tracing_cpumask | 
 |    current_tracer              set_event                   tracing_enabled | 
 |    dyn_ftrace_total_info       set_ftrace_filter           tracing_on | 
 |    enabled_functions           set_ftrace_notrace          tracing_thresh | 
 |    events                      set_ftrace_pid | 
 |    free_buffer                 set_graph_function | 
 |  | 
 | The files listed above are used for various purposes | 
 | - some relate directly to the tracers themselves, others are used to set | 
 | tracing options, and yet others actually contain the tracing output when | 
 | a tracer is in effect. Some of the functions can be guessed from their | 
 | names, others need explanation; in any case, we'll cover some of the | 
 | files we see here below but for an explanation of the others, please see | 
 | the ftrace documentation. | 
 |  | 
 | We'll start by looking at some of the available built-in tracers. | 
 |  | 
 | cat'ing the 'available_tracers' file lists the set of available tracers:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing# cat available_tracers | 
 |    blk function_graph function nop | 
 |  | 
 | The 'current_tracer' file contains the tracer currently in effect:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing# cat current_tracer | 
 |    nop | 
 |  | 
 | The above listing of current_tracer shows that the | 
 | 'nop' tracer is in effect, which is just another way of saying that | 
 | there's actually no tracer currently in effect. | 
 |  | 
 | echo'ing one of the available_tracers into current_tracer makes the | 
 | specified tracer the current tracer:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing# echo function > current_tracer | 
 |    root@sugarbay:/sys/kernel/debug/tracing# cat current_tracer | 
 |    function | 
 |  | 
 | The above sets the current tracer to be the 'function tracer'. This tracer | 
 | traces every function call in the kernel and makes it available as the | 
 | contents of the 'trace' file. Reading the 'trace' file lists the | 
 | currently buffered function calls that have been traced by the function | 
 | tracer:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing# cat trace | less | 
 |  | 
 |    # tracer: function | 
 |    # | 
 |    # entries-in-buffer/entries-written: 310629/766471   #P:8 | 
 |    # | 
 |    #                              _-----=> irqs-off | 
 |    #                             / _----=> need-resched | 
 |    #                            | / _---=> hardirq/softirq | 
 |    #                            || / _--=> preempt-depth | 
 |    #                            ||| /     delay | 
 |    #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION | 
 |    #              | |       |   ||||       |         | | 
 |             <idle>-0     [004] d..1   470.867169: ktime_get_real <-intel_idle | 
 |             <idle>-0     [004] d..1   470.867170: getnstimeofday <-ktime_get_real | 
 |             <idle>-0     [004] d..1   470.867171: ns_to_timeval <-intel_idle | 
 |             <idle>-0     [004] d..1   470.867171: ns_to_timespec <-ns_to_timeval | 
 |             <idle>-0     [004] d..1   470.867172: smp_apic_timer_interrupt <-apic_timer_interrupt | 
 |             <idle>-0     [004] d..1   470.867172: native_apic_mem_write <-smp_apic_timer_interrupt | 
 |             <idle>-0     [004] d..1   470.867172: irq_enter <-smp_apic_timer_interrupt | 
 |             <idle>-0     [004] d..1   470.867172: rcu_irq_enter <-irq_enter | 
 |             <idle>-0     [004] d..1   470.867173: rcu_idle_exit_common.isra.33 <-rcu_irq_enter | 
 |             <idle>-0     [004] d..1   470.867173: local_bh_disable <-irq_enter | 
 |             <idle>-0     [004] d..1   470.867173: add_preempt_count <-local_bh_disable | 
 |             <idle>-0     [004] d.s1   470.867174: tick_check_idle <-irq_enter | 
 |             <idle>-0     [004] d.s1   470.867174: tick_check_oneshot_broadcast <-tick_check_idle | 
 |             <idle>-0     [004] d.s1   470.867174: ktime_get <-tick_check_idle | 
 |             <idle>-0     [004] d.s1   470.867174: tick_nohz_stop_idle <-tick_check_idle | 
 |             <idle>-0     [004] d.s1   470.867175: update_ts_time_stats <-tick_nohz_stop_idle | 
 |             <idle>-0     [004] d.s1   470.867175: nr_iowait_cpu <-update_ts_time_stats | 
 |             <idle>-0     [004] d.s1   470.867175: tick_do_update_jiffies64 <-tick_check_idle | 
 |             <idle>-0     [004] d.s1   470.867175: _raw_spin_lock <-tick_do_update_jiffies64 | 
 |             <idle>-0     [004] d.s1   470.867176: add_preempt_count <-_raw_spin_lock | 
 |             <idle>-0     [004] d.s2   470.867176: do_timer <-tick_do_update_jiffies64 | 
 |             <idle>-0     [004] d.s2   470.867176: _raw_spin_lock <-do_timer | 
 |             <idle>-0     [004] d.s2   470.867176: add_preempt_count <-_raw_spin_lock | 
 |             <idle>-0     [004] d.s3   470.867177: ntp_tick_length <-do_timer | 
 |             <idle>-0     [004] d.s3   470.867177: _raw_spin_lock_irqsave <-ntp_tick_length | 
 |             . | 
 |             . | 
 |             . | 
 |  | 
 | Each line in the trace above shows what was happening in the kernel on a given | 
 | cpu, to the level of detail of function calls. Each entry shows the function | 
 | called, followed by its caller (after the arrow). | 
 |  | 
 | The function tracer gives you an extremely detailed idea of what the | 
 | kernel was doing at the point in time the trace was taken, and is a | 
 | great way to learn about how the kernel code works in a dynamic sense. | 
 |  | 
 | .. admonition:: Tying it Together | 
 |  | 
 |    The ftrace function tracer is also available from within perf, as the | 
 |    ftrace:function tracepoint. | 
 |  | 
 | It is a little more difficult to follow the call chains than it needs to | 
 | be --- luckily there's a variant of the function tracer that displays the | 
 | callchains explicitly, called the 'function_graph' tracer:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing# echo function_graph > current_tracer | 
 |    root@sugarbay:/sys/kernel/debug/tracing# cat trace | less | 
 |  | 
 |     tracer: function_graph | 
 |  | 
 |     CPU  DURATION                  FUNCTION CALLS | 
 |     |     |   |                     |   |   |   | | 
 |    7)   0.046 us    |      pick_next_task_fair(); | 
 |    7)   0.043 us    |      pick_next_task_stop(); | 
 |    7)   0.042 us    |      pick_next_task_rt(); | 
 |    7)   0.032 us    |      pick_next_task_fair(); | 
 |    7)   0.030 us    |      pick_next_task_idle(); | 
 |    7)               |      _raw_spin_unlock_irq() { | 
 |    7)   0.033 us    |        sub_preempt_count(); | 
 |    7)   0.258 us    |      } | 
 |    7)   0.032 us    |      sub_preempt_count(); | 
 |    7) + 13.341 us   |    } /* __schedule */ | 
 |    7)   0.095 us    |  } /* sub_preempt_count */ | 
 |    7)               |  schedule() { | 
 |    7)               |    __schedule() { | 
 |    7)   0.060 us    |      add_preempt_count(); | 
 |    7)   0.044 us    |      rcu_note_context_switch(); | 
 |    7)               |      _raw_spin_lock_irq() { | 
 |    7)   0.033 us    |        add_preempt_count(); | 
 |    7)   0.247 us    |      } | 
 |    7)               |      idle_balance() { | 
 |    7)               |        _raw_spin_unlock() { | 
 |    7)   0.031 us    |          sub_preempt_count(); | 
 |    7)   0.246 us    |        } | 
 |    7)               |        update_shares() { | 
 |    7)   0.030 us    |          __rcu_read_lock(); | 
 |    7)   0.029 us    |          __rcu_read_unlock(); | 
 |    7)   0.484 us    |        } | 
 |    7)   0.030 us    |        __rcu_read_lock(); | 
 |    7)               |        load_balance() { | 
 |    7)               |          find_busiest_group() { | 
 |    7)   0.031 us    |            idle_cpu(); | 
 |    7)   0.029 us    |            idle_cpu(); | 
 |    7)   0.035 us    |            idle_cpu(); | 
 |    7)   0.906 us    |          } | 
 |    7)   1.141 us    |        } | 
 |    7)   0.022 us    |        msecs_to_jiffies(); | 
 |    7)               |        load_balance() { | 
 |    7)               |          find_busiest_group() { | 
 |    7)   0.031 us    |            idle_cpu(); | 
 |    . | 
 |    . | 
 |    . | 
 |    4)   0.062 us    |        msecs_to_jiffies(); | 
 |    4)   0.062 us    |        __rcu_read_unlock(); | 
 |    4)               |        _raw_spin_lock() { | 
 |    4)   0.073 us    |          add_preempt_count(); | 
 |    4)   0.562 us    |        } | 
 |    4) + 17.452 us   |      } | 
 |    4)   0.108 us    |      put_prev_task_fair(); | 
 |    4)   0.102 us    |      pick_next_task_fair(); | 
 |    4)   0.084 us    |      pick_next_task_stop(); | 
 |    4)   0.075 us    |      pick_next_task_rt(); | 
 |    4)   0.062 us    |      pick_next_task_fair(); | 
 |    4)   0.066 us    |      pick_next_task_idle(); | 
 |    ------------------------------------------ | 
 |    4)   kworker-74   =>    <idle>-0 | 
 |    ------------------------------------------ | 
 |  | 
 |    4)               |      finish_task_switch() { | 
 |    4)               |        _raw_spin_unlock_irq() { | 
 |    4)   0.100 us    |          sub_preempt_count(); | 
 |    4)   0.582 us    |        } | 
 |    4)   1.105 us    |      } | 
 |    4)   0.088 us    |      sub_preempt_count(); | 
 |    4) ! 100.066 us  |    } | 
 |    . | 
 |    . | 
 |    . | 
 |    3)               |  sys_ioctl() { | 
 |    3)   0.083 us    |    fget_light(); | 
 |    3)               |    security_file_ioctl() { | 
 |    3)   0.066 us    |      cap_file_ioctl(); | 
 |    3)   0.562 us    |    } | 
 |    3)               |    do_vfs_ioctl() { | 
 |    3)               |      drm_ioctl() { | 
 |    3)   0.075 us    |        drm_ut_debug_printk(); | 
 |    3)               |        i915_gem_pwrite_ioctl() { | 
 |    3)               |          i915_mutex_lock_interruptible() { | 
 |    3)   0.070 us    |            mutex_lock_interruptible(); | 
 |    3)   0.570 us    |          } | 
 |    3)               |          drm_gem_object_lookup() { | 
 |    3)               |            _raw_spin_lock() { | 
 |    3)   0.080 us    |              add_preempt_count(); | 
 |    3)   0.620 us    |            } | 
 |    3)               |            _raw_spin_unlock() { | 
 |    3)   0.085 us    |              sub_preempt_count(); | 
 |    3)   0.562 us    |            } | 
 |    3)   2.149 us    |          } | 
 |    3)   0.133 us    |          i915_gem_object_pin(); | 
 |    3)               |          i915_gem_object_set_to_gtt_domain() { | 
 |    3)   0.065 us    |            i915_gem_object_flush_gpu_write_domain(); | 
 |    3)   0.065 us    |            i915_gem_object_wait_rendering(); | 
 |    3)   0.062 us    |            i915_gem_object_flush_cpu_write_domain(); | 
 |    3)   1.612 us    |          } | 
 |    3)               |          i915_gem_object_put_fence() { | 
 |    3)   0.097 us    |            i915_gem_object_flush_fence.constprop.36(); | 
 |    3)   0.645 us    |          } | 
 |    3)   0.070 us    |          add_preempt_count(); | 
 |    3)   0.070 us    |          sub_preempt_count(); | 
 |    3)   0.073 us    |          i915_gem_object_unpin(); | 
 |    3)   0.068 us    |          mutex_unlock(); | 
 |    3)   9.924 us    |        } | 
 |    3) + 11.236 us   |      } | 
 |    3) + 11.770 us   |    } | 
 |    3) + 13.784 us   |  } | 
 |    3)               |  sys_ioctl() { | 
 |  | 
 | As you can see, the function_graph display is much easier | 
 | to follow. Also note that in addition to the function calls and | 
 | associated braces, other events such as scheduler events are displayed | 
 | in context. In fact, you can freely include any tracepoint available in | 
 | the trace events subsystem described in the next section by simply | 
 | enabling those events, and they'll appear in context in the function | 
 | graph display. Quite a powerful tool for understanding kernel dynamics. | 
 |  | 
 | Also notice that there are various annotations on the left hand side of | 
 | the display. For example if the total time it took for a given function | 
 | to execute is above a certain threshold, an exclamation point or plus | 
 | sign appears on the left hand side. Please see the ftrace documentation | 
 | for details on all these fields. | 
 |  | 
 | The 'trace events' Subsystem | 
 | ---------------------------- | 
 |  | 
 | One especially important directory contained within the | 
 | /sys/kernel/debug/tracing directory is the 'events' subdirectory, which | 
 | contains representations of every tracepoint in the system. Listing out | 
 | the contents of the 'events' subdirectory, we see mainly another set of | 
 | subdirectories:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing# cd events | 
 |    root@sugarbay:/sys/kernel/debug/tracing/events# ls -al | 
 |    drwxr-xr-x   38 root     root             0 Nov 14 23:19 . | 
 |    drwxr-xr-x    5 root     root             0 Nov 14 23:19 .. | 
 |    drwxr-xr-x   19 root     root             0 Nov 14 23:19 block | 
 |    drwxr-xr-x   32 root     root             0 Nov 14 23:19 btrfs | 
 |    drwxr-xr-x    5 root     root             0 Nov 14 23:19 drm | 
 |    -rw-r--r--    1 root     root             0 Nov 14 23:19 enable | 
 |    drwxr-xr-x   40 root     root             0 Nov 14 23:19 ext3 | 
 |    drwxr-xr-x   79 root     root             0 Nov 14 23:19 ext4 | 
 |    drwxr-xr-x   14 root     root             0 Nov 14 23:19 ftrace | 
 |    drwxr-xr-x    8 root     root             0 Nov 14 23:19 hda | 
 |    -r--r--r--    1 root     root             0 Nov 14 23:19 header_event | 
 |    -r--r--r--    1 root     root             0 Nov 14 23:19 header_page | 
 |    drwxr-xr-x   25 root     root             0 Nov 14 23:19 i915 | 
 |    drwxr-xr-x    7 root     root             0 Nov 14 23:19 irq | 
 |    drwxr-xr-x   12 root     root             0 Nov 14 23:19 jbd | 
 |    drwxr-xr-x   14 root     root             0 Nov 14 23:19 jbd2 | 
 |    drwxr-xr-x   14 root     root             0 Nov 14 23:19 kmem | 
 |    drwxr-xr-x    7 root     root             0 Nov 14 23:19 module | 
 |    drwxr-xr-x    3 root     root             0 Nov 14 23:19 napi | 
 |    drwxr-xr-x    6 root     root             0 Nov 14 23:19 net | 
 |    drwxr-xr-x    3 root     root             0 Nov 14 23:19 oom | 
 |    drwxr-xr-x   12 root     root             0 Nov 14 23:19 power | 
 |    drwxr-xr-x    3 root     root             0 Nov 14 23:19 printk | 
 |    drwxr-xr-x    8 root     root             0 Nov 14 23:19 random | 
 |    drwxr-xr-x    4 root     root             0 Nov 14 23:19 raw_syscalls | 
 |    drwxr-xr-x    3 root     root             0 Nov 14 23:19 rcu | 
 |    drwxr-xr-x    6 root     root             0 Nov 14 23:19 rpm | 
 |    drwxr-xr-x   20 root     root             0 Nov 14 23:19 sched | 
 |    drwxr-xr-x    7 root     root             0 Nov 14 23:19 scsi | 
 |    drwxr-xr-x    4 root     root             0 Nov 14 23:19 signal | 
 |    drwxr-xr-x    5 root     root             0 Nov 14 23:19 skb | 
 |    drwxr-xr-x    4 root     root             0 Nov 14 23:19 sock | 
 |    drwxr-xr-x   10 root     root             0 Nov 14 23:19 sunrpc | 
 |    drwxr-xr-x  538 root     root             0 Nov 14 23:19 syscalls | 
 |    drwxr-xr-x    4 root     root             0 Nov 14 23:19 task | 
 |    drwxr-xr-x   14 root     root             0 Nov 14 23:19 timer | 
 |    drwxr-xr-x    3 root     root             0 Nov 14 23:19 udp | 
 |    drwxr-xr-x   21 root     root             0 Nov 14 23:19 vmscan | 
 |    drwxr-xr-x    3 root     root             0 Nov 14 23:19 vsyscall | 
 |    drwxr-xr-x    6 root     root             0 Nov 14 23:19 workqueue | 
 |    drwxr-xr-x   26 root     root             0 Nov 14 23:19 writeback | 
 |  | 
 | Each one of these subdirectories | 
 | corresponds to a 'subsystem' and contains yet again more subdirectories, | 
 | each one of those finally corresponding to a tracepoint. For example, | 
 | here are the contents of the 'kmem' subsystem:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing/events# cd kmem | 
 |    root@sugarbay:/sys/kernel/debug/tracing/events/kmem# ls -al | 
 |    drwxr-xr-x   14 root     root             0 Nov 14 23:19 . | 
 |    drwxr-xr-x   38 root     root             0 Nov 14 23:19 .. | 
 |    -rw-r--r--    1 root     root             0 Nov 14 23:19 enable | 
 |    -rw-r--r--    1 root     root             0 Nov 14 23:19 filter | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 kfree | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 kmalloc | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 kmalloc_node | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 kmem_cache_alloc | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 kmem_cache_alloc_node | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 kmem_cache_free | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 mm_page_alloc | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 mm_page_alloc_extfrag | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 mm_page_alloc_zone_locked | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 mm_page_free | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 mm_page_free_batched | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 mm_page_pcpu_drain | 
 |  | 
 | Let's see what's inside the subdirectory for a | 
 | specific tracepoint, in this case the one for kmalloc:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing/events/kmem# cd kmalloc | 
 |    root@sugarbay:/sys/kernel/debug/tracing/events/kmem/kmalloc# ls -al | 
 |    drwxr-xr-x    2 root     root             0 Nov 14 23:19 . | 
 |    drwxr-xr-x   14 root     root             0 Nov 14 23:19 .. | 
 |    -rw-r--r--    1 root     root             0 Nov 14 23:19 enable | 
 |    -rw-r--r--    1 root     root             0 Nov 14 23:19 filter | 
 |    -r--r--r--    1 root     root             0 Nov 14 23:19 format | 
 |    -r--r--r--    1 root     root             0 Nov 14 23:19 id | 
 |  | 
 | The 'format' file for the | 
 | tracepoint describes the event in memory, which is used by the various | 
 | tracing tools that now make use of these tracepoint to parse the event | 
 | and make sense of it, along with a 'print fmt' field that allows tools | 
 | like ftrace to display the event as text. Here's what the format of the | 
 | kmalloc event looks like:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing/events/kmem/kmalloc# cat format | 
 |    name: kmalloc | 
 |    ID: 313 | 
 |    format: | 
 |            field:unsigned short common_type;	offset:0;	size:2;	signed:0; | 
 |            field:unsigned char common_flags;	offset:2;	size:1;	signed:0; | 
 |            field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0; | 
 |            field:int common_pid;	offset:4;	size:4;	signed:1; | 
 |            field:int common_padding;	offset:8;	size:4;	signed:1; | 
 |  | 
 |            field:unsigned long call_site;	offset:16;	size:8;	signed:0; | 
 |            field:const void * ptr;	offset:24;	size:8;	signed:0; | 
 |            field:size_t bytes_req;	offset:32;	size:8;	signed:0; | 
 |            field:size_t bytes_alloc;	offset:40;	size:8;	signed:0; | 
 |            field:gfp_t gfp_flags;	offset:48;	size:4;	signed:0; | 
 |  | 
 |    print fmt: "call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s", REC->call_site, REC->ptr, REC->bytes_req, REC->bytes_alloc, | 
 |    (REC->gfp_flags) ? __print_flags(REC->gfp_flags, "|", {(unsigned long)(((( gfp_t)0x10u) | (( gfp_t)0x40u) | (( gfp_t)0x80u) | (( | 
 |    gfp_t)0x20000u) | (( gfp_t)0x02u) | (( gfp_t)0x08u)) | (( gfp_t)0x4000u) | (( gfp_t)0x10000u) | (( gfp_t)0x1000u) | (( gfp_t)0x200u) | (( | 
 |    gfp_t)0x400000u)), "GFP_TRANSHUGE"}, {(unsigned long)((( gfp_t)0x10u) | (( gfp_t)0x40u) | (( gfp_t)0x80u) | (( gfp_t)0x20000u) | (( | 
 |    gfp_t)0x02u) | (( gfp_t)0x08u)), "GFP_HIGHUSER_MOVABLE"}, {(unsigned long)((( gfp_t)0x10u) | (( gfp_t)0x40u) | (( gfp_t)0x80u) | (( | 
 |    gfp_t)0x20000u) | (( gfp_t)0x02u)), "GFP_HIGHUSER"}, {(unsigned long)((( gfp_t)0x10u) | (( gfp_t)0x40u) | (( gfp_t)0x80u) | (( | 
 |    gfp_t)0x20000u)), "GFP_USER"}, {(unsigned long)((( gfp_t)0x10u) | (( gfp_t)0x40u) | (( gfp_t)0x80u) | (( gfp_t)0x80000u)), GFP_TEMPORARY"}, | 
 |    {(unsigned long)((( gfp_t)0x10u) | (( gfp_t)0x40u) | (( gfp_t)0x80u)), "GFP_KERNEL"}, {(unsigned long)((( gfp_t)0x10u) | (( gfp_t)0x40u)), | 
 |    "GFP_NOFS"}, {(unsigned long)((( gfp_t)0x20u)), "GFP_ATOMIC"}, {(unsigned long)((( gfp_t)0x10u)), "GFP_NOIO"}, {(unsigned long)(( | 
 |    gfp_t)0x20u), "GFP_HIGH"}, {(unsigned long)(( gfp_t)0x10u), "GFP_WAIT"}, {(unsigned long)(( gfp_t)0x40u), "GFP_IO"}, {(unsigned long)(( | 
 |    gfp_t)0x100u), "GFP_COLD"}, {(unsigned long)(( gfp_t)0x200u), "GFP_NOWARN"}, {(unsigned long)(( gfp_t)0x400u), "GFP_REPEAT"}, {(unsigned | 
 |    long)(( gfp_t)0x800u), "GFP_NOFAIL"}, {(unsigned long)(( gfp_t)0x1000u), "GFP_NORETRY"},      {(unsigned long)(( gfp_t)0x4000u), "GFP_COMP"}, | 
 |    {(unsigned long)(( gfp_t)0x8000u), "GFP_ZERO"}, {(unsigned long)(( gfp_t)0x10000u), "GFP_NOMEMALLOC"}, {(unsigned long)(( gfp_t)0x20000u), | 
 |    "GFP_HARDWALL"}, {(unsigned long)(( gfp_t)0x40000u), "GFP_THISNODE"}, {(unsigned long)(( gfp_t)0x80000u), "GFP_RECLAIMABLE"}, {(unsigned | 
 |    long)(( gfp_t)0x08u), "GFP_MOVABLE"}, {(unsigned long)(( gfp_t)0), "GFP_NOTRACK"}, {(unsigned long)(( gfp_t)0x400000u), "GFP_NO_KSWAPD"}, | 
 |    {(unsigned long)(( gfp_t)0x800000u), "GFP_OTHER_NODE"} ) : "GFP_NOWAIT" | 
 |  | 
 | The 'enable' file | 
 | in the tracepoint directory is what allows the user (or tools such as | 
 | trace-cmd) to actually turn the tracepoint on and off. When enabled, the | 
 | corresponding tracepoint will start appearing in the ftrace 'trace' file | 
 | described previously. For example, this turns on the kmalloc tracepoint:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing/events/kmem/kmalloc# echo 1 > enable | 
 |  | 
 | At the moment, we're not interested in the function tracer or | 
 | some other tracer that might be in effect, so we first turn it off, but | 
 | if we do that, we still need to turn tracing on in order to see the | 
 | events in the output buffer:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing# echo nop > current_tracer | 
 |    root@sugarbay:/sys/kernel/debug/tracing# echo 1 > tracing_on | 
 |  | 
 | Now, if we look at the 'trace' file, we see nothing | 
 | but the kmalloc events we just turned on:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing# cat trace | less | 
 |    # tracer: nop | 
 |    # | 
 |    # entries-in-buffer/entries-written: 1897/1897   #P:8 | 
 |    # | 
 |    #                              _-----=> irqs-off | 
 |    #                             / _----=> need-resched | 
 |    #                            | / _---=> hardirq/softirq | 
 |    #                            || / _--=> preempt-depth | 
 |    #                            ||| /     delay | 
 |    #           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION | 
 |    #              | |       |   ||||       |         | | 
 |           dropbear-1465  [000] ...1 18154.620753: kmalloc: call_site=ffffffff816650d4 ptr=ffff8800729c3000 bytes_req=2048 bytes_alloc=2048 gfp_flags=GFP_KERNEL | 
 |             <idle>-0     [000] ..s3 18154.621640: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d555800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |             <idle>-0     [000] ..s3 18154.621656: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d555800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |    matchbox-termin-1361  [001] ...1 18154.755472: kmalloc: call_site=ffffffff81614050 ptr=ffff88006d5f0e00 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_KERNEL|GFP_REPEAT | 
 |               Xorg-1264  [002] ...1 18154.755581: kmalloc: call_site=ffffffff8141abe8 ptr=ffff8800734f4cc0 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL|GFP_NOWARN|GFP_NORETRY | 
 |               Xorg-1264  [002] ...1 18154.755583: kmalloc: call_site=ffffffff814192a3 ptr=ffff88001f822520 bytes_req=24 bytes_alloc=32 gfp_flags=GFP_KERNEL|GFP_ZERO | 
 |               Xorg-1264  [002] ...1 18154.755589: kmalloc: call_site=ffffffff81419edb ptr=ffff8800721a2f00 bytes_req=64 bytes_alloc=64 gfp_flags=GFP_KERNEL|GFP_ZERO | 
 |    matchbox-termin-1361  [001] ...1 18155.354594: kmalloc: call_site=ffffffff81614050 ptr=ffff88006db35400 bytes_req=576 bytes_alloc=1024 gfp_flags=GFP_KERNEL|GFP_REPEAT | 
 |               Xorg-1264  [002] ...1 18155.354703: kmalloc: call_site=ffffffff8141abe8 ptr=ffff8800734f4cc0 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL|GFP_NOWARN|GFP_NORETRY | 
 |               Xorg-1264  [002] ...1 18155.354705: kmalloc: call_site=ffffffff814192a3 ptr=ffff88001f822520 bytes_req=24 bytes_alloc=32 gfp_flags=GFP_KERNEL|GFP_ZERO | 
 |               Xorg-1264  [002] ...1 18155.354711: kmalloc: call_site=ffffffff81419edb ptr=ffff8800721a2f00 bytes_req=64 bytes_alloc=64 gfp_flags=GFP_KERNEL|GFP_ZERO | 
 |             <idle>-0     [000] ..s3 18155.673319: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d555800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |           dropbear-1465  [000] ...1 18155.673525: kmalloc: call_site=ffffffff816650d4 ptr=ffff8800729c3000 bytes_req=2048 bytes_alloc=2048 gfp_flags=GFP_KERNEL | 
 |             <idle>-0     [000] ..s3 18155.674821: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d554800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |             <idle>-0     [000] ..s3 18155.793014: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d554800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |           dropbear-1465  [000] ...1 18155.793219: kmalloc: call_site=ffffffff816650d4 ptr=ffff8800729c3000 bytes_req=2048 bytes_alloc=2048 gfp_flags=GFP_KERNEL | 
 |             <idle>-0     [000] ..s3 18155.794147: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d555800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |             <idle>-0     [000] ..s3 18155.936705: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d555800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |           dropbear-1465  [000] ...1 18155.936910: kmalloc: call_site=ffffffff816650d4 ptr=ffff8800729c3000 bytes_req=2048 bytes_alloc=2048 gfp_flags=GFP_KERNEL | 
 |             <idle>-0     [000] ..s3 18155.937869: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d554800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |    matchbox-termin-1361  [001] ...1 18155.953667: kmalloc: call_site=ffffffff81614050 ptr=ffff88006d5f2000 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_KERNEL|GFP_REPEAT | 
 |               Xorg-1264  [002] ...1 18155.953775: kmalloc: call_site=ffffffff8141abe8 ptr=ffff8800734f4cc0 bytes_req=168 bytes_alloc=192 gfp_flags=GFP_KERNEL|GFP_NOWARN|GFP_NORETRY | 
 |               Xorg-1264  [002] ...1 18155.953777: kmalloc: call_site=ffffffff814192a3 ptr=ffff88001f822520 bytes_req=24 bytes_alloc=32 gfp_flags=GFP_KERNEL|GFP_ZERO | 
 |               Xorg-1264  [002] ...1 18155.953783: kmalloc: call_site=ffffffff81419edb ptr=ffff8800721a2f00 bytes_req=64 bytes_alloc=64 gfp_flags=GFP_KERNEL|GFP_ZERO | 
 |             <idle>-0     [000] ..s3 18156.176053: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d554800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |           dropbear-1465  [000] ...1 18156.176257: kmalloc: call_site=ffffffff816650d4 ptr=ffff8800729c3000 bytes_req=2048 bytes_alloc=2048 gfp_flags=GFP_KERNEL | 
 |             <idle>-0     [000] ..s3 18156.177717: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d555800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |             <idle>-0     [000] ..s3 18156.399229: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d555800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |           dropbear-1465  [000] ...1 18156.399434: kmalloc: call_site=ffffffff816650d4 ptr=ffff8800729c3000 bytes_http://rostedt.homelinux.com/kernelshark/req=2048 bytes_alloc=2048 gfp_flags=GFP_KERNEL | 
 |             <idle>-0     [000] ..s3 18156.400660: kmalloc: call_site=ffffffff81619b36 ptr=ffff88006d554800 bytes_req=512 bytes_alloc=512 gfp_flags=GFP_ATOMIC | 
 |    matchbox-termin-1361  [001] ...1 18156.552800: kmalloc: call_site=ffffffff81614050 ptr=ffff88006db34800 bytes_req=576 bytes_alloc=1024 gfp_flags=GFP_KERNEL|GFP_REPEAT | 
 |  | 
 | To again disable the kmalloc event, we need to send 0 to the enable file:: | 
 |  | 
 |    root@sugarbay:/sys/kernel/debug/tracing/events/kmem/kmalloc# echo 0 > enable | 
 |  | 
 | You can enable any number of events or complete subsystems (by | 
 | using the 'enable' file in the subsystem directory) and get an | 
 | arbitrarily fine-grained idea of what's going on in the system by | 
 | enabling as many of the appropriate tracepoints as applicable. | 
 |  | 
 | A number of the tools described in this HOWTO do just that, including | 
 | trace-cmd and kernelshark in the next section. | 
 |  | 
 | .. admonition:: Tying it Together | 
 |  | 
 |    These tracepoints and their representation are used not only by | 
 |    ftrace, but by many of the other tools covered in this document and | 
 |    they form a central point of integration for the various tracers | 
 |    available in Linux. They form a central part of the instrumentation | 
 |    for the following tools: perf, lttng, ftrace, blktrace and SystemTap | 
 |  | 
 | .. admonition:: Tying it Together | 
 |  | 
 |    Eventually all the special-purpose tracers currently available in | 
 |    /sys/kernel/debug/tracing will be removed and replaced with | 
 |    equivalent tracers based on the 'trace events' subsystem. | 
 |  | 
 | trace-cmd/kernelshark | 
 | --------------------- | 
 |  | 
 | trace-cmd is essentially an extensive command-line 'wrapper' interface | 
 | that hides the details of all the individual files in | 
 | /sys/kernel/debug/tracing, allowing users to specify specific particular | 
 | events within the /sys/kernel/debug/tracing/events/ subdirectory and to | 
 | collect traces and avoid having to deal with those details directly. | 
 |  | 
 | As yet another layer on top of that, kernelshark provides a GUI that | 
 | allows users to start and stop traces and specify sets of events using | 
 | an intuitive interface, and view the output as both trace events and as | 
 | a per-CPU graphical display. It directly uses 'trace-cmd' as the | 
 | plumbing that accomplishes all that underneath the covers (and actually | 
 | displays the trace-cmd command it uses, as we'll see). | 
 |  | 
 | To start a trace using kernelshark, first start kernelshark:: | 
 |  | 
 |    root@sugarbay:~# kernelshark | 
 |  | 
 | Then bring up the 'Capture' dialog by | 
 | choosing from the kernelshark menu:: | 
 |  | 
 |    Capture | Record | 
 |  | 
 | That will display the following dialog, which allows you to choose one or more | 
 | events (or even one or more complete subsystems) to trace: | 
 |  | 
 | .. image:: figures/kernelshark-choose-events.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | Note that these are exactly the same sets of events described in the | 
 | previous trace events subsystem section, and in fact is where trace-cmd | 
 | gets them for kernelshark. | 
 |  | 
 | In the above screenshot, we've decided to explore the graphics subsystem | 
 | a bit and so have chosen to trace all the tracepoints contained within | 
 | the 'i915' and 'drm' subsystems. | 
 |  | 
 | After doing that, we can start and stop the trace using the 'Run' and | 
 | 'Stop' button on the lower right corner of the dialog (the same button | 
 | will turn into the 'Stop' button after the trace has started): | 
 |  | 
 | .. image:: figures/kernelshark-output-display.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | Notice that the right-hand pane shows the exact trace-cmd command-line | 
 | that's used to run the trace, along with the results of the trace-cmd | 
 | run. | 
 |  | 
 | Once the 'Stop' button is pressed, the graphical view magically fills up | 
 | with a colorful per-cpu display of the trace data, along with the | 
 | detailed event listing below that: | 
 |  | 
 | .. image:: figures/kernelshark-i915-display.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | Here's another example, this time a display resulting from tracing 'all | 
 | events': | 
 |  | 
 | .. image:: figures/kernelshark-all.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | The tool is pretty self-explanatory, but for more detailed information | 
 | on navigating through the data, see the `kernelshark | 
 | website <https://rostedt.homelinux.com/kernelshark/>`__. | 
 |  | 
 | ftrace Documentation | 
 | -------------------- | 
 |  | 
 | The documentation for ftrace can be found in the kernel Documentation | 
 | directory:: | 
 |  | 
 |    Documentation/trace/ftrace.txt | 
 |  | 
 | The documentation for the trace event subsystem can also be found in the kernel | 
 | Documentation directory:: | 
 |  | 
 |    Documentation/trace/events.txt | 
 |  | 
 | There is a nice series of articles on using ftrace and trace-cmd at LWN: | 
 |  | 
 | -  `Debugging the kernel using Ftrace - part | 
 |    1 <https://lwn.net/Articles/365835/>`__ | 
 |  | 
 | -  `Debugging the kernel using Ftrace - part | 
 |    2 <https://lwn.net/Articles/366796/>`__ | 
 |  | 
 | -  `Secrets of the Ftrace function | 
 |    tracer <https://lwn.net/Articles/370423/>`__ | 
 |  | 
 | -  `trace-cmd: A front-end for | 
 |    Ftrace <https://lwn.net/Articles/410200/>`__ | 
 |  | 
 | There's more detailed documentation kernelshark usage here: | 
 | `KernelShark <https://rostedt.homelinux.com/kernelshark/>`__ | 
 |  | 
 | An amusing yet useful README (a tracing mini-HOWTO) can be found in | 
 | ``/sys/kernel/debug/tracing/README``. | 
 |  | 
 | systemtap | 
 | ========= | 
 |  | 
 | SystemTap is a system-wide script-based tracing and profiling tool. | 
 |  | 
 | SystemTap scripts are C-like programs that are executed in the kernel to | 
 | gather/print/aggregate data extracted from the context they end up being | 
 | invoked under. | 
 |  | 
 | For example, this probe from the `SystemTap | 
 | tutorial <https://sourceware.org/systemtap/tutorial/>`__ simply prints a | 
 | line every time any process on the system open()s a file. For each line, | 
 | it prints the executable name of the program that opened the file, along | 
 | with its PID, and the name of the file it opened (or tried to open), | 
 | which it extracts from the open syscall's argstr. | 
 |  | 
 | .. code-block:: none | 
 |  | 
 |    probe syscall.open | 
 |    { | 
 |            printf ("%s(%d) open (%s)\n", execname(), pid(), argstr) | 
 |    } | 
 |  | 
 |    probe timer.ms(4000) # after 4 seconds | 
 |    { | 
 |            exit () | 
 |    } | 
 |  | 
 | Normally, to execute this | 
 | probe, you'd simply install systemtap on the system you want to probe, | 
 | and directly run the probe on that system e.g. assuming the name of the | 
 | file containing the above text is trace_open.stp:: | 
 |  | 
 |    # stap trace_open.stp | 
 |  | 
 | What systemtap does under the covers to run this probe is 1) parse and | 
 | convert the probe to an equivalent 'C' form, 2) compile the 'C' form | 
 | into a kernel module, 3) insert the module into the kernel, which arms | 
 | it, and 4) collect the data generated by the probe and display it to the | 
 | user. | 
 |  | 
 | In order to accomplish steps 1 and 2, the 'stap' program needs access to | 
 | the kernel build system that produced the kernel that the probed system | 
 | is running. In the case of a typical embedded system (the 'target'), the | 
 | kernel build system unfortunately isn't typically part of the image | 
 | running on the target. It is normally available on the 'host' system | 
 | that produced the target image however; in such cases, steps 1 and 2 are | 
 | executed on the host system, and steps 3 and 4 are executed on the | 
 | target system, using only the systemtap 'runtime'. | 
 |  | 
 | The systemtap support in Yocto assumes that only steps 3 and 4 are run | 
 | on the target; it is possible to do everything on the target, but this | 
 | section assumes only the typical embedded use-case. | 
 |  | 
 | So basically what you need to do in order to run a systemtap script on | 
 | the target is to 1) on the host system, compile the probe into a kernel | 
 | module that makes sense to the target, 2) copy the module onto the | 
 | target system and 3) insert the module into the target kernel, which | 
 | arms it, and 4) collect the data generated by the probe and display it | 
 | to the user. | 
 |  | 
 | systemtap Setup | 
 | --------------- | 
 |  | 
 | Those are a lot of steps and a lot of details, but fortunately Yocto | 
 | includes a script called 'crosstap' that will take care of those | 
 | details, allowing you to simply execute a systemtap script on the remote | 
 | target, with arguments if necessary. | 
 |  | 
 | In order to do this from a remote host, however, you need to have access | 
 | to the build for the image you booted. The 'crosstap' script provides | 
 | details on how to do this if you run the script on the host without | 
 | having done a build:: | 
 |  | 
 |    $ crosstap root@192.168.1.88 trace_open.stp | 
 |  | 
 |    Error: No target kernel build found. | 
 |    Did you forget to create a local build of your image? | 
 |  | 
 |    'crosstap' requires a local sdk build of the target system | 
 |    (or a build that includes 'tools-profile') in order to build | 
 |    kernel modules that can probe the target system. | 
 |  | 
 |    Practically speaking, that means you need to do the following: | 
 |     - If you're running a pre-built image, download the release | 
 |       and/or BSP tarballs used to build the image. | 
 |     - If you're working from git sources, just clone the metadata | 
 |       and BSP layers needed to build the image you'll be booting. | 
 |     - Make sure you're properly set up to build a new image (see | 
 |       the BSP README and/or the widely available basic documentation | 
 |       that discusses how to build images). | 
 |     - Build an -sdk version of the image e.g.: | 
 |         $ bitbake core-image-sato-sdk | 
 |     OR | 
 |     - Build a non-sdk image but include the profiling tools: | 
 |         [ edit local.conf and add 'tools-profile' to the end of | 
 |           the EXTRA_IMAGE_FEATURES variable ] | 
 |         $ bitbake core-image-sato | 
 |  | 
 |    Once you've build the image on the host system, you're ready to | 
 |    boot it (or the equivalent pre-built image) and use 'crosstap' | 
 |    to probe it (you need to source the environment as usual first): | 
 |  | 
 |       $ source oe-init-build-env | 
 |       $ cd ~/my/systemtap/scripts | 
 |       $ crosstap root@192.168.1.xxx myscript.stp | 
 |  | 
 | .. note:: | 
 |  | 
 |    SystemTap, which uses 'crosstap', assumes you can establish an ssh | 
 |    connection to the remote target. Please refer to the crosstap wiki | 
 |    page for details on verifying ssh connections at | 
 |    . Also, the ability to ssh into the target system is not enabled by | 
 |    default in \*-minimal images. | 
 |  | 
 | So essentially what you need to | 
 | do is build an SDK image or image with 'tools-profile' as detailed in | 
 | the ":ref:`profile-manual/intro:General Setup`" section of this | 
 | manual, and boot the resulting target image. | 
 |  | 
 | .. note:: | 
 |  | 
 |    If you have a :term:`Build Directory` containing multiple machines, you need | 
 |    to have the :term:`MACHINE` you're connecting to selected in local.conf, and | 
 |    the kernel in that machine's :term:`Build Directory` must match the kernel on | 
 |    the booted system exactly, or you'll get the above 'crosstap' message | 
 |    when you try to invoke a script. | 
 |  | 
 | Running a Script on a Target | 
 | ---------------------------- | 
 |  | 
 | Once you've done that, you should be able to run a systemtap script on | 
 | the target:: | 
 |  | 
 |    $ cd /path/to/yocto | 
 |    $ source oe-init-build-env | 
 |  | 
 |    ### Shell environment set up for builds. ### | 
 |  | 
 |    You can now run 'bitbake <target>' | 
 |  | 
 |    Common targets are: | 
 |             core-image-minimal | 
 |             core-image-sato | 
 |             meta-toolchain | 
 |             meta-ide-support | 
 |  | 
 |    You can also run generated QEMU images with a command like 'runqemu qemux86-64' | 
 |  | 
 | Once you've done that, you can cd to whatever | 
 | directory contains your scripts and use 'crosstap' to run the script:: | 
 |  | 
 |    $ cd /path/to/my/systemap/script | 
 |    $ crosstap root@192.168.7.2 trace_open.stp | 
 |  | 
 | If you get an error connecting to the target e.g.:: | 
 |  | 
 |    $ crosstap root@192.168.7.2 trace_open.stp | 
 |    error establishing ssh connection on remote 'root@192.168.7.2' | 
 |  | 
 | Try ssh'ing to the target and see what happens:: | 
 |  | 
 |    $ ssh root@192.168.7.2 | 
 |  | 
 | A lot of the time, connection | 
 | problems are due specifying a wrong IP address or having a 'host key | 
 | verification error'. | 
 |  | 
 | If everything worked as planned, you should see something like this | 
 | (enter the password when prompted, or press enter if it's set up to use | 
 | no password): | 
 |  | 
 | .. code-block:: none | 
 |  | 
 |    $ crosstap root@192.168.7.2 trace_open.stp | 
 |    root@192.168.7.2's password: | 
 |    matchbox-termin(1036) open ("/tmp/vte3FS2LW", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600) | 
 |    matchbox-termin(1036) open ("/tmp/vteJMC7LW", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600) | 
 |  | 
 | systemtap Documentation | 
 | ----------------------- | 
 |  | 
 | The SystemTap language reference can be found here: `SystemTap Language | 
 | Reference <https://sourceware.org/systemtap/langref/>`__ | 
 |  | 
 | Links to other SystemTap documents, tutorials, and examples can be found | 
 | here: `SystemTap documentation | 
 | page <https://sourceware.org/systemtap/documentation.html>`__ | 
 |  | 
 | Sysprof | 
 | ======= | 
 |  | 
 | Sysprof is a very easy to use system-wide profiler that consists of a | 
 | single window with three panes and a few buttons which allow you to | 
 | start, stop, and view the profile from one place. | 
 |  | 
 | Sysprof Setup | 
 | ------------- | 
 |  | 
 | For this section, we'll assume you've already performed the basic setup | 
 | outlined in the ":ref:`profile-manual/intro:General Setup`" section. | 
 |  | 
 | Sysprof is a GUI-based application that runs on the target system. For | 
 | the rest of this document we assume you've ssh'ed to the host and will | 
 | be running Sysprof on the target (you can use the '-X' option to ssh and | 
 | have the Sysprof GUI run on the target but display remotely on the host | 
 | if you want). | 
 |  | 
 | Basic Sysprof Usage | 
 | ------------------- | 
 |  | 
 | To start profiling the system, you simply press the 'Start' button. To | 
 | stop profiling and to start viewing the profile data in one easy step, | 
 | press the 'Profile' button. | 
 |  | 
 | Once you've pressed the profile button, the three panes will fill up | 
 | with profiling data: | 
 |  | 
 | .. image:: figures/sysprof-copy-to-user.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | The left pane shows a list of functions and processes. Selecting one of | 
 | those expands that function in the right pane, showing all its callees. | 
 | Note that this caller-oriented display is essentially the inverse of | 
 | perf's default callee-oriented callchain display. | 
 |  | 
 | In the screenshot above, we're focusing on ``__copy_to_user_ll()`` and | 
 | looking up the callchain we can see that one of the callers of | 
 | ``__copy_to_user_ll`` is sys_read() and the complete callpath between them. | 
 | Notice that this is essentially a portion of the same information we saw | 
 | in the perf display shown in the perf section of this page. | 
 |  | 
 | .. image:: figures/sysprof-copy-from-user.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | Similarly, the above is a snapshot of the Sysprof display of a | 
 | copy-from-user callchain. | 
 |  | 
 | Finally, looking at the third Sysprof pane in the lower left, we can see | 
 | a list of all the callers of a particular function selected in the top | 
 | left pane. In this case, the lower pane is showing all the callers of | 
 | ``__mark_inode_dirty``: | 
 |  | 
 | .. image:: figures/sysprof-callers.png | 
 |    :align: center | 
 |    :width: 70% | 
 |  | 
 | Double-clicking on one of those functions will in turn change the focus | 
 | to the selected function, and so on. | 
 |  | 
 | .. admonition:: Tying it Together | 
 |  | 
 |    If you like sysprof's 'caller-oriented' display, you may be able to | 
 |    approximate it in other tools as well. For example, 'perf report' has | 
 |    the -g (--call-graph) option that you can experiment with; one of the | 
 |    options is 'caller' for an inverted caller-based callgraph display. | 
 |  | 
 | Sysprof Documentation | 
 | --------------------- | 
 |  | 
 | There doesn't seem to be any documentation for Sysprof, but maybe that's | 
 | because it's pretty self-explanatory. The Sysprof website, however, is | 
 | here: `Sysprof, System-wide Performance Profiler for | 
 | Linux <http://sysprof.com/>`__ | 
 |  | 
 | LTTng (Linux Trace Toolkit, next generation) | 
 | ============================================ | 
 |  | 
 | LTTng Setup | 
 | ----------- | 
 |  | 
 | For this section, we'll assume you've already performed the basic setup | 
 | outlined in the ":ref:`profile-manual/intro:General Setup`" section. | 
 | LTTng is run on the target system by ssh'ing to it. | 
 |  | 
 | Collecting and Viewing Traces | 
 | ----------------------------- | 
 |  | 
 | Once you've applied the above commits and built and booted your image | 
 | (you need to build the core-image-sato-sdk image or use one of the other | 
 | methods described in the ":ref:`profile-manual/intro:General Setup`" section), you're ready to start | 
 | tracing. | 
 |  | 
 | Collecting and viewing a trace on the target (inside a shell) | 
 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
 |  | 
 | First, from the host, ssh to the target:: | 
 |  | 
 |    $ ssh -l root 192.168.1.47 | 
 |    The authenticity of host '192.168.1.47 (192.168.1.47)' can't be established. | 
 |    RSA key fingerprint is 23:bd:c8:b1:a8:71:52:00:ee:00:4f:64:9e:10:b9:7e. | 
 |    Are you sure you want to continue connecting (yes/no)? yes | 
 |    Warning: Permanently added '192.168.1.47' (RSA) to the list of known hosts. | 
 |    root@192.168.1.47's password: | 
 |  | 
 | Once on the target, use these steps to create a trace:: | 
 |  | 
 |    root@crownbay:~# lttng create | 
 |    Spawning a session daemon | 
 |    Session auto-20121015-232120 created. | 
 |    Traces will be written in /home/root/lttng-traces/auto-20121015-232120 | 
 |  | 
 | Enable the events you want to trace (in this case all kernel events):: | 
 |  | 
 |    root@crownbay:~# lttng enable-event --kernel --all | 
 |    All kernel events are enabled in channel channel0 | 
 |  | 
 | Start the trace:: | 
 |  | 
 |    root@crownbay:~# lttng start | 
 |    Tracing started for session auto-20121015-232120 | 
 |  | 
 | And then stop the trace after awhile or after running a particular workload that | 
 | you want to trace:: | 
 |  | 
 |    root@crownbay:~# lttng stop | 
 |    Tracing stopped for session auto-20121015-232120 | 
 |  | 
 | You can now view the trace in text form on the target:: | 
 |  | 
 |    root@crownbay:~# lttng view | 
 |    [23:21:56.989270399] (+?.?????????) sys_geteuid: { 1 }, { } | 
 |    [23:21:56.989278081] (+0.000007682) exit_syscall: { 1 }, { ret = 0 } | 
 |    [23:21:56.989286043] (+0.000007962) sys_pipe: { 1 }, { fildes = 0xB77B9E8C } | 
 |    [23:21:56.989321802] (+0.000035759) exit_syscall: { 1 }, { ret = 0 } | 
 |    [23:21:56.989329345] (+0.000007543) sys_mmap_pgoff: { 1 }, { addr = 0x0, len = 10485760, prot = 3, flags = 131362, fd = 4294967295, pgoff = 0 } | 
 |    [23:21:56.989351694] (+0.000022349) exit_syscall: { 1 }, { ret = -1247805440 } | 
 |    [23:21:56.989432989] (+0.000081295) sys_clone: { 1 }, { clone_flags = 0x411, newsp = 0xB5EFFFE4, parent_tid = 0xFFFFFFFF, child_tid = 0x0 } | 
 |    [23:21:56.989477129] (+0.000044140) sched_stat_runtime: { 1 }, { comm = "lttng-consumerd", tid = 1193, runtime = 681660, vruntime = 43367983388 } | 
 |    [23:21:56.989486697] (+0.000009568) sched_migrate_task: { 1 }, { comm = "lttng-consumerd", tid = 1193, prio = 20, orig_cpu = 1, dest_cpu = 1 } | 
 |    [23:21:56.989508418] (+0.000021721) hrtimer_init: { 1 }, { hrtimer = 3970832076, clockid = 1, mode = 1 } | 
 |    [23:21:56.989770462] (+0.000262044) hrtimer_cancel: { 1 }, { hrtimer = 3993865440 } | 
 |    [23:21:56.989771580] (+0.000001118) hrtimer_cancel: { 0 }, { hrtimer = 3993812192 } | 
 |    [23:21:56.989776957] (+0.000005377) hrtimer_expire_entry: { 1 }, { hrtimer = 3993865440, now = 79815980007057, function = 3238465232 } | 
 |    [23:21:56.989778145] (+0.000001188) hrtimer_expire_entry: { 0 }, { hrtimer = 3993812192, now = 79815980008174, function = 3238465232 } | 
 |    [23:21:56.989791695] (+0.000013550) softirq_raise: { 1 }, { vec = 1 } | 
 |    [23:21:56.989795396] (+0.000003701) softirq_raise: { 0 }, { vec = 1 } | 
 |    [23:21:56.989800635] (+0.000005239) softirq_raise: { 0 }, { vec = 9 } | 
 |    [23:21:56.989807130] (+0.000006495) sched_stat_runtime: { 1 }, { comm = "lttng-consumerd", tid = 1193, runtime = 330710, vruntime = 43368314098 } | 
 |    [23:21:56.989809993] (+0.000002863) sched_stat_runtime: { 0 }, { comm = "lttng-sessiond", tid = 1181, runtime = 1015313, vruntime = 36976733240 } | 
 |    [23:21:56.989818514] (+0.000008521) hrtimer_expire_exit: { 0 }, { hrtimer = 3993812192 } | 
 |    [23:21:56.989819631] (+0.000001117) hrtimer_expire_exit: { 1 }, { hrtimer = 3993865440 } | 
 |    [23:21:56.989821866] (+0.000002235) hrtimer_start: { 0 }, { hrtimer = 3993812192, function = 3238465232, expires = 79815981000000, softexpires = 79815981000000 } | 
 |    [23:21:56.989822984] (+0.000001118) hrtimer_start: { 1 }, { hrtimer = 3993865440, function = 3238465232, expires = 79815981000000, softexpires = 79815981000000 } | 
 |    [23:21:56.989832762] (+0.000009778) softirq_entry: { 1 }, { vec = 1 } | 
 |    [23:21:56.989833879] (+0.000001117) softirq_entry: { 0 }, { vec = 1 } | 
 |    [23:21:56.989838069] (+0.000004190) timer_cancel: { 1 }, { timer = 3993871956 } | 
 |    [23:21:56.989839187] (+0.000001118) timer_cancel: { 0 }, { timer = 3993818708 } | 
 |    [23:21:56.989841492] (+0.000002305) timer_expire_entry: { 1 }, { timer = 3993871956, now = 79515980, function = 3238277552 } | 
 |    [23:21:56.989842819] (+0.000001327) timer_expire_entry: { 0 }, { timer = 3993818708, now = 79515980, function = 3238277552 } | 
 |    [23:21:56.989854831] (+0.000012012) sched_stat_runtime: { 1 }, { comm = "lttng-consumerd", tid = 1193, runtime = 49237, vruntime = 43368363335 } | 
 |    [23:21:56.989855949] (+0.000001118) sched_stat_runtime: { 0 }, { comm = "lttng-sessiond", tid = 1181, runtime = 45121, vruntime = 36976778361 } | 
 |    [23:21:56.989861257] (+0.000005308) sched_stat_sleep: { 1 }, { comm = "kworker/1:1", tid = 21, delay = 9451318 } | 
 |    [23:21:56.989862374] (+0.000001117) sched_stat_sleep: { 0 }, { comm = "kworker/0:0", tid = 4, delay = 9958820 } | 
 |    [23:21:56.989868241] (+0.000005867) sched_wakeup: { 0 }, { comm = "kworker/0:0", tid = 4, prio = 120, success = 1, target_cpu = 0 } | 
 |    [23:21:56.989869358] (+0.000001117) sched_wakeup: { 1 }, { comm = "kworker/1:1", tid = 21, prio = 120, success = 1, target_cpu = 1 } | 
 |    [23:21:56.989877460] (+0.000008102) timer_expire_exit: { 1 }, { timer = 3993871956 } | 
 |    [23:21:56.989878577] (+0.000001117) timer_expire_exit: { 0 }, { timer = 3993818708 } | 
 |    . | 
 |    . | 
 |    . | 
 |  | 
 | You can now safely destroy the trace | 
 | session (note that this doesn't delete the trace --- it's still there in | 
 | ~/lttng-traces):: | 
 |  | 
 |    root@crownbay:~# lttng destroy | 
 |    Session auto-20121015-232120 destroyed at /home/root | 
 |  | 
 | Note that the trace is saved in a directory of the same name as returned by | 
 | 'lttng create', under the ~/lttng-traces directory (note that you can change this by | 
 | supplying your own name to 'lttng create'):: | 
 |  | 
 |    root@crownbay:~# ls -al ~/lttng-traces | 
 |    drwxrwx---    3 root     root          1024 Oct 15 23:21 . | 
 |    drwxr-xr-x    5 root     root          1024 Oct 15 23:57 .. | 
 |    drwxrwx---    3 root     root          1024 Oct 15 23:21 auto-20121015-232120 | 
 |  | 
 | Collecting and viewing a userspace trace on the target (inside a shell) | 
 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
 |  | 
 | For LTTng userspace tracing, you need to have a properly instrumented | 
 | userspace program. For this example, we'll use the 'hello' test program | 
 | generated by the lttng-ust build. | 
 |  | 
 | The 'hello' test program isn't installed on the root filesystem by the lttng-ust | 
 | build, so we need to copy it over manually. First cd into the build | 
 | directory that contains the hello executable:: | 
 |  | 
 |    $ cd build/tmp/work/core2_32-poky-linux/lttng-ust/2.0.5-r0/git/tests/hello/.libs | 
 |  | 
 | Copy that over to the target machine:: | 
 |  | 
 |    $ scp hello root@192.168.1.20: | 
 |  | 
 | You now have the instrumented lttng 'hello world' test program on the | 
 | target, ready to test. | 
 |  | 
 | First, from the host, ssh to the target:: | 
 |  | 
 |    $ ssh -l root 192.168.1.47 | 
 |    The authenticity of host '192.168.1.47 (192.168.1.47)' can't be established. | 
 |    RSA key fingerprint is 23:bd:c8:b1:a8:71:52:00:ee:00:4f:64:9e:10:b9:7e. | 
 |    Are you sure you want to continue connecting (yes/no)? yes | 
 |    Warning: Permanently added '192.168.1.47' (RSA) to the list of known hosts. | 
 |    root@192.168.1.47's password: | 
 |  | 
 | Once on the target, use these steps to create a trace:: | 
 |  | 
 |    root@crownbay:~# lttng create | 
 |    Session auto-20190303-021943 created. | 
 |    Traces will be written in /home/root/lttng-traces/auto-20190303-021943 | 
 |  | 
 | Enable the events you want to trace (in this case all userspace events):: | 
 |  | 
 |    root@crownbay:~# lttng enable-event --userspace --all | 
 |    All UST events are enabled in channel channel0 | 
 |  | 
 | Start the trace:: | 
 |  | 
 |    root@crownbay:~# lttng start | 
 |    Tracing started for session auto-20190303-021943 | 
 |  | 
 | Run the instrumented hello world program:: | 
 |  | 
 |    root@crownbay:~# ./hello | 
 |    Hello, World! | 
 |    Tracing... done. | 
 |  | 
 | And then stop the trace after awhile or after running a particular workload | 
 | that you want to trace:: | 
 |  | 
 |    root@crownbay:~# lttng stop | 
 |    Tracing stopped for session auto-20190303-021943 | 
 |  | 
 | You can now view the trace in text form on the target:: | 
 |  | 
 |    root@crownbay:~# lttng view | 
 |    [02:31:14.906146544] (+?.?????????) hello:1424 ust_tests_hello:tptest: { cpu_id = 1 }, { intfield = 0, intfield2 = 0x0, longfield = 0, netintfield = 0, netintfieldhex = 0x0, arrfield1 = [ [0] = 1, [1] = 2, [2] = 3 ], arrfield2 = "test", _seqfield1_length = 4, seqfield1 = [ [0] = 116, [1] = 101, [2] = 115, [3] = 116 ], _seqfield2_length = 4,  seqfield2 = "test", stringfield = "test", floatfield = 2222, doublefield = 2, boolfield = 1 } | 
 |    [02:31:14.906170360] (+0.000023816) hello:1424 ust_tests_hello:tptest: { cpu_id = 1 }, { intfield = 1, intfield2 = 0x1, longfield = 1, netintfield = 1, netintfieldhex = 0x1, arrfield1 = [ [0] = 1, [1] = 2, [2] = 3 ], arrfield2 = "test", _seqfield1_length = 4, seqfield1 = [ [0] = 116, [1] = 101, [2] = 115, [3] = 116 ], _seqfield2_length = 4, seqfield2 = "test", stringfield = "test", floatfield = 2222, doublefield = 2, boolfield = 1 } | 
 |    [02:31:14.906183140] (+0.000012780) hello:1424 ust_tests_hello:tptest: { cpu_id = 1 }, { intfield = 2, intfield2 = 0x2, longfield = 2, netintfield = 2, netintfieldhex = 0x2, arrfield1 = [ [0] = 1, [1] = 2, [2] = 3 ], arrfield2 = "test", _seqfield1_length = 4, seqfield1 = [ [0] = 116, [1] = 101, [2] = 115, [3] = 116 ], _seqfield2_length = 4, seqfield2 = "test", stringfield = "test", floatfield = 2222, doublefield = 2, boolfield = 1 } | 
 |    [02:31:14.906194385] (+0.000011245) hello:1424 ust_tests_hello:tptest: { cpu_id = 1 }, { intfield = 3, intfield2 = 0x3, longfield = 3, netintfield = 3, netintfieldhex = 0x3, arrfield1 = [ [0] = 1, [1] = 2, [2] = 3 ], arrfield2 = "test", _seqfield1_length = 4, seqfield1 = [ [0] = 116, [1] = 101, [2] = 115, [3] = 116 ], _seqfield2_length = 4, seqfield2 = "test", stringfield = "test", floatfield = 2222, doublefield = 2, boolfield = 1 } | 
 |    . | 
 |    . | 
 |    . | 
 |  | 
 | You can now safely destroy the trace session (note that this doesn't delete the | 
 | trace --- it's still there in ~/lttng-traces):: | 
 |  | 
 |    root@crownbay:~# lttng destroy | 
 |    Session auto-20190303-021943 destroyed at /home/root | 
 |  | 
 | LTTng Documentation | 
 | ------------------- | 
 |  | 
 | You can find the primary LTTng Documentation on the `LTTng | 
 | Documentation <https://lttng.org/docs/>`__ site. The documentation on | 
 | this site is appropriate for intermediate to advanced software | 
 | developers who are working in a Linux environment and are interested in | 
 | efficient software tracing. | 
 |  | 
 | For information on LTTng in general, visit the `LTTng | 
 | Project <https://lttng.org/lttng2.0>`__ site. You can find a "Getting | 
 | Started" link on this site that takes you to an LTTng Quick Start. | 
 |  | 
 | blktrace | 
 | ======== | 
 |  | 
 | blktrace is a tool for tracing and reporting low-level disk I/O. | 
 | blktrace provides the tracing half of the equation; its output can be | 
 | piped into the blkparse program, which renders the data in a | 
 | human-readable form and does some basic analysis: | 
 |  | 
 | blktrace Setup | 
 | -------------- | 
 |  | 
 | For this section, we'll assume you've already performed the basic setup | 
 | outlined in the ":ref:`profile-manual/intro:General Setup`" | 
 | section. | 
 |  | 
 | blktrace is an application that runs on the target system. You can run | 
 | the entire blktrace and blkparse pipeline on the target, or you can run | 
 | blktrace in 'listen' mode on the target and have blktrace and blkparse | 
 | collect and analyze the data on the host (see the | 
 | ":ref:`profile-manual/usage:Using blktrace Remotely`" section | 
 | below). For the rest of this section we assume you've ssh'ed to the host and | 
 | will be running blkrace on the target. | 
 |  | 
 | Basic blktrace Usage | 
 | -------------------- | 
 |  | 
 | To record a trace, simply run the 'blktrace' command, giving it the name | 
 | of the block device you want to trace activity on:: | 
 |  | 
 |    root@crownbay:~# blktrace /dev/sdc | 
 |  | 
 | In another shell, execute a workload you want to trace. :: | 
 |  | 
 |    root@crownbay:/media/sdc# rm linux-2.6.19.2.tar.bz2; wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2; sync | 
 |    Connecting to downloads.yoctoproject.org (140.211.169.59:80) | 
 |    linux-2.6.19.2.tar.b 100% \|*******************************\| 41727k 0:00:00 ETA | 
 |  | 
 | Press Ctrl-C in the blktrace shell to stop the trace. It | 
 | will display how many events were logged, along with the per-cpu file | 
 | sizes (blktrace records traces in per-cpu kernel buffers and simply | 
 | dumps them to userspace for blkparse to merge and sort later). :: | 
 |  | 
 |    ^C=== sdc === | 
 |     CPU  0:                 7082 events,      332 KiB data | 
 |     CPU  1:                 1578 events,       74 KiB data | 
 |     Total:                  8660 events (dropped 0),      406 KiB data | 
 |  | 
 | If you examine the files saved to disk, you see multiple files, one per CPU and | 
 | with the device name as the first part of the filename:: | 
 |  | 
 |    root@crownbay:~# ls -al | 
 |    drwxr-xr-x    6 root     root          1024 Oct 27 22:39 . | 
 |    drwxr-sr-x    4 root     root          1024 Oct 26 18:24 .. | 
 |    -rw-r--r--    1 root     root        339938 Oct 27 22:40 sdc.blktrace.0 | 
 |    -rw-r--r--    1 root     root         75753 Oct 27 22:40 sdc.blktrace.1 | 
 |  | 
 | To view the trace events, simply invoke 'blkparse' in the directory | 
 | containing the trace files, giving it the device name that forms the | 
 | first part of the filenames:: | 
 |  | 
 |    root@crownbay:~# blkparse sdc | 
 |  | 
 |     8,32   1        1     0.000000000  1225  Q  WS 3417048 + 8 [jbd2/sdc-8] | 
 |     8,32   1        2     0.000025213  1225  G  WS 3417048 + 8 [jbd2/sdc-8] | 
 |     8,32   1        3     0.000033384  1225  P   N [jbd2/sdc-8] | 
 |     8,32   1        4     0.000043301  1225  I  WS 3417048 + 8 [jbd2/sdc-8] | 
 |     8,32   1        0     0.000057270     0  m   N cfq1225 insert_request | 
 |     8,32   1        0     0.000064813     0  m   N cfq1225 add_to_rr | 
 |     8,32   1        5     0.000076336  1225  U   N [jbd2/sdc-8] 1 | 
 |     8,32   1        0     0.000088559     0  m   N cfq workload slice:150 | 
 |     8,32   1        0     0.000097359     0  m   N cfq1225 set_active wl_prio:0 wl_type:1 | 
 |     8,32   1        0     0.000104063     0  m   N cfq1225 Not idling. st->count:1 | 
 |     8,32   1        0     0.000112584     0  m   N cfq1225 fifo=  (null) | 
 |     8,32   1        0     0.000118730     0  m   N cfq1225 dispatch_insert | 
 |     8,32   1        0     0.000127390     0  m   N cfq1225 dispatched a request | 
 |     8,32   1        0     0.000133536     0  m   N cfq1225 activate rq, drv=1 | 
 |     8,32   1        6     0.000136889  1225  D  WS 3417048 + 8 [jbd2/sdc-8] | 
 |     8,32   1        7     0.000360381  1225  Q  WS 3417056 + 8 [jbd2/sdc-8] | 
 |     8,32   1        8     0.000377422  1225  G  WS 3417056 + 8 [jbd2/sdc-8] | 
 |     8,32   1        9     0.000388876  1225  P   N [jbd2/sdc-8] | 
 |     8,32   1       10     0.000397886  1225  Q  WS 3417064 + 8 [jbd2/sdc-8] | 
 |     8,32   1       11     0.000404800  1225  M  WS 3417064 + 8 [jbd2/sdc-8] | 
 |     8,32   1       12     0.000412343  1225  Q  WS 3417072 + 8 [jbd2/sdc-8] | 
 |     8,32   1       13     0.000416533  1225  M  WS 3417072 + 8 [jbd2/sdc-8] | 
 |     8,32   1       14     0.000422121  1225  Q  WS 3417080 + 8 [jbd2/sdc-8] | 
 |     8,32   1       15     0.000425194  1225  M  WS 3417080 + 8 [jbd2/sdc-8] | 
 |     8,32   1       16     0.000431968  1225  Q  WS 3417088 + 8 [jbd2/sdc-8] | 
 |     8,32   1       17     0.000435251  1225  M  WS 3417088 + 8 [jbd2/sdc-8] | 
 |     8,32   1       18     0.000440279  1225  Q  WS 3417096 + 8 [jbd2/sdc-8] | 
 |     8,32   1       19     0.000443911  1225  M  WS 3417096 + 8 [jbd2/sdc-8] | 
 |     8,32   1       20     0.000450336  1225  Q  WS 3417104 + 8 [jbd2/sdc-8] | 
 |     8,32   1       21     0.000454038  1225  M  WS 3417104 + 8 [jbd2/sdc-8] | 
 |     8,32   1       22     0.000462070  1225  Q  WS 3417112 + 8 [jbd2/sdc-8] | 
 |     8,32   1       23     0.000465422  1225  M  WS 3417112 + 8 [jbd2/sdc-8] | 
 |     8,32   1       24     0.000474222  1225  I  WS 3417056 + 64 [jbd2/sdc-8] | 
 |     8,32   1        0     0.000483022     0  m   N cfq1225 insert_request | 
 |     8,32   1       25     0.000489727  1225  U   N [jbd2/sdc-8] 1 | 
 |     8,32   1        0     0.000498457     0  m   N cfq1225 Not idling. st->count:1 | 
 |     8,32   1        0     0.000503765     0  m   N cfq1225 dispatch_insert | 
 |     8,32   1        0     0.000512914     0  m   N cfq1225 dispatched a request | 
 |     8,32   1        0     0.000518851     0  m   N cfq1225 activate rq, drv=2 | 
 |     . | 
 |     . | 
 |     . | 
 |     8,32   0        0    58.515006138     0  m   N cfq3551 complete rqnoidle 1 | 
 |     8,32   0     2024    58.516603269     3  C  WS 3156992 + 16 [0] | 
 |     8,32   0        0    58.516626736     0  m   N cfq3551 complete rqnoidle 1 | 
 |     8,32   0        0    58.516634558     0  m   N cfq3551 arm_idle: 8 group_idle: 0 | 
 |     8,32   0        0    58.516636933     0  m   N cfq schedule dispatch | 
 |     8,32   1        0    58.516971613     0  m   N cfq3551 slice expired t=0 | 
 |     8,32   1        0    58.516982089     0  m   N cfq3551 sl_used=13 disp=6 charge=13 iops=0 sect=80 | 
 |     8,32   1        0    58.516985511     0  m   N cfq3551 del_from_rr | 
 |     8,32   1        0    58.516990819     0  m   N cfq3551 put_queue | 
 |  | 
 |    CPU0 (sdc): | 
 |     Reads Queued:           0,        0KiB	 Writes Queued:         331,   26,284KiB | 
 |     Read Dispatches:        0,        0KiB	 Write Dispatches:      485,   40,484KiB | 
 |     Reads Requeued:         0		 Writes Requeued:         0 | 
 |     Reads Completed:        0,        0KiB	 Writes Completed:      511,   41,000KiB | 
 |     Read Merges:            0,        0KiB	 Write Merges:           13,      160KiB | 
 |     Read depth:             0        	 Write depth:             2 | 
 |     IO unplugs:            23        	 Timer unplugs:           0 | 
 |    CPU1 (sdc): | 
 |     Reads Queued:           0,        0KiB	 Writes Queued:         249,   15,800KiB | 
 |     Read Dispatches:        0,        0KiB	 Write Dispatches:       42,    1,600KiB | 
 |     Reads Requeued:         0		 Writes Requeued:         0 | 
 |     Reads Completed:        0,        0KiB	 Writes Completed:       16,    1,084KiB | 
 |     Read Merges:            0,        0KiB	 Write Merges:           40,      276KiB | 
 |     Read depth:             0        	 Write depth:             2 | 
 |     IO unplugs:            30        	 Timer unplugs:           1 | 
 |  | 
 |    Total (sdc): | 
 |     Reads Queued:           0,        0KiB	 Writes Queued:         580,   42,084KiB | 
 |     Read Dispatches:        0,        0KiB	 Write Dispatches:      527,   42,084KiB | 
 |     Reads Requeued:         0		 Writes Requeued:         0 | 
 |     Reads Completed:        0,        0KiB	 Writes Completed:      527,   42,084KiB | 
 |     Read Merges:            0,        0KiB	 Write Merges:           53,      436KiB | 
 |     IO unplugs:            53        	 Timer unplugs:           1 | 
 |  | 
 |    Throughput (R/W): 0KiB/s / 719KiB/s | 
 |    Events (sdc): 6,592 entries | 
 |    Skips: 0 forward (0 -   0.0%) | 
 |    Input file sdc.blktrace.0 added | 
 |    Input file sdc.blktrace.1 added | 
 |  | 
 | The report shows each event that was | 
 | found in the blktrace data, along with a summary of the overall block | 
 | I/O traffic during the run. You can look at the | 
 | `blkparse <https://linux.die.net/man/1/blkparse>`__ manpage to learn the | 
 | meaning of each field displayed in the trace listing. | 
 |  | 
 | Live Mode | 
 | ~~~~~~~~~ | 
 |  | 
 | blktrace and blkparse are designed from the ground up to be able to | 
 | operate together in a 'pipe mode' where the stdout of blktrace can be | 
 | fed directly into the stdin of blkparse:: | 
 |  | 
 |    root@crownbay:~# blktrace /dev/sdc -o - | blkparse -i - | 
 |  | 
 | This enables long-lived tracing sessions | 
 | to run without writing anything to disk, and allows the user to look for | 
 | certain conditions in the trace data in 'real-time' by viewing the trace | 
 | output as it scrolls by on the screen or by passing it along to yet | 
 | another program in the pipeline such as grep which can be used to | 
 | identify and capture conditions of interest. | 
 |  | 
 | There's actually another blktrace command that implements the above | 
 | pipeline as a single command, so the user doesn't have to bother typing | 
 | in the above command sequence:: | 
 |  | 
 |    root@crownbay:~# btrace /dev/sdc | 
 |  | 
 | Using blktrace Remotely | 
 | ~~~~~~~~~~~~~~~~~~~~~~~ | 
 |  | 
 | Because blktrace traces block I/O and at the same time normally writes | 
 | its trace data to a block device, and in general because it's not really | 
 | a great idea to make the device being traced the same as the device the | 
 | tracer writes to, blktrace provides a way to trace without perturbing | 
 | the traced device at all by providing native support for sending all | 
 | trace data over the network. | 
 |  | 
 | To have blktrace operate in this mode, start blktrace on the target | 
 | system being traced with the -l option, along with the device to trace:: | 
 |  | 
 |    root@crownbay:~# blktrace -l /dev/sdc | 
 |    server: waiting for connections... | 
 |  | 
 | On the host system, use the -h option to connect to the target system, | 
 | also passing it the device to trace:: | 
 |  | 
 |    $ blktrace -d /dev/sdc -h 192.168.1.43 | 
 |    blktrace: connecting to 192.168.1.43 | 
 |    blktrace: connected! | 
 |  | 
 | On the target system, you should see this:: | 
 |  | 
 |    server: connection from 192.168.1.43 | 
 |  | 
 | In another shell, execute a workload you want to trace. :: | 
 |  | 
 |    root@crownbay:/media/sdc# rm linux-2.6.19.2.tar.bz2; wget &YOCTO_DL_URL;/mirror/sources/linux-2.6.19.2.tar.bz2; sync | 
 |    Connecting to downloads.yoctoproject.org (140.211.169.59:80) | 
 |    linux-2.6.19.2.tar.b 100% \|*******************************\| 41727k 0:00:00 ETA | 
 |  | 
 | When it's done, do a Ctrl-C on the host system to stop the | 
 | trace:: | 
 |  | 
 |    ^C=== sdc === | 
 |     CPU  0:                 7691 events,      361 KiB data | 
 |     CPU  1:                 4109 events,      193 KiB data | 
 |     Total:                 11800 events (dropped 0),      554 KiB data | 
 |  | 
 | On the target system, you should also see a trace summary for the trace | 
 | just ended:: | 
 |  | 
 |    server: end of run for 192.168.1.43:sdc | 
 |    === sdc === | 
 |     CPU  0:                 7691 events,      361 KiB data | 
 |     CPU  1:                 4109 events,      193 KiB data | 
 |     Total:                 11800 events (dropped 0),      554 KiB data | 
 |  | 
 | The blktrace instance on the host will | 
 | save the target output inside a hostname-timestamp directory:: | 
 |  | 
 |    $ ls -al | 
 |    drwxr-xr-x   10 root     root          1024 Oct 28 02:40 . | 
 |    drwxr-sr-x    4 root     root          1024 Oct 26 18:24 .. | 
 |    drwxr-xr-x    2 root     root          1024 Oct 28 02:40 192.168.1.43-2012-10-28-02:40:56 | 
 |  | 
 | cd into that directory to see the output files:: | 
 |  | 
 |    $ ls -l | 
 |    -rw-r--r--    1 root     root        369193 Oct 28 02:44 sdc.blktrace.0 | 
 |    -rw-r--r--    1 root     root        197278 Oct 28 02:44 sdc.blktrace.1 | 
 |  | 
 | And run blkparse on the host system using the device name:: | 
 |  | 
 |    $ blkparse sdc | 
 |  | 
 |     8,32   1        1     0.000000000  1263  Q  RM 6016 + 8 [ls] | 
 |     8,32   1        0     0.000036038     0  m   N cfq1263 alloced | 
 |     8,32   1        2     0.000039390  1263  G  RM 6016 + 8 [ls] | 
 |     8,32   1        3     0.000049168  1263  I  RM 6016 + 8 [ls] | 
 |     8,32   1        0     0.000056152     0  m   N cfq1263 insert_request | 
 |     8,32   1        0     0.000061600     0  m   N cfq1263 add_to_rr | 
 |     8,32   1        0     0.000075498     0  m   N cfq workload slice:300 | 
 |     . | 
 |     . | 
 |     . | 
 |     8,32   0        0   177.266385696     0  m   N cfq1267 arm_idle: 8 group_idle: 0 | 
 |     8,32   0        0   177.266388140     0  m   N cfq schedule dispatch | 
 |     8,32   1        0   177.266679239     0  m   N cfq1267 slice expired t=0 | 
 |     8,32   1        0   177.266689297     0  m   N cfq1267 sl_used=9 disp=6 charge=9 iops=0 sect=56 | 
 |     8,32   1        0   177.266692649     0  m   N cfq1267 del_from_rr | 
 |     8,32   1        0   177.266696560     0  m   N cfq1267 put_queue | 
 |  | 
 |    CPU0 (sdc): | 
 |     Reads Queued:           0,        0KiB	 Writes Queued:         270,   21,708KiB | 
 |     Read Dispatches:       59,    2,628KiB	 Write Dispatches:      495,   39,964KiB | 
 |     Reads Requeued:         0		 Writes Requeued:         0 | 
 |     Reads Completed:       90,    2,752KiB	 Writes Completed:      543,   41,596KiB | 
 |     Read Merges:            0,        0KiB	 Write Merges:            9,      344KiB | 
 |     Read depth:             2        	 Write depth:             2 | 
 |     IO unplugs:            20        	 Timer unplugs:           1 | 
 |    CPU1 (sdc): | 
 |     Reads Queued:         688,    2,752KiB	 Writes Queued:         381,   20,652KiB | 
 |     Read Dispatches:       31,      124KiB	 Write Dispatches:       59,    2,396KiB | 
 |     Reads Requeued:         0		 Writes Requeued:         0 | 
 |     Reads Completed:        0,        0KiB	 Writes Completed:       11,      764KiB | 
 |     Read Merges:          598,    2,392KiB	 Write Merges:           88,      448KiB | 
 |     Read depth:             2        	 Write depth:             2 | 
 |     IO unplugs:            52        	 Timer unplugs:           0 | 
 |  | 
 |    Total (sdc): | 
 |     Reads Queued:         688,    2,752KiB	 Writes Queued:         651,   42,360KiB | 
 |     Read Dispatches:       90,    2,752KiB	 Write Dispatches:      554,   42,360KiB | 
 |     Reads Requeued:         0		 Writes Requeued:         0 | 
 |     Reads Completed:       90,    2,752KiB	 Writes Completed:      554,   42,360KiB | 
 |     Read Merges:          598,    2,392KiB	 Write Merges:           97,      792KiB | 
 |     IO unplugs:            72        	 Timer unplugs:           1 | 
 |  | 
 |    Throughput (R/W): 15KiB/s / 238KiB/s | 
 |    Events (sdc): 9,301 entries | 
 |    Skips: 0 forward (0 -   0.0%) | 
 |  | 
 | You should see the trace events and summary just as you would have if you'd run | 
 | the same command on the target. | 
 |  | 
 | Tracing Block I/O via 'ftrace' | 
 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
 |  | 
 | It's also possible to trace block I/O using only | 
 | :ref:`profile-manual/usage:The 'trace events' Subsystem`, which | 
 | can be useful for casual tracing if you don't want to bother dealing with the | 
 | userspace tools. | 
 |  | 
 | To enable tracing for a given device, use /sys/block/xxx/trace/enable, | 
 | where xxx is the device name. This for example enables tracing for | 
 | /dev/sdc:: | 
 |  | 
 |    root@crownbay:/sys/kernel/debug/tracing# echo 1 > /sys/block/sdc/trace/enable | 
 |  | 
 | Once you've selected the device(s) you want | 
 | to trace, selecting the 'blk' tracer will turn the blk tracer on:: | 
 |  | 
 |    root@crownbay:/sys/kernel/debug/tracing# cat available_tracers | 
 |    blk function_graph function nop | 
 |  | 
 |    root@crownbay:/sys/kernel/debug/tracing# echo blk > current_tracer | 
 |  | 
 | Execute the workload you're interested in:: | 
 |  | 
 |    root@crownbay:/sys/kernel/debug/tracing# cat /media/sdc/testfile.txt | 
 |  | 
 | And look at the output (note here that we're using 'trace_pipe' instead of | 
 | trace to capture this trace --- this allows us to wait around on the pipe | 
 | for data to appear):: | 
 |  | 
 |    root@crownbay:/sys/kernel/debug/tracing# cat trace_pipe | 
 |                cat-3587  [001] d..1  3023.276361:   8,32   Q   R 1699848 + 8 [cat] | 
 |                cat-3587  [001] d..1  3023.276410:   8,32   m   N cfq3587 alloced | 
 |                cat-3587  [001] d..1  3023.276415:   8,32   G   R 1699848 + 8 [cat] | 
 |                cat-3587  [001] d..1  3023.276424:   8,32   P   N [cat] | 
 |                cat-3587  [001] d..2  3023.276432:   8,32   I   R 1699848 + 8 [cat] | 
 |                cat-3587  [001] d..1  3023.276439:   8,32   m   N cfq3587 insert_request | 
 |                cat-3587  [001] d..1  3023.276445:   8,32   m   N cfq3587 add_to_rr | 
 |                cat-3587  [001] d..2  3023.276454:   8,32   U   N [cat] 1 | 
 |                cat-3587  [001] d..1  3023.276464:   8,32   m   N cfq workload slice:150 | 
 |                cat-3587  [001] d..1  3023.276471:   8,32   m   N cfq3587 set_active wl_prio:0 wl_type:2 | 
 |                cat-3587  [001] d..1  3023.276478:   8,32   m   N cfq3587 fifo=  (null) | 
 |                cat-3587  [001] d..1  3023.276483:   8,32   m   N cfq3587 dispatch_insert | 
 |                cat-3587  [001] d..1  3023.276490:   8,32   m   N cfq3587 dispatched a request | 
 |                cat-3587  [001] d..1  3023.276497:   8,32   m   N cfq3587 activate rq, drv=1 | 
 |                cat-3587  [001] d..2  3023.276500:   8,32   D   R 1699848 + 8 [cat] | 
 |  | 
 | And this turns off tracing for the specified device:: | 
 |  | 
 |    root@crownbay:/sys/kernel/debug/tracing# echo 0 > /sys/block/sdc/trace/enable | 
 |  | 
 | blktrace Documentation | 
 | ---------------------- | 
 |  | 
 | Online versions of the man pages for the commands discussed in this | 
 | section can be found here: | 
 |  | 
 | -  https://linux.die.net/man/8/blktrace | 
 |  | 
 | -  https://linux.die.net/man/1/blkparse | 
 |  | 
 | -  https://linux.die.net/man/8/btrace | 
 |  | 
 | The above manpages, along with manpages for the other blktrace utilities | 
 | (btt, blkiomon, etc) can be found in the /doc directory of the blktrace | 
 | tools git repo:: | 
 |  | 
 |    $ git clone git://git.kernel.dk/blktrace.git |