Pull tracing updates from Steven Rostedt: - Add function names as a way to filter function addresses - Add sample module to test ftrace ops and dynamic trampolines - Allow stack traces to be passed from beginning event to end event for synthetic events. This will allow seeing the stack trace of when a task is scheduled out and recorded when it gets scheduled back in. - Add trace event helper __get_buf() to use as a temporary buffer when printing out trace event output. - Add kernel command line to create trace instances on boot up. - Add enabling of events to instances created at boot up. - Add trace_array_puts() to write into instances. - Allow boot instances to take a snapshot at the end of boot up. - Allow live patch modules to include trace events - Minor fixes and clean ups * tag 'trace-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: (31 commits) tracing: Remove unnecessary NULL assignment tracepoint: Allow livepatch module add trace event tracing: Always use canonical ftrace path tracing/histogram: Fix stacktrace histogram Documententation tracing/histogram: Fix stacktrace key tracing/histogram: Fix a few problems with stacktrace variable printing tracing: Add BUILD_BUG() to make sure stacktrace fits in strings tracing/histogram: Don't use strlen to find length of stacktrace variables tracing: Allow boot instances to have snapshot buffers tracing: Add trace_array_puts() to write into instance tracing: Add enabling of events to boot instances tracing: Add creation of instances at boot command line tracing: Fix trace_event_raw_event_synth() if else statement samples: ftrace: Make some global variables static ftrace: sample: avoid open-coded 64-bit division samples: ftrace: Include the nospec-branch.h only for x86 tracing: Acquire buffer from temparary trace sequence tracing/histogram: Wrap remaining shell snippets in code blocks tracing/osnoise: No need for schedule_hrtimeout range bpf/tracing: Use stage6 of tracing to not duplicate macros ...
Unified · Split
| @@ -1509,6 +1509,15 @@ · 1508 unmodified lines | |||
| 1509 | boot up that is likely to be overridden by user space | 1509 | boot up that is likely to be overridden by user space |
| 1510 | start up functionality. | 1510 | start up functionality. |
| 1511 | 1511 | ||
| 1512 | Optionally, the snapshot can also be defined for a tracing | ||
| 1513 | instance that was created by the trace_instance= command | ||
| 1514 | line parameter. | ||
| 1515 | |||
| 1516 | trace_instance=foo,sched_switch ftrace_boot_snapshot=foo | ||
| 1517 | |||
| 1518 | The above will cause the "foo" tracing instance to trigger | ||
| 1519 | a snapshot at the end of boot up. | ||
| 1520 | |||
| 1512 | ftrace_dump_on_oops[=orig_cpu] | 1521 | ftrace_dump_on_oops[=orig_cpu] |
| 1513 | [FTRACE] will dump the trace buffers on oops. | 1522 | [FTRACE] will dump the trace buffers on oops. |
| 1514 | If no parameter is passed, ftrace will dump | 1523 | If no parameter is passed, ftrace will dump |
| @@ -6283,6 +6292,26 @@ · 4768 unmodified lines | |||
| 6283 | comma-separated list of trace events to enable. See | 6292 | comma-separated list of trace events to enable. See |
| 6284 | also Documentation/trace/events.rst | 6293 | also Documentation/trace/events.rst |
| 6285 | 6294 | ||
| 6295 | trace_instance=[instance-info] | ||
| 6296 | [FTRACE] Create a ring buffer instance early in boot up. | ||
| 6297 | This will be listed in: | ||
| 6298 | |||
| 6299 | /sys/kernel/tracing/instances | ||
| 6300 | |||
| 6301 | Events can be enabled at the time the instance is created | ||
| 6302 | via: | ||
| 6303 | |||
| 6304 | trace_instance=<name>,<system1>:<event1>,<system2>:<event2> | ||
| 6305 | |||
| 6306 | Note, the "<system*>:" portion is optional if the event is | ||
| 6307 | unique. | ||
| 6308 | |||
| 6309 | trace_instance=foo,sched:sched_switch,irq_handler_entry,initcall | ||
| 6310 | |||
| 6311 | will enable the "sched_switch" event (note, the "sched:" is optional, and | ||
| 6312 | the same thing would happen if it was left off). The irq_handler_entry | ||
| 6313 | event, and all events under the "initcall" system. | ||
| 6314 | |||
| 6286 | trace_options=[option-list] | 6315 | trace_options=[option-list] |
| 6287 | [FTRACE] Enable or disable tracer options at boot. | 6316 | [FTRACE] Enable or disable tracer options at boot. |
| 6288 | The option-list is a comma delimited list of options | 6317 | The option-list is a comma delimited list of options |
| @@ -207,6 +207,18 @@ field name:: · 206 unmodified lines | |||
| 207 | As the kernel will have to know how to retrieve the memory that the pointer | 207 | As the kernel will have to know how to retrieve the memory that the pointer |
| 208 | is at from user space. | 208 | is at from user space. |
| 209 | 209 | ||
| 210 | You can convert any long type to a function address and search by function name:: | ||
| 211 | |||
| 212 | call_site.function == security_prepare_creds | ||
| 213 | |||
| 214 | The above will filter when the field "call_site" falls on the address within | ||
| 215 | "security_prepare_creds". That is, it will compare the value of "call_site" and | ||
| 216 | the filter will return true if it is greater than or equal to the start of | ||
| 217 | the function "security_prepare_creds" and less than the end of that function. | ||
| 218 | |||
| 219 | The ".function" postfix can only be attached to values of size long, and can only | ||
| 220 | be compared with "==" or "!=". | ||
| 221 | |||
| 210 | 5.2 Setting filters | 222 | 5.2 Setting filters |
| 211 | ------------------- | 223 | ------------------- |
| 212 | 224 | ||
| @@ -81,6 +81,7 @@ Documentation written by Tom Zanussi · 80 unmodified lines | |||
| 81 | .usecs display a common_timestamp in microseconds | 81 | .usecs display a common_timestamp in microseconds |
| 82 | .percent display a number of percentage value | 82 | .percent display a number of percentage value |
| 83 | .graph display a bar-graph of a value | 83 | .graph display a bar-graph of a value |
| 84 | .stacktrace display as a stacktrace (must by a long[] type) | ||
| 84 | ============= ================================================= | 85 | ============= ================================================= |
| 85 | 86 | ||
| 86 | Note that in general the semantics of a given field aren't | 87 | Note that in general the semantics of a given field aren't |
| @@ -1786,6 +1787,8 @@ or assigned to a variable and referenced in a subsequent expression:: · 1699 unmodified lines | |||
| 1786 | # echo 'hist:keys=next_pid:us_per_sec=1000000 ...' >> event/trigger | 1787 | # echo 'hist:keys=next_pid:us_per_sec=1000000 ...' >> event/trigger |
| 1787 | # echo 'hist:keys=next_pid:timestamp_secs=common_timestamp/$us_per_sec ...' >> event/trigger | 1788 | # echo 'hist:keys=next_pid:timestamp_secs=common_timestamp/$us_per_sec ...' >> event/trigger |
| 1788 | 1789 | ||
| 1790 | Variables can even hold stacktraces, which are useful with synthetic events. | ||
| 1791 | |||
| 1789 | 2.2.2 Synthetic Events | 1792 | 2.2.2 Synthetic Events |
| 1790 | ---------------------- | 1793 | ---------------------- |
| 1791 | 1794 | ||
| @@ -1861,7 +1864,7 @@ A histogram can now be defined for the new synthetic event:: · 69 unmodified lines | |||
| 1861 | The above shows the latency "lat" in a power of 2 grouping. | 1864 | The above shows the latency "lat" in a power of 2 grouping. |
| 1862 | 1865 | ||
| 1863 | Like any other event, once a histogram is enabled for the event, the | 1866 | Like any other event, once a histogram is enabled for the event, the |
| 1864 | output can be displayed by reading the event's 'hist' file. | 1867 | output can be displayed by reading the event's 'hist' file:: |
| 1865 | 1868 | ||
| 1866 | # cat /sys/kernel/tracing/events/synthetic/wakeup_latency/hist | 1869 | # cat /sys/kernel/tracing/events/synthetic/wakeup_latency/hist |
| 1867 | 1870 | ||
| @@ -1908,7 +1911,7 @@ output can be displayed by reading the event's 'hist' file. · 40 unmodified lines | |||
| 1908 | 1911 | ||
| 1909 | 1912 | ||
| 1910 | The latency values can also be grouped linearly by a given size with | 1913 | The latency values can also be grouped linearly by a given size with |
| 1911 | the ".buckets" modifier and specify a size (in this case groups of 10). | 1914 | the ".buckets" modifier and specify a size (in this case groups of 10):: |
| 1912 | 1915 | ||
| 1913 | # echo 'hist:keys=pid,prio,lat.buckets=10:sort=lat' >> \ | 1916 | # echo 'hist:keys=pid,prio,lat.buckets=10:sort=lat' >> \ |
| 1914 | /sys/kernel/tracing/events/synthetic/wakeup_latency/trigger | 1917 | /sys/kernel/tracing/events/synthetic/wakeup_latency/trigger |
| @@ -1940,6 +1943,157 @@ the ".buckets" modifier and specify a size (in this case groups of 10). · 25 unmodified lines | |||
| 1940 | Entries: 16 | 1943 | Entries: 16 |
| 1941 | Dropped: 0 | 1944 | Dropped: 0 |
| 1942 | 1945 | ||
| 1946 | To save stacktraces, create a synthetic event with a field of type "unsigned long[]" | ||
| 1947 | or even just "long[]". For example, to see how long a task is blocked in an | ||
| 1948 | uninterruptible state:: | ||
| 1949 | |||
| 1950 | # cd /sys/kernel/tracing | ||
| 1951 | # echo 's:block_lat pid_t pid; u64 delta; unsigned long[] stack;' > dynamic_events | ||
| 1952 | # echo 'hist:keys=next_pid:ts=common_timestamp.usecs,st=stacktrace if prev_state == 2' >> events/sched/sched_switch/trigger | ||
| 1953 | # echo 'hist:keys=prev_pid:delta=common_timestamp.usecs-$ts,s=$st:onmax($delta).trace(block_lat,prev_pid,$delta,$s)' >> events/sched/sched_switch/trigger | ||
| 1954 | # echo 1 > events/synthetic/block_lat/enable | ||
| 1955 | # cat trace | ||
| 1956 | |||
| 1957 | # tracer: nop | ||
| 1958 | # | ||
| 1959 | # entries-in-buffer/entries-written: 2/2 #P:8 | ||
| 1960 | # | ||
| 1961 | # _-----=> irqs-off/BH-disabled | ||
| 1962 | # / _----=> need-resched | ||
| 1963 | # | / _---=> hardirq/softirq | ||
| 1964 | # || / _--=> preempt-depth | ||
| 1965 | # ||| / _-=> migrate-disable | ||
| 1966 | # |||| / delay | ||
| 1967 | # TASK-PID CPU# ||||| TIMESTAMP FUNCTION | ||
| 1968 | # | | | ||||| | | | ||
| 1969 | <idle>-0 [005] d..4. 521.164922: block_lat: pid=0 delta=8322 stack=STACK: | ||
| 1970 | => __schedule+0x448/0x7b0 | ||
| 1971 | => schedule+0x5a/0xb0 | ||
| 1972 | => io_schedule+0x42/0x70 | ||
| 1973 | => bit_wait_io+0xd/0x60 | ||
| 1974 | => __wait_on_bit+0x4b/0x140 | ||
| 1975 | => out_of_line_wait_on_bit+0x91/0xb0 | ||
| 1976 | => jbd2_journal_commit_transaction+0x1679/0x1a70 | ||
| 1977 | => kjournald2+0xa9/0x280 | ||
| 1978 | => kthread+0xe9/0x110 | ||
| 1979 | => ret_from_fork+0x2c/0x50 | ||
| 1980 | |||
| 1981 | <...>-2 [004] d..4. 525.184257: block_lat: pid=2 delta=76 stack=STACK: | ||
| 1982 | => __schedule+0x448/0x7b0 | ||
| 1983 | => schedule+0x5a/0xb0 | ||
| 1984 | => schedule_timeout+0x11a/0x150 | ||
| 1985 | => wait_for_completion_killable+0x144/0x1f0 | ||
| 1986 | => __kthread_create_on_node+0xe7/0x1e0 | ||
| 1987 | => kthread_create_on_node+0x51/0x70 | ||
| 1988 | => create_worker+0xcc/0x1a0 | ||
| 1989 | => worker_thread+0x2ad/0x380 | ||
| 1990 | => kthread+0xe9/0x110 | ||
| 1991 | => ret_from_fork+0x2c/0x50 | ||
| 1992 | |||
| 1993 | A synthetic event that has a stacktrace field may use it as a key in | ||
| 1994 | histogram:: | ||
| 1995 | |||
| 1996 | # echo 'hist:keys=delta.buckets=100,stack.stacktrace:sort=delta' > events/synthetic/block_lat/trigger | ||
| 1997 | # cat events/synthetic/block_lat/hist | ||
| 1998 | |||
| 1999 | # event histogram | ||
| 2000 | # | ||
| 2001 | # trigger info: hist:keys=delta.buckets=100,stack.stacktrace:vals=hitcount:sort=delta.buckets=100:size=2048 [active] | ||
| 2002 | # | ||
| 2003 | { delta: ~ 0-99, stack.stacktrace __schedule+0xa19/0x1520 | ||
| 2004 | schedule+0x6b/0x110 | ||
| 2005 | io_schedule+0x46/0x80 | ||
| 2006 | bit_wait_io+0x11/0x80 | ||
| 2007 | __wait_on_bit+0x4e/0x120 | ||
| 2008 | out_of_line_wait_on_bit+0x8d/0xb0 | ||
| 2009 | __wait_on_buffer+0x33/0x40 | ||
| 2010 | jbd2_journal_commit_transaction+0x155a/0x19b0 | ||
| 2011 | kjournald2+0xab/0x270 | ||
| 2012 | kthread+0xfa/0x130 | ||
| 2013 | ret_from_fork+0x29/0x50 | ||
| 2014 | } hitcount: 1 | ||
| 2015 | { delta: ~ 0-99, stack.stacktrace __schedule+0xa19/0x1520 | ||
| 2016 | schedule+0x6b/0x110 | ||
| 2017 | io_schedule+0x46/0x80 | ||
| 2018 | rq_qos_wait+0xd0/0x170 | ||
| 2019 | wbt_wait+0x9e/0xf0 | ||
| 2020 | __rq_qos_throttle+0x25/0x40 | ||
| 2021 | blk_mq_submit_bio+0x2c3/0x5b0 | ||
| 2022 | __submit_bio+0xff/0x190 | ||
| 2023 | submit_bio_noacct_nocheck+0x25b/0x2b0 | ||
| 2024 | submit_bio_noacct+0x20b/0x600 | ||
| 2025 | submit_bio+0x28/0x90 | ||
| 2026 | ext4_bio_write_page+0x1e0/0x8c0 | ||
| 2027 | mpage_submit_page+0x60/0x80 | ||
| 2028 | mpage_process_page_bufs+0x16c/0x180 | ||
| 2029 | mpage_prepare_extent_to_map+0x23f/0x530 | ||
| 2030 | } hitcount: 1 | ||
| 2031 | { delta: ~ 0-99, stack.stacktrace __schedule+0xa19/0x1520 | ||
| 2032 | schedule+0x6b/0x110 | ||
| 2033 | schedule_hrtimeout_range_clock+0x97/0x110 | ||
| 2034 | schedule_hrtimeout_range+0x13/0x20 | ||
| 2035 | usleep_range_state+0x65/0x90 | ||
| 2036 | __intel_wait_for_register+0x1c1/0x230 [i915] | ||
| 2037 | intel_psr_wait_for_idle_locked+0x171/0x2a0 [i915] | ||
| 2038 | intel_pipe_update_start+0x169/0x360 [i915] | ||
| 2039 | intel_update_crtc+0x112/0x490 [i915] | ||
| 2040 | skl_commit_modeset_enables+0x199/0x600 [i915] | ||
| 2041 | intel_atomic_commit_tail+0x7c4/0x1080 [i915] | ||
| 2042 | intel_atomic_commit_work+0x12/0x20 [i915] | ||
| 2043 | process_one_work+0x21c/0x3f0 | ||
| 2044 | worker_thread+0x50/0x3e0 | ||
| 2045 | kthread+0xfa/0x130 | ||
| 2046 | } hitcount: 3 | ||
| 2047 | { delta: ~ 0-99, stack.stacktrace __schedule+0xa19/0x1520 | ||
| 2048 | schedule+0x6b/0x110 | ||
| 2049 | schedule_timeout+0x11e/0x160 | ||
| 2050 | __wait_for_common+0x8f/0x190 | ||
| 2051 | wait_for_completion+0x24/0x30 | ||
| 2052 | __flush_work.isra.0+0x1cc/0x360 | ||
| 2053 | flush_work+0xe/0x20 | ||
| 2054 | drm_mode_rmfb+0x18b/0x1d0 [drm] | ||
| 2055 | drm_mode_rmfb_ioctl+0x10/0x20 [drm] | ||
| 2056 | drm_ioctl_kernel+0xb8/0x150 [drm] | ||
| 2057 | drm_ioctl+0x243/0x560 [drm] | ||
| 2058 | __x64_sys_ioctl+0x92/0xd0 | ||
| 2059 | do_syscall_64+0x59/0x90 | ||
| 2060 | entry_SYSCALL_64_after_hwframe+0x72/0xdc | ||
| 2061 | } hitcount: 1 | ||
| 2062 | { delta: ~ 0-99, stack.stacktrace __schedule+0xa19/0x1520 | ||
| 2063 | schedule+0x6b/0x110 | ||
| 2064 | schedule_timeout+0x87/0x160 | ||
| 2065 | __wait_for_common+0x8f/0x190 | ||
| 2066 | wait_for_completion_timeout+0x1d/0x30 | ||
| 2067 | drm_atomic_helper_wait_for_flip_done+0x57/0x90 [drm_kms_helper] | ||
| 2068 | intel_atomic_commit_tail+0x8ce/0x1080 [i915] | ||
| 2069 | intel_atomic_commit_work+0x12/0x20 [i915] | ||
| 2070 | process_one_work+0x21c/0x3f0 | ||
| 2071 | worker_thread+0x50/0x3e0 | ||
| 2072 | kthread+0xfa/0x130 | ||
| 2073 | ret_from_fork+0x29/0x50 | ||
| 2074 | } hitcount: 1 | ||
| 2075 | { delta: ~ 100-199, stack.stacktrace __schedule+0xa19/0x1520 | ||
| 2076 | schedule+0x6b/0x110 | ||
| 2077 | schedule_hrtimeout_range_clock+0x97/0x110 | ||
| 2078 | schedule_hrtimeout_range+0x13/0x20 | ||
| 2079 | usleep_range_state+0x65/0x90 | ||
| 2080 | pci_set_low_power_state+0x17f/0x1f0 | ||
| 2081 | pci_set_power_state+0x49/0x250 | ||
| 2082 | pci_finish_runtime_suspend+0x4a/0x90 | ||
| 2083 | pci_pm_runtime_suspend+0xcb/0x1b0 | ||
| 2084 | __rpm_callback+0x48/0x120 | ||
| 2085 | rpm_callback+0x67/0x70 | ||
| 2086 | rpm_suspend+0x167/0x780 | ||
| 2087 | rpm_idle+0x25a/0x380 | ||
| 2088 | pm_runtime_work+0x93/0xc0 | ||
| 2089 | process_one_work+0x21c/0x3f0 | ||
| 2090 | } hitcount: 1 | ||
| 2091 | |||
| 2092 | Totals: | ||
| 2093 | Hits: 10 | ||
| 2094 | Entries: 7 | ||
| 2095 | Dropped: 0 | ||
| 2096 | |||
| 1943 | 2.2.3 Hist trigger 'handlers' and 'actions' | 2097 | 2.2.3 Hist trigger 'handlers' and 'actions' |
| 1944 | ------------------------------------------- | 2098 | ------------------------------------------- |
| 1945 | 2099 | ||
| @@ -2054,11 +2208,11 @@ The following commonly-used handler.action pairs are available: · 108 unmodified lines | |||
| 2054 | wakeup_new_test($testpid) if comm=="cyclictest"' >> \ | 2208 | wakeup_new_test($testpid) if comm=="cyclictest"' >> \ |
| 2055 | /sys/kernel/tracing/events/sched/sched_wakeup_new/trigger | 2209 | /sys/kernel/tracing/events/sched/sched_wakeup_new/trigger |
| 2056 | 2210 | ||
| 2057 | Or, equivalently, using the 'trace' keyword syntax: | 2211 | Or, equivalently, using the 'trace' keyword syntax:: |
| 2058 | 2212 | ||
| 2059 | # echo 'hist:keys=$testpid:testpid=pid:onmatch(sched.sched_wakeup_new).\ | 2213 | # echo 'hist:keys=$testpid:testpid=pid:onmatch(sched.sched_wakeup_new).\ |
| 2060 | trace(wakeup_new_test,$testpid) if comm=="cyclictest"' >> \ | 2214 | trace(wakeup_new_test,$testpid) if comm=="cyclictest"' >> \ |
| 2061 | /sys/kernel/tracing/events/sched/sched_wakeup_new/trigger | 2215 | /sys/kernel/tracing/events/sched/sched_wakeup_new/trigger |
| 2062 | 2216 | ||
| 2063 | Creating and displaying a histogram based on those events is now | 2217 | Creating and displaying a histogram based on those events is now |
| 2064 | just a matter of using the fields and new synthetic event in the | 2218 | just a matter of using the fields and new synthetic event in the |
| @@ -2191,48 +2345,48 @@ The following commonly-used handler.action pairs are available: · 126 unmodified lines | |||
| 2191 | resulting latency, stored in wakeup_lat, exceeds the current | 2345 | resulting latency, stored in wakeup_lat, exceeds the current |
| 2192 | maximum latency, a snapshot is taken. As part of the setup, all | 2346 | maximum latency, a snapshot is taken. As part of the setup, all |
| 2193 | the scheduler events are also enabled, which are the events that | 2347 | the scheduler events are also enabled, which are the events that |
| 2194 | will show up in the snapshot when it is taken at some point: | 2348 | will show up in the snapshot when it is taken at some point:: |
| 2195 | 2349 | ||
| 2196 | # echo 1 > /sys/kernel/tracing/events/sched/enable | 2350 | # echo 1 > /sys/kernel/tracing/events/sched/enable |
| 2197 | 2351 | ||
| 2198 | # echo 'hist:keys=pid:ts0=common_timestamp.usecs \ | 2352 | # echo 'hist:keys=pid:ts0=common_timestamp.usecs \ |
| 2199 | if comm=="cyclictest"' >> \ | 2353 | if comm=="cyclictest"' >> \ |
| 2200 | /sys/kernel/tracing/events/sched/sched_waking/trigger | 2354 | /sys/kernel/tracing/events/sched/sched_waking/trigger |
| 2201 | 2355 | ||
| 2202 | # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0: \ | 2356 | # echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0: \ |
| 2203 | onmax($wakeup_lat).save(next_prio,next_comm,prev_pid,prev_prio, \ | 2357 | onmax($wakeup_lat).save(next_prio,next_comm,prev_pid,prev_prio, \ |
| 2204 | prev_comm):onmax($wakeup_lat).snapshot() \ | 2358 | prev_comm):onmax($wakeup_lat).snapshot() \ |
| 2205 | if next_comm=="cyclictest"' >> \ | 2359 | if next_comm=="cyclictest"' >> \ |
| 2206 | /sys/kernel/tracing/events/sched/sched_switch/trigger | 2360 | /sys/kernel/tracing/events/sched/sched_switch/trigger |
| 2207 | 2361 | ||
| 2208 | When the histogram is displayed, for each bucket the max value | 2362 | When the histogram is displayed, for each bucket the max value |
| 2209 | and the saved values corresponding to the max are displayed | 2363 | and the saved values corresponding to the max are displayed |
| 2210 | following the rest of the fields. | 2364 | following the rest of the fields. |
| 2211 | 2365 | ||
| 2212 | If a snapshot was taken, there is also a message indicating that, | 2366 | If a snapshot was taken, there is also a message indicating that, |
| 2213 | along with the value and event that triggered the global maximum: | 2367 | along with the value and event that triggered the global maximum:: |
| 2214 | 2368 | ||
| 2215 | # cat /sys/kernel/tracing/events/sched/sched_switch/hist | 2369 | # cat /sys/kernel/tracing/events/sched/sched_switch/hist |
| 2216 | { next_pid: 2101 } hitcount: 200 | 2370 | { next_pid: 2101 } hitcount: 200 |
| 2217 | max: 52 next_prio: 120 next_comm: cyclictest \ | 2371 | max: 52 next_prio: 120 next_comm: cyclictest \ |
| 2218 | prev_pid: 0 prev_prio: 120 prev_comm: swapper/6 | 2372 | prev_pid: 0 prev_prio: 120 prev_comm: swapper/6 |
| 2219 | 2373 | ||
| 2220 | { next_pid: 2103 } hitcount: 1326 | 2374 | { next_pid: 2103 } hitcount: 1326 |
| 2221 | max: 572 next_prio: 19 next_comm: cyclictest \ | 2375 | max: 572 next_prio: 19 next_comm: cyclictest \ |
| 2222 | prev_pid: 0 prev_prio: 120 prev_comm: swapper/1 | 2376 | prev_pid: 0 prev_prio: 120 prev_comm: swapper/1 |
| 2223 | 2377 | ||
| 2224 | { next_pid: 2102 } hitcount: 1982 \ | 2378 | { next_pid: 2102 } hitcount: 1982 \ |
| 2225 | max: 74 next_prio: 19 next_comm: cyclictest \ | 2379 | max: 74 next_prio: 19 next_comm: cyclictest \ |
| 2226 | prev_pid: 0 prev_prio: 120 prev_comm: swapper/5 | 2380 | prev_pid: 0 prev_prio: 120 prev_comm: swapper/5 |
| 2227 | 2381 | ||
| 2228 | Snapshot taken (see tracing/snapshot). Details: | 2382 | Snapshot taken (see tracing/snapshot). Details: |
| 2229 | triggering value { onmax($wakeup_lat) }: 572 \ | 2383 | triggering value { onmax($wakeup_lat) }: 572 \ |
| 2230 | triggered by event with key: { next_pid: 2103 } | 2384 | triggered by event with key: { next_pid: 2103 } |
| 2231 | 2385 | ||
| 2232 | Totals: | 2386 | Totals: |
| 2233 | Hits: 3508 | 2387 | Hits: 3508 |
| 2234 | Entries: 3 | 2388 | Entries: 3 |
| 2235 | Dropped: 0 | 2389 | Dropped: 0 |
| 2236 | 2390 | ||
| 2237 | In the above case, the event that triggered the global maximum has | 2391 | In the above case, the event that triggered the global maximum has |
| 2238 | the key with next_pid == 2103. If you look at the bucket that has | 2392 | the key with next_pid == 2103. If you look at the bucket that has |
| @@ -2310,15 +2464,15 @@ The following commonly-used handler.action pairs are available: · 71 unmodified lines | |||
| 2310 | $cwnd variable. If the value has changed, a snapshot is taken. | 2464 | $cwnd variable. If the value has changed, a snapshot is taken. |
| 2311 | As part of the setup, all the scheduler and tcp events are also | 2465 | As part of the setup, all the scheduler and tcp events are also |
| 2312 | enabled, which are the events that will show up in the snapshot | 2466 | enabled, which are the events that will show up in the snapshot |
| 2313 | when it is taken at some point: | 2467 | when it is taken at some point:: |
| 2314 | 2468 | ||
| 2315 | # echo 1 > /sys/kernel/tracing/events/sched/enable | 2469 | # echo 1 > /sys/kernel/tracing/events/sched/enable |
| 2316 | # echo 1 > /sys/kernel/tracing/events/tcp/enable | 2470 | # echo 1 > /sys/kernel/tracing/events/tcp/enable |
| 2317 | 2471 | ||
| 2318 | # echo 'hist:keys=dport:cwnd=snd_cwnd: \ | 2472 | # echo 'hist:keys=dport:cwnd=snd_cwnd: \ |
| 2319 | onchange($cwnd).save(snd_wnd,srtt,rcv_wnd): \ | 2473 | onchange($cwnd).save(snd_wnd,srtt,rcv_wnd): \ |
| 2320 | onchange($cwnd).snapshot()' >> \ | 2474 | onchange($cwnd).snapshot()' >> \ |
| 2321 | /sys/kernel/tracing/events/tcp/tcp_probe/trigger | 2475 | /sys/kernel/tracing/events/tcp/tcp_probe/trigger |
| 2322 | 2476 | ||
| 2323 | When the histogram is displayed, for each bucket the tracked value | 2477 | When the histogram is displayed, for each bucket the tracked value |
| 2324 | and the saved values corresponding to that value are displayed | 2478 | and the saved values corresponding to that value are displayed |
| @@ -2341,10 +2495,10 @@ The following commonly-used handler.action pairs are available: · 16 unmodified lines | |||
| 2341 | { dport: 443 } hitcount: 211 | 2495 | { dport: 443 } hitcount: 211 |
| 2342 | changed: 10 snd_wnd: 26960 srtt: 17379 rcv_wnd: 28800 | 2496 | changed: 10 snd_wnd: 26960 srtt: 17379 rcv_wnd: 28800 |
| 2343 | 2497 | ||
| 2344 | Snapshot taken (see tracing/snapshot). Details:: | 2498 | Snapshot taken (see tracing/snapshot). Details: |
| 2345 | 2499 | ||
| 2346 | triggering value { onchange($cwnd) }: 10 | 2500 | triggering value { onchange($cwnd) }: 10 |
| 2347 | triggered by event with key: { dport: 80 } | 2501 | triggered by event with key: { dport: 80 } |
| 2348 | 2502 | ||
| 2349 | Totals: | 2503 | Totals: |
| 2350 | Hits: 414 | 2504 | Hits: 414 |
| @@ -297,7 +297,7 @@ bool mac_pton(const char *s, u8 *mac); · 296 unmodified lines | |||
| 297 | * | 297 | * |
| 298 | * Use tracing_on/tracing_off when you want to quickly turn on or off | 298 | * Use tracing_on/tracing_off when you want to quickly turn on or off |
| 299 | * tracing. It simply enables or disables the recording of the trace events. | 299 | * tracing. It simply enables or disables the recording of the trace events. |
| 300 | * This also corresponds to the user space /sys/kernel/debug/tracing/tracing_on | 300 | * This also corresponds to the user space /sys/kernel/tracing/tracing_on |
| 301 | * file, which gives a means for the kernel and userspace to interact. | 301 | * file, which gives a means for the kernel and userspace to interact. |
| 302 | * Place a tracing_off() in the kernel where you want tracing to end. | 302 | * Place a tracing_off() in the kernel where you want tracing to end. |
| 303 | * From user space, examine the trace, and then echo 1 > tracing_on | 303 | * From user space, examine the trace, and then echo 1 > tracing_on |
| @@ -33,6 +33,18 @@ struct trace_array; · 32 unmodified lines | |||
| 33 | int register_ftrace_export(struct trace_export *export); | 33 | int register_ftrace_export(struct trace_export *export); |
| 34 | int unregister_ftrace_export(struct trace_export *export); | 34 | int unregister_ftrace_export(struct trace_export *export); |
| 35 | 35 | ||
| 36 | /** | ||
| 37 | * trace_array_puts - write a constant string into the trace buffer. | ||
| 38 | * @tr: The trace array to write to | ||
| 39 | * @str: The constant string to write | ||
| 40 | */ | ||
| 41 | #define trace_array_puts(tr, str) \ | ||
| 42 | ({ \ | ||
| 43 | str ? __trace_array_puts(tr, _THIS_IP_, str, strlen(str)) : -1; \ | ||
| 44 | }) | ||
| 45 | int __trace_array_puts(struct trace_array *tr, unsigned long ip, | ||
| 46 | const char *str, int size); | ||
| 47 | |||
| 36 | void trace_printk_init_buffers(void); | 48 | void trace_printk_init_buffers(void); |
| 37 | __printf(3, 4) | 49 | __printf(3, 4) |
| 38 | int trace_array_printk(struct trace_array *tr, unsigned long ip, | 50 | int trace_array_printk(struct trace_array *tr, unsigned long ip, |
| @@ -95,6 +95,7 @@ extern void trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp, · 94 unmodified lines | |||
| 95 | extern int trace_seq_hex_dump(struct trace_seq *s, const char *prefix_str, | 95 | extern int trace_seq_hex_dump(struct trace_seq *s, const char *prefix_str, |
| 96 | int prefix_type, int rowsize, int groupsize, | 96 | int prefix_type, int rowsize, int groupsize, |
| 97 | const void *buf, size_t len, bool ascii); | 97 | const void *buf, size_t len, bool ascii); |
| 98 | char *trace_seq_acquire(struct trace_seq *s, unsigned int len); | ||
| 98 | 99 | ||
| 99 | #else /* CONFIG_TRACING */ | 100 | #else /* CONFIG_TRACING */ |
| 100 | static inline __printf(2, 3) | 101 | static inline __printf(2, 3) |
| @@ -139,6 +140,10 @@ static inline int trace_seq_path(struct trace_seq *s, const struct path *path) · 38 unmodified lines | |||
| 139 | { | 140 | { |
| 140 | return 0; | 141 | return 0; |
| 141 | } | 142 | } |
| 143 | static inline char *trace_seq_acquire(struct trace_seq *s, unsigned int len) | ||
| 144 | { | ||
| 145 | return NULL; | ||
| 146 | } | ||
| 142 | #endif /* CONFIG_TRACING */ | 147 | #endif /* CONFIG_TRACING */ |
| 143 | 148 | ||
| 144 | #endif /* _LINUX_TRACE_SEQ_H */ | 149 | #endif /* _LINUX_TRACE_SEQ_H */ |
| @@ -482,7 +482,7 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) · 481 unmodified lines | |||
| 482 | * * This is how the trace record is structured and will | 482 | * * This is how the trace record is structured and will |
| 483 | * * be saved into the ring buffer. These are the fields | 483 | * * be saved into the ring buffer. These are the fields |
| 484 | * * that will be exposed to user-space in | 484 | * * that will be exposed to user-space in |
| 485 | * * /sys/kernel/debug/tracing/events/<*>/format. | 485 | * * /sys/kernel/tracing/events/<*>/format. |
| 486 | * * | 486 | * * |
| 487 | * * The declared 'local variable' is called '__entry' | 487 | * * The declared 'local variable' is called '__entry' |
| 488 | * * | 488 | * * |
| @@ -542,7 +542,7 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) · 53 unmodified lines | |||
| 542 | * tracepoint callback (this is used by programmatic plugins and | 542 | * tracepoint callback (this is used by programmatic plugins and |
| 543 | * can also by used by generic instrumentation like SystemTap), and | 543 | * can also by used by generic instrumentation like SystemTap), and |
| 544 | * it is also used to expose a structured trace record in | 544 | * it is also used to expose a structured trace record in |
| 545 | * /sys/kernel/debug/tracing/events/. | 545 | * /sys/kernel/tracing/events/. |
| 546 | * | 546 | * |
| 547 | * A set of (un)registration functions can be passed to the variant | 547 | * A set of (un)registration functions can be passed to the variant |
| 548 | * TRACE_EVENT_FN to perform any (un)registration work. | 548 | * TRACE_EVENT_FN to perform any (un)registration work. |
| @@ -4,50 +4,7 @@ · 3 unmodified lines | |||
| 4 | 4 | ||
| 5 | #ifdef CONFIG_BPF_EVENTS | 5 | #ifdef CONFIG_BPF_EVENTS |
| 6 | 6 | ||
| 7 | #undef __entry | 7 | #include "stages/stage6_event_callback.h" |
| 8 | #define __entry entry | ||
| 9 | |||
| 10 | #undef __get_dynamic_array | ||
| 11 | #define __get_dynamic_array(field) \ | ||
| 12 | ((void *)__entry + (__entry->__data_loc_##field & 0xffff)) | ||
| 13 | |||
| 14 | #undef __get_dynamic_array_len | ||
| 15 | #define __get_dynamic_array_len(field) \ | ||
| 16 | ((__entry->__data_loc_##field >> 16) & 0xffff) | ||
| 17 | |||
| 18 | #undef __get_str | ||
| 19 | #define __get_str(field) ((char *)__get_dynamic_array(field)) | ||
| 20 | |||
| 21 | #undef __get_bitmask | ||
| 22 | #define __get_bitmask(field) (char *)__get_dynamic_array(field) | ||
| 23 | |||
| 24 | #undef __get_cpumask | ||
| 25 | #define __get_cpumask(field) (char *)__get_dynamic_array(field) | ||
| 26 | |||
| 27 | #undef __get_sockaddr | ||
| 28 | #define __get_sockaddr(field) ((struct sockaddr *)__get_dynamic_array(field)) | ||
| 29 | |||
| 30 | #undef __get_rel_dynamic_array | ||
| 31 | #define __get_rel_dynamic_array(field) \ | ||
| 32 | ((void *)(&__entry->__rel_loc_##field) + \ | ||
| 33 | sizeof(__entry->__rel_loc_##field) + \ | ||
| 34 | (__entry->__rel_loc_##field & 0xffff)) | ||
| 35 | |||
| 36 | #undef __get_rel_dynamic_array_len | ||
| 37 | #define __get_rel_dynamic_array_len(field) \ | ||
| 38 | ((__entry->__rel_loc_##field >> 16) & 0xffff) | ||
| 39 | |||
| 40 | #undef __get_rel_str | ||
| 41 | #define __get_rel_str(field) ((char *)__get_rel_dynamic_array(field)) | ||
| 42 | |||
| 43 | #undef __get_rel_bitmask | ||
| 44 | #define __get_rel_bitmask(field) (char *)__get_rel_dynamic_array(field) | ||
| 45 | |||
| 46 | #undef __get_rel_cpumask | ||
| 47 | #define __get_rel_cpumask(field) (char *)__get_rel_dynamic_array(field) | ||
| 48 | |||
| 49 | #undef __get_rel_sockaddr | ||
| 50 | #define __get_rel_sockaddr(field) ((struct sockaddr *)__get_rel_dynamic_array(field)) | ||
| 51 | 8 | ||
| 52 | #undef __perf_count | 9 | #undef __perf_count |
| 53 | #define __perf_count(c) (c) | 10 | #define __perf_count(c) (c) |
| @@ -4,51 +4,7 @@ · 3 unmodified lines | |||
| 4 | 4 | ||
| 5 | #ifdef CONFIG_PERF_EVENTS | 5 | #ifdef CONFIG_PERF_EVENTS |
| 6 | 6 | ||
| 7 | #undef __entry | 7 | #include "stages/stage6_event_callback.h" |
| 8 | #define __entry entry | ||
| 9 | |||
| 10 | #undef __get_dynamic_array | ||
| 11 | #define __get_dynamic_array(field) \ | ||
| 12 | ((void *)__entry + (__entry->__data_loc_##field & 0xffff)) | ||
| 13 | |||
| 14 | #undef __get_dynamic_array_len | ||
| 15 | #define __get_dynamic_array_len(field) \ | ||
| 16 | ((__entry->__data_loc_##field >> 16) & 0xffff) | ||
| 17 | |||
| 18 | #undef __get_str | ||
| 19 | #define __get_str(field) ((char *)__get_dynamic_array(field)) | ||
| 20 | |||
| 21 | #undef __get_bitmask | ||
| 22 | #define __get_bitmask(field) (char *)__get_dynamic_array(field) | ||
| 23 | |||
| 24 | #undef __get_cpumask | ||
| 25 | #define __get_cpumask(field) (char *)__get_dynamic_array(field) | ||
| 26 | |||
| 27 | #undef __get_sockaddr | ||
| 28 | #define __get_sockaddr(field) ((struct sockaddr *)__get_dynamic_array(field)) | ||
| 29 | |||
| 30 | #undef __get_rel_dynamic_array | ||
| 31 | #define __get_rel_dynamic_array(field) \ | ||
| 32 | ((void *)__entry + \ | ||
| 33 | offsetof(typeof(*__entry), __rel_loc_##field) + \ | ||
| 34 | sizeof(__entry->__rel_loc_##field) + \ | ||
| 35 | (__entry->__rel_loc_##field & 0xffff)) | ||
| 36 | |||
| 37 | #undef __get_rel_dynamic_array_len | ||
| 38 | #define __get_rel_dynamic_array_len(field) \ | ||
| 39 | ((__entry->__rel_loc_##field >> 16) & 0xffff) | ||
| 40 | |||
| 41 | #undef __get_rel_str | ||
| 42 | #define __get_rel_str(field) ((char *)__get_rel_dynamic_array(field)) | ||
| 43 | |||
| 44 | #undef __get_rel_bitmask | ||
| 45 | #define __get_rel_bitmask(field) (char *)__get_rel_dynamic_array(field) | ||
| 46 | |||
| 47 | #undef __get_rel_cpumask | ||
| 48 | #define __get_rel_cpumask(field) (char *)__get_rel_dynamic_array(field) | ||
| 49 | |||
| 50 | #undef __get_rel_sockaddr | ||
| 51 | #define __get_rel_sockaddr(field) ((struct sockaddr *)__get_rel_dynamic_array(field)) | ||
| 52 | 8 | ||
| 53 | #undef __perf_count | 9 | #undef __perf_count |
| 54 | #define __perf_count(c) (__count = (c)) | 10 | #define __perf_count(c) (__count = (c)) |
| @@ -139,3 +139,6 @@ · 138 unmodified lines | |||
| 139 | u64 ____val = (u64)(value); \ | 139 | u64 ____val = (u64)(value); \ |
| 140 | (u32) do_div(____val, NSEC_PER_SEC); \ | 140 | (u32) do_div(____val, NSEC_PER_SEC); \ |
| 141 | }) | 141 | }) |
| 142 | |||
| 143 | #undef __get_buf | ||
| 144 | #define __get_buf(len) trace_seq_acquire(p, (len)) | ||
| @@ -2,6 +2,9 @@ · 1 unmodified line | |||
| 2 | 2 | ||
| 3 | /* Stage 6 definitions for creating trace events */ | 3 | /* Stage 6 definitions for creating trace events */ |
| 4 | 4 | ||
| 5 | /* Reuse some of the stage 3 macros */ | ||
| 6 | #include "stage3_trace_output.h" | ||
| 7 | |||
| 5 | #undef __entry | 8 | #undef __entry |
| 6 | #define __entry entry | 9 | #define __entry entry |
| 7 | 10 | ||
| @@ -23,6 +23,7 @@ · 22 unmodified lines | |||
| 23 | #undef __get_rel_sockaddr | 23 | #undef __get_rel_sockaddr |
| 24 | #undef __print_array | 24 | #undef __print_array |
| 25 | #undef __print_hex_dump | 25 | #undef __print_hex_dump |
| 26 | #undef __get_buf | ||
| 26 | 27 | ||
| 27 | /* | 28 | /* |
| 28 | * The below is not executed in the kernel. It is only what is | 29 | * The below is not executed in the kernel. It is only what is |
| @@ -242,7 +242,7 @@ config DYNAMIC_FTRACE · 241 unmodified lines | |||
| 242 | enabled, and the functions not enabled will not affect | 242 | enabled, and the functions not enabled will not affect |
| 243 | performance of the system. | 243 | performance of the system. |
| 244 | 244 | ||
| 245 | See the files in /sys/kernel/debug/tracing: | 245 | See the files in /sys/kernel/tracing: |
| 246 | available_filter_functions | 246 | available_filter_functions |
| 247 | set_ftrace_filter | 247 | set_ftrace_filter |
| 248 | set_ftrace_notrace | 248 | set_ftrace_notrace |
| @@ -306,7 +306,7 @@ config STACK_TRACER · 57 unmodified lines | |||
| 306 | select KALLSYMS | 306 | select KALLSYMS |
| 307 | help | 307 | help |
| 308 | This special tracer records the maximum stack footprint of the | 308 | This special tracer records the maximum stack footprint of the |
| 309 | kernel and displays it in /sys/kernel/debug/tracing/stack_trace. | 309 | kernel and displays it in /sys/kernel/tracing/stack_trace. |
| 310 | 310 | ||
| 311 | This tracer works by hooking into every function call that the | 311 | This tracer works by hooking into every function call that the |
| 312 | kernel executes, and keeping a maximum stack depth value and | 312 | kernel executes, and keeping a maximum stack depth value and |
| @@ -346,7 +346,7 @@ config IRQSOFF_TRACER · 33 unmodified lines | |||
| 346 | disabled by default and can be runtime (re-)started | 346 | disabled by default and can be runtime (re-)started |
| 347 | via: | 347 | via: |
| 348 | 348 | ||
| 349 | echo 0 > /sys/kernel/debug/tracing/tracing_max_latency | 349 | echo 0 > /sys/kernel/tracing/tracing_max_latency |
| 350 | 350 | ||
| 351 | (Note that kernel size and overhead increase with this option | 351 | (Note that kernel size and overhead increase with this option |
| 352 | enabled. This option and the preempt-off timing option can be | 352 | enabled. This option and the preempt-off timing option can be |
| @@ -370,7 +370,7 @@ config PREEMPT_TRACER · 17 unmodified lines | |||
| 370 | disabled by default and can be runtime (re-)started | 370 | disabled by default and can be runtime (re-)started |
| 371 | via: | 371 | via: |
| 372 | 372 | ||
| 373 | echo 0 > /sys/kernel/debug/tracing/tracing_max_latency | 373 | echo 0 > /sys/kernel/tracing/tracing_max_latency |
| 374 | 374 | ||
| 375 | (Note that kernel size and overhead increase with this option | 375 | (Note that kernel size and overhead increase with this option |
| 376 | enabled. This option and the irqs-off timing option can be | 376 | enabled. This option and the irqs-off timing option can be |
| @@ -522,7 +522,7 @@ config TRACER_SNAPSHOT · 145 unmodified lines | |||
| 522 | Allow tracing users to take snapshot of the current buffer using the | 522 | Allow tracing users to take snapshot of the current buffer using the |
| 523 | ftrace interface, e.g.: | 523 | ftrace interface, e.g.: |
| 524 | 524 | ||
| 525 | echo 1 > /sys/kernel/debug/tracing/snapshot | 525 | echo 1 > /sys/kernel/tracing/snapshot |
| 526 | cat snapshot | 526 | cat snapshot |
| 527 | 527 | ||
| 528 | config TRACER_SNAPSHOT_PER_CPU_SWAP | 528 | config TRACER_SNAPSHOT_PER_CPU_SWAP |
| @@ -534,7 +534,7 @@ config TRACER_SNAPSHOT_PER_CPU_SWAP · 5 unmodified lines | |||
| 534 | full swap (all buffers). If this is set, then the following is | 534 | full swap (all buffers). If this is set, then the following is |
| 535 | allowed: | 535 | allowed: |
| 536 | 536 | ||
| 537 | echo 1 > /sys/kernel/debug/tracing/per_cpu/cpu2/snapshot | 537 | echo 1 > /sys/kernel/tracing/per_cpu/cpu2/snapshot |
| 538 | 538 | ||
| 539 | After which, only the tracing buffer for CPU 2 was swapped with | 539 | After which, only the tracing buffer for CPU 2 was swapped with |
| 540 | the main tracing buffer, and the other CPU buffers remain the same. | 540 | the main tracing buffer, and the other CPU buffers remain the same. |
| @@ -581,7 +581,7 @@ config PROFILE_ANNOTATED_BRANCHES · 40 unmodified lines | |||
| 581 | This tracer profiles all likely and unlikely macros | 581 | This tracer profiles all likely and unlikely macros |
| 582 | in the kernel. It will display the results in: | 582 | in the kernel. It will display the results in: |
| 583 | 583 | ||
| 584 | /sys/kernel/debug/tracing/trace_stat/branch_annotated | 584 | /sys/kernel/tracing/trace_stat/branch_annotated |
| 585 | 585 | ||
| 586 | Note: this will add a significant overhead; only turn this | 586 | Note: this will add a significant overhead; only turn this |
| 587 | on if you need to profile the system's use of these macros. | 587 | on if you need to profile the system's use of these macros. |
| @@ -594,7 +594,7 @@ config PROFILE_ALL_BRANCHES · 6 unmodified lines | |||
| 594 | taken in the kernel is recorded whether it hit or miss. | 594 | taken in the kernel is recorded whether it hit or miss. |
| 595 | The results will be displayed in: | 595 | The results will be displayed in: |
| 596 | 596 | ||
| 597 | /sys/kernel/debug/tracing/trace_stat/branch_all | 597 | /sys/kernel/tracing/trace_stat/branch_all |
| 598 | 598 | ||
| 599 | This option also enables the likely/unlikely profiler. | 599 | This option also enables the likely/unlikely profiler. |
| 600 | 600 | ||
| @@ -645,8 +645,8 @@ config BLK_DEV_IO_TRACE · 44 unmodified lines | |||
| 645 | Tracing also is possible using the ftrace interface, e.g.: | 645 | Tracing also is possible using the ftrace interface, e.g.: |
| 646 | 646 | ||
| 647 | echo 1 > /sys/block/sda/sda1/trace/enable | 647 | echo 1 > /sys/block/sda/sda1/trace/enable |
| 648 | echo blk > /sys/kernel/debug/tracing/current_tracer | 648 | echo blk > /sys/kernel/tracing/current_tracer |
| 649 | cat /sys/kernel/debug/tracing/trace_pipe | 649 | cat /sys/kernel/tracing/trace_pipe |
| 650 | 650 | ||
| 651 | If unsure, say N. | 651 | If unsure, say N. |
| 652 | 652 | ||
| @@ -21,7 +21,7 @@ · 20 unmodified lines | |||
| 21 | * Then: | 21 | * Then: |
| 22 | * | 22 | * |
| 23 | * # insmod kernel/trace/kprobe_event_gen_test.ko | 23 | * # insmod kernel/trace/kprobe_event_gen_test.ko |
| 24 | * # cat /sys/kernel/debug/tracing/trace | 24 | * # cat /sys/kernel/tracing/trace |
| 25 | * | 25 | * |
| 26 | * You should see many instances of the "gen_kprobe_test" and | 26 | * You should see many instances of the "gen_kprobe_test" and |
| 27 | * "gen_kretprobe_test" events in the trace buffer. | 27 | * "gen_kretprobe_test" events in the trace buffer. |
| @@ -2864,7 +2864,7 @@ rb_check_timestamp(struct ring_buffer_per_cpu *cpu_buffer, · 2863 unmodified lines | |||
| 2864 | sched_clock_stable() ? "" : | 2864 | sched_clock_stable() ? "" : |
| 2865 | "If you just came from a suspend/resume,\n" | 2865 | "If you just came from a suspend/resume,\n" |
| 2866 | "please switch to the trace global clock:\n" | 2866 | "please switch to the trace global clock:\n" |
| 2867 | " echo global > /sys/kernel/debug/tracing/trace_clock\n" | 2867 | " echo global > /sys/kernel/tracing/trace_clock\n" |
| 2868 | "or add trace_clock=global to the kernel command line\n"); | 2868 | "or add trace_clock=global to the kernel command line\n"); |
| 2869 | } | 2869 | } |
| 2870 | 2870 | ||
| @@ -5604,11 +5604,16 @@ EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page); · 2733 unmodified lines | |||
| 5604 | */ | 5604 | */ |
| 5605 | void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu, void *data) | 5605 | void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu, void *data) |
| 5606 | { | 5606 | { |
| 5607 | struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu]; | 5607 | struct ring_buffer_per_cpu *cpu_buffer; |
| 5608 | struct buffer_data_page *bpage = data; | 5608 | struct buffer_data_page *bpage = data; |
| 5609 | struct page *page = virt_to_page(bpage); | 5609 | struct page *page = virt_to_page(bpage); |
| 5610 | unsigned long flags; | 5610 | unsigned long flags; |
| 5611 | 5611 | ||
| 5612 | if (!buffer || !buffer->buffers || !buffer->buffers[cpu]) | ||
| 5613 | return; | ||
| 5614 | |||
| 5615 | cpu_buffer = buffer->buffers[cpu]; | ||
| 5616 | |||
| 5612 | /* If the page is still in use someplace else, we can't reuse it */ | 5617 | /* If the page is still in use someplace else, we can't reuse it */ |
| 5613 | if (page_ref_count(page) > 1) | 5618 | if (page_ref_count(page) > 1) |
| 5614 | goto out; | 5619 | goto out; |
| @@ -22,7 +22,7 @@ · 21 unmodified lines | |||
| 22 | * Then: | 22 | * Then: |
| 23 | * | 23 | * |
| 24 | * # insmod kernel/trace/synth_event_gen_test.ko | 24 | * # insmod kernel/trace/synth_event_gen_test.ko |
| 25 | * # cat /sys/kernel/debug/tracing/trace | 25 | * # cat /sys/kernel/tracing/trace |
| 26 | * | 26 | * |
| 27 | * You should see several events in the trace buffer - | 27 | * You should see several events in the trace buffer - |
| 28 | * "create_synth_test", "empty_synth_test", and several instances of | 28 | * "create_synth_test", "empty_synth_test", and several instances of |
| @@ -49,6 +49,8 @@ · 48 unmodified lines | |||
| 49 | #include <linux/irq_work.h> | 49 | #include <linux/irq_work.h> |
| 50 | #include <linux/workqueue.h> | 50 | #include <linux/workqueue.h> |
| 51 | 51 | ||
| 52 | #include <asm/setup.h> /* COMMAND_LINE_SIZE */ | ||
| 53 | |||
| 52 | #include "trace.h" | 54 | #include "trace.h" |
| 53 | #include "trace_output.h" | 55 | #include "trace_output.h" |
| 54 | 56 | ||
| @@ -186,6 +188,12 @@ static char *default_bootup_tracer; · 131 unmodified lines | |||
| 186 | static bool allocate_snapshot; | 188 | static bool allocate_snapshot; |
| 187 | static bool snapshot_at_boot; | 189 | static bool snapshot_at_boot; |
| 188 | 190 | ||
| 191 | static char boot_instance_info[COMMAND_LINE_SIZE] __initdata; | ||
| 192 | static int boot_instance_index; | ||
| 193 | |||
| 194 | static char boot_snapshot_info[COMMAND_LINE_SIZE] __initdata; | ||
| 195 | static int boot_snapshot_index; | ||
| 196 | |||
| 189 | static int __init set_cmdline_ftrace(char *str) | 197 | static int __init set_cmdline_ftrace(char *str) |
| 190 | { | 198 | { |
| 191 | strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); | 199 | strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); |
| @@ -222,9 +230,22 @@ __setup("traceoff_on_warning", stop_trace_on_warning); · 30 unmodified lines | |||
| 222 | 230 | ||
| 223 | static int __init boot_alloc_snapshot(char *str) | 231 | static int __init boot_alloc_snapshot(char *str) |
| 224 | { | 232 | { |
| 225 | allocate_snapshot = true; | 233 | char *slot = boot_snapshot_info + boot_snapshot_index; |
| 226 | /* We also need the main ring buffer expanded */ | 234 | int left = sizeof(boot_snapshot_info) - boot_snapshot_index; |
| 227 | ring_buffer_expanded = true; | 235 | int ret; |
| 236 | |||
| 237 | if (str[0] == '=') { | ||
| 238 | str++; | ||
| 239 | if (strlen(str) >= left) | ||
| 240 | return -1; | ||
| 241 | |||
| 242 | ret = snprintf(slot, left, "%s\t", str); | ||
| 243 | boot_snapshot_index += ret; | ||
| 244 | } else { | ||
| 245 | allocate_snapshot = true; | ||
| 246 | /* We also need the main ring buffer expanded */ | ||
| 247 | ring_buffer_expanded = true; | ||
| 248 | } | ||
| 228 | return 1; | 249 | return 1; |
| 229 | } | 250 | } |
| 230 | __setup("alloc_snapshot", boot_alloc_snapshot); | 251 | __setup("alloc_snapshot", boot_alloc_snapshot); |
| @@ -239,6 +260,23 @@ static int __init boot_snapshot(char *str) · 8 unmodified lines | |||
| 239 | __setup("ftrace_boot_snapshot", boot_snapshot); | 260 | __setup("ftrace_boot_snapshot", boot_snapshot); |
| 240 | 261 | ||
| 241 | 262 | ||
| 263 | static int __init boot_instance(char *str) | ||
| 264 | { | ||
| 265 | char *slot = boot_instance_info + boot_instance_index; | ||
| 266 | int left = sizeof(boot_instance_info) - boot_instance_index; | ||
| 267 | int ret; | ||
| 268 | |||
| 269 | if (strlen(str) >= left) | ||
| 270 | return -1; | ||
| 271 | |||
| 272 | ret = snprintf(slot, left, "%s\t", str); | ||
| 273 | boot_instance_index += ret; | ||
| 274 | |||
| 275 | return 1; | ||
| 276 | } | ||
| 277 | __setup("trace_instance=", boot_instance); | ||
| 278 | |||
| 279 | |||
| 242 | static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata; | 280 | static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata; |
| 243 | 281 | ||
| 244 | static int __init set_trace_boot_options(char *str) | 282 | static int __init set_trace_boot_options(char *str) |
| @@ -1001,13 +1039,8 @@ __buffer_unlock_commit(struct trace_buffer *buffer, struct ring_buffer_event *ev · 756 unmodified lines | |||
| 1001 | ring_buffer_unlock_commit(buffer); | 1039 | ring_buffer_unlock_commit(buffer); |
| 1002 | } | 1040 | } |
| 1003 | 1041 | ||
| 1004 | /** | 1042 | int __trace_array_puts(struct trace_array *tr, unsigned long ip, |
| 1005 | * __trace_puts - write a constant string into the trace buffer. | 1043 | const char *str, int size) |
| 1006 | * @ip: The address of the caller | ||
| 1007 | * @str: The constant string to write | ||
| 1008 | * @size: The size of the string. | ||
| 1009 | */ | ||
| 1010 | int __trace_puts(unsigned long ip, const char *str, int size) | ||
| 1011 | { | 1044 | { |
| 1012 | struct ring_buffer_event *event; | 1045 | struct ring_buffer_event *event; |
| 1013 | struct trace_buffer *buffer; | 1046 | struct trace_buffer *buffer; |
| @@ -1015,7 +1048,7 @@ int __trace_puts(unsigned long ip, const char *str, int size) · 1 unmodified line | |||
| 1015 | unsigned int trace_ctx; | 1048 | unsigned int trace_ctx; |
| 1016 | int alloc; | 1049 | int alloc; |
| 1017 | 1050 | ||
| 1018 | if (!(global_trace.trace_flags & TRACE_ITER_PRINTK)) | 1051 | if (!(tr->trace_flags & TRACE_ITER_PRINTK)) |
| 1019 | return 0; | 1052 | return 0; |
| 1020 | 1053 | ||
| 1021 | if (unlikely(tracing_selftest_running || tracing_disabled)) | 1054 | if (unlikely(tracing_selftest_running || tracing_disabled)) |
| @@ -1024,7 +1057,7 @@ int __trace_puts(unsigned long ip, const char *str, int size) · 2 unmodified lines | |||
| 1024 | alloc = sizeof(*entry) + size + 2; /* possible \n added */ | 1057 | alloc = sizeof(*entry) + size + 2; /* possible \n added */ |
| 1025 | 1058 | ||
| 1026 | trace_ctx = tracing_gen_ctx(); | 1059 | trace_ctx = tracing_gen_ctx(); |
| 1027 | buffer = global_trace.array_buffer.buffer; | 1060 | buffer = tr->array_buffer.buffer; |
| 1028 | ring_buffer_nest_start(buffer); | 1061 | ring_buffer_nest_start(buffer); |
| 1029 | event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc, | 1062 | event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc, |
| 1030 | trace_ctx); | 1063 | trace_ctx); |
| @@ -1046,11 +1079,23 @@ int __trace_puts(unsigned long ip, const char *str, int size) · 15 unmodified lines | |||
| 1046 | entry->buf[size] = '\0'; | 1079 | entry->buf[size] = '\0'; |
| 1047 | 1080 | ||
| 1048 | __buffer_unlock_commit(buffer, event); | 1081 | __buffer_unlock_commit(buffer, event); |
| 1049 | ftrace_trace_stack(&global_trace, buffer, trace_ctx, 4, NULL); | 1082 | ftrace_trace_stack(tr, buffer, trace_ctx, 4, NULL); |
| 1050 | out: | 1083 | out: |
| 1051 | ring_buffer_nest_end(buffer); | 1084 | ring_buffer_nest_end(buffer); |
| 1052 | return size; | 1085 | return size; |
| 1053 | } | 1086 | } |
| 1087 | EXPORT_SYMBOL_GPL(__trace_array_puts); | ||
| 1088 | |||
| 1089 | /** | ||
| 1090 | * __trace_puts - write a constant string into the trace buffer. | ||
| 1091 | * @ip: The address of the caller | ||
| 1092 | * @str: The constant string to write | ||
| 1093 | * @size: The size of the string. | ||
| 1094 | */ | ||
| 1095 | int __trace_puts(unsigned long ip, const char *str, int size) | ||
| 1096 | { | ||
| 1097 | return __trace_array_puts(&global_trace, ip, str, size); | ||
| 1098 | } | ||
| 1054 | EXPORT_SYMBOL_GPL(__trace_puts); | 1099 | EXPORT_SYMBOL_GPL(__trace_puts); |
| 1055 | 1100 | ||
| 1056 | /** | 1101 | /** |
| @@ -1142,7 +1187,7 @@ void tracing_snapshot_instance(struct trace_array *tr) · 85 unmodified lines | |||
| 1142 | * | 1187 | * |
| 1143 | * Note, make sure to allocate the snapshot with either | 1188 | * Note, make sure to allocate the snapshot with either |
| 1144 | * a tracing_snapshot_alloc(), or by doing it manually | 1189 | * a tracing_snapshot_alloc(), or by doing it manually |
| 1145 | * with: echo 1 > /sys/kernel/debug/tracing/snapshot | 1190 | * with: echo 1 > /sys/kernel/tracing/snapshot |
| 1146 | * | 1191 | * |
| 1147 | * If the snapshot buffer is not allocated, it will stop tracing. | 1192 | * If the snapshot buffer is not allocated, it will stop tracing. |
| 1148 | * Basically making a permanent snapshot. | 1193 | * Basically making a permanent snapshot. |
| @@ -5760,7 +5805,7 @@ static const char readme_msg[] = · 4611 unmodified lines | |||
| 5760 | #ifdef CONFIG_SYNTH_EVENTS | 5805 | #ifdef CONFIG_SYNTH_EVENTS |
| 5761 | " events/synthetic_events\t- Create/append/remove/show synthetic events\n" | 5806 | " events/synthetic_events\t- Create/append/remove/show synthetic events\n" |
| 5762 | "\t Write into this file to define/undefine new synthetic events.\n" | 5807 | "\t Write into this file to define/undefine new synthetic events.\n" |
| 5763 | "\t example: echo 'myevent u64 lat; char name[]' >> synthetic_events\n" | 5808 | "\t example: echo 'myevent u64 lat; char name[]; long[] stack' >> synthetic_events\n" |
| 5764 | #endif | 5809 | #endif |
| 5765 | #endif | 5810 | #endif |
| 5766 | ; | 5811 | ; |
| @@ -9225,10 +9270,6 @@ static int allocate_trace_buffers(struct trace_array *tr, int size) · 3458 unmodified lines | |||
| 9225 | } | 9270 | } |
| 9226 | tr->allocated_snapshot = allocate_snapshot; | 9271 | tr->allocated_snapshot = allocate_snapshot; |
| 9227 | 9272 | ||
| 9228 | /* | ||
| 9229 | * Only the top level trace array gets its snapshot allocated | ||
| 9230 | * from the kernel command line. | ||
| 9231 | */ | ||
| 9232 | allocate_snapshot = false; | 9273 | allocate_snapshot = false; |
| 9233 | #endif | 9274 | #endif |
| 9234 | 9275 | ||
| @@ -10144,6 +10185,79 @@ out: · 909 unmodified lines | |||
| 10144 | return ret; | 10185 | return ret; |
| 10145 | } | 10186 | } |
| 10146 | 10187 | ||
| 10188 | #ifdef CONFIG_TRACER_MAX_TRACE | ||
| 10189 | __init static bool tr_needs_alloc_snapshot(const char *name) | ||
| 10190 | { | ||
| 10191 | char *test; | ||
| 10192 | int len = strlen(name); | ||
| 10193 | bool ret; | ||
| 10194 | |||
| 10195 | if (!boot_snapshot_index) | ||
| 10196 | return false; | ||
| 10197 | |||
| 10198 | if (strncmp(name, boot_snapshot_info, len) == 0 && | ||
| 10199 | boot_snapshot_info[len] == '\t') | ||
| 10200 | return true; | ||
| 10201 | |||
| 10202 | test = kmalloc(strlen(name) + 3, GFP_KERNEL); | ||
| 10203 | if (!test) | ||
| 10204 | return false; | ||
| 10205 | |||
| 10206 | sprintf(test, "\t%s\t", name); | ||
| 10207 | ret = strstr(boot_snapshot_info, test) == NULL; | ||
| 10208 | kfree(test); | ||
| 10209 | return ret; | ||
| 10210 | } | ||
| 10211 | |||
| 10212 | __init static void do_allocate_snapshot(const char *name) | ||
| 10213 | { | ||
| 10214 | if (!tr_needs_alloc_snapshot(name)) | ||
| 10215 | return; | ||
| 10216 | |||
| 10217 | /* | ||
| 10218 | * When allocate_snapshot is set, the next call to | ||
| 10219 | * allocate_trace_buffers() (called by trace_array_get_by_name()) | ||
| 10220 | * will allocate the snapshot buffer. That will alse clear | ||
| 10221 | * this flag. | ||
| 10222 | */ | ||
| 10223 | allocate_snapshot = true; | ||
| 10224 | } | ||
| 10225 | #else | ||
| 10226 | static inline void do_allocate_snapshot(const char *name) { } | ||
| 10227 | #endif | ||
| 10228 | |||
| 10229 | __init static void enable_instances(void) | ||
| 10230 | { | ||
| 10231 | struct trace_array *tr; | ||
| 10232 | char *curr_str; | ||
| 10233 | char *str; | ||
| 10234 | char *tok; | ||
| 10235 | |||
| 10236 | /* A tab is always appended */ | ||
| 10237 | boot_instance_info[boot_instance_index - 1] = '\0'; | ||
| 10238 | str = boot_instance_info; | ||
| 10239 | |||
| 10240 | while ((curr_str = strsep(&str, "\t"))) { | ||
| 10241 | |||
| 10242 | tok = strsep(&curr_str, ","); | ||
| 10243 | |||
| 10244 | if (IS_ENABLED(CONFIG_TRACER_MAX_TRACE)) | ||
| 10245 | do_allocate_snapshot(tok); | ||
| 10246 | |||
| 10247 | tr = trace_array_get_by_name(tok); | ||
| 10248 | if (!tr) { | ||
| 10249 | pr_warn("Failed to create instance buffer %s\n", curr_str); | ||
| 10250 | continue; | ||
| 10251 | } | ||
| 10252 | /* Allow user space to delete it */ | ||
| 10253 | trace_array_put(tr); | ||
| 10254 | |||
| 10255 | while ((tok = strsep(&curr_str, ","))) { | ||
| 10256 | early_enable_events(tr, tok, true); | ||
| 10257 | } | ||
| 10258 | } | ||
| 10259 | } | ||
| 10260 | |||
| 10147 | __init static int tracer_alloc_buffers(void) | 10261 | __init static int tracer_alloc_buffers(void) |
| 10148 | { | 10262 | { |
| 10149 | int ring_buf_size; | 10263 | int ring_buf_size; |
| @@ -10277,10 +10391,19 @@ out: · 127 unmodified lines | |||
| 10277 | 10391 | ||
| 10278 | void __init ftrace_boot_snapshot(void) | 10392 | void __init ftrace_boot_snapshot(void) |
| 10279 | { | 10393 | { |
| 10394 | struct trace_array *tr; | ||
| 10395 | |||
| 10280 | if (snapshot_at_boot) { | 10396 | if (snapshot_at_boot) { |
| 10281 | tracing_snapshot(); | 10397 | tracing_snapshot(); |
| 10282 | internal_trace_puts("** Boot snapshot taken **\n"); | 10398 | internal_trace_puts("** Boot snapshot taken **\n"); |
| 10283 | } | 10399 | } |
| 10400 | |||
| 10401 | list_for_each_entry(tr, &ftrace_trace_arrays, list) { | ||
| 10402 | if (tr == &global_trace) | ||
| 10403 | continue; | ||
| 10404 | trace_array_puts(tr, "** Boot snapshot taken **\n"); | ||
| 10405 | tracing_snapshot_instance(tr); | ||
| 10406 | } | ||
| 10284 | } | 10407 | } |
| 10285 | 10408 | ||
| 10286 | void __init early_trace_init(void) | 10409 | void __init early_trace_init(void) |
| @@ -10302,6 +10425,9 @@ void __init early_trace_init(void) · 15 unmodified lines | |||
| 10302 | void __init trace_init(void) | 10425 | void __init trace_init(void) |
| 10303 | { | 10426 | { |
| 10304 | trace_event_init(); | 10427 | trace_event_init(); |
| 10428 | |||
| 10429 | if (boot_instance_index) | ||
| 10430 | enable_instances(); | ||
| 10305 | } | 10431 | } |
| 10306 | 10432 | ||
| 10307 | __init static void clear_boot_tracer(void) | 10433 | __init static void clear_boot_tracer(void) |
| @@ -113,6 +113,10 @@ enum trace_type { · 112 unmodified lines | |||
| 113 | #define MEM_FAIL(condition, fmt, ...) \ | 113 | #define MEM_FAIL(condition, fmt, ...) \ |
| 114 | DO_ONCE_LITE_IF(condition, pr_err, "ERROR: " fmt, ##__VA_ARGS__) | 114 | DO_ONCE_LITE_IF(condition, pr_err, "ERROR: " fmt, ##__VA_ARGS__) |
| 115 | 115 | ||
| 116 | #define HIST_STACKTRACE_DEPTH 16 | ||
| 117 | #define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long)) | ||
| 118 | #define HIST_STACKTRACE_SKIP 5 | ||
| 119 | |||
| 116 | /* | 120 | /* |
| 117 | * syscalls are special, and need special handling, this is why | 121 | * syscalls are special, and need special handling, this is why |
| 118 | * they are not included in trace_entries.h | 122 | * they are not included in trace_entries.h |
| @@ -1331,6 +1335,8 @@ DECLARE_PER_CPU(int, trace_buffered_event_cnt); · 1212 unmodified lines | |||
| 1331 | void trace_buffered_event_disable(void); | 1335 | void trace_buffered_event_disable(void); |
| 1332 | void trace_buffered_event_enable(void); | 1336 | void trace_buffered_event_enable(void); |
| 1333 | 1337 | ||
| 1338 | void early_enable_events(struct trace_array *tr, char *buf, bool disable_first); | ||
| 1339 | |||
| 1334 | static inline void | 1340 | static inline void |
| 1335 | __trace_event_discard_commit(struct trace_buffer *buffer, | 1341 | __trace_event_discard_commit(struct trace_buffer *buffer, |
| 1336 | struct ring_buffer_event *event) | 1342 | struct ring_buffer_event *event) |
| @@ -2281,8 +2281,6 @@ create_new_subsystem(const char *name) · 2280 unmodified lines | |||
| 2281 | if (!system->name) | 2281 | if (!system->name) |
| 2282 | goto out_free; | 2282 | goto out_free; |
| 2283 | 2283 | ||
| 2284 | system->filter = NULL; | ||
| 2285 | |||
| 2286 | system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL); | 2284 | system->filter = kzalloc(sizeof(struct event_filter), GFP_KERNEL); |
| 2287 | if (!system->filter) | 2285 | if (!system->filter) |
| 2288 | goto out_free; | 2286 | goto out_free; |
| @@ -2843,7 +2841,7 @@ static __init int setup_trace_triggers(char *str) · 554 unmodified lines | |||
| 2843 | if (!trigger) | 2841 | if (!trigger) |
| 2844 | break; | 2842 | break; |
| 2845 | bootup_triggers[i].event = strsep(&trigger, "."); | 2843 | bootup_triggers[i].event = strsep(&trigger, "."); |
| 2846 | bootup_triggers[i].trigger = strsep(&trigger, "."); | 2844 | bootup_triggers[i].trigger = trigger; |
| 2847 | if (!bootup_triggers[i].trigger) | 2845 | if (!bootup_triggers[i].trigger) |
| 2848 | break; | 2846 | break; |
| 2849 | } | 2847 | } |
| @@ -3771,10 +3769,9 @@ static __init int event_trace_memsetup(void) · 921 unmodified lines | |||
| 3771 | return 0; | 3769 | return 0; |
| 3772 | } | 3770 | } |
| 3773 | 3771 | ||
| 3774 | static __init void | 3772 | __init void |
| 3775 | early_enable_events(struct trace_array *tr, bool disable_first) | 3773 | early_enable_events(struct trace_array *tr, char *buf, bool disable_first) |
| 3776 | { | 3774 | { |
| 3777 | char *buf = bootup_event_buf; | ||
| 3778 | char *token; | 3775 | char *token; |
| 3779 | int ret; | 3776 | int ret; |
| 3780 | 3777 | ||
| @@ -3827,7 +3824,7 @@ static __init int event_trace_enable(void) · 46 unmodified lines | |||
| 3827 | */ | 3824 | */ |
| 3828 | __trace_early_add_events(tr); | 3825 | __trace_early_add_events(tr); |
| 3829 | 3826 | ||
| 3830 | early_enable_events(tr, false); | 3827 | early_enable_events(tr, bootup_event_buf, false); |
| 3831 | 3828 | ||
| 3832 | trace_printk_start_comm(); | 3829 | trace_printk_start_comm(); |
| 3833 | 3830 | ||
| @@ -3855,7 +3852,7 @@ static __init int event_trace_enable_again(void) · 21 unmodified lines | |||
| 3855 | if (!tr) | 3852 | if (!tr) |
| 3856 | return -ENODEV; | 3853 | return -ENODEV; |
| 3857 | 3854 | ||
| 3858 | early_enable_events(tr, true); | 3855 | early_enable_events(tr, bootup_event_buf, true); |
| 3859 | 3856 | ||
| 3860 | return 0; | 3857 | return 0; |
| 3861 | } | 3858 | } |
| @@ -64,6 +64,7 @@ enum filter_pred_fn { · 63 unmodified lines | |||
| 64 | FILTER_PRED_FN_PCHAR_USER, | 64 | FILTER_PRED_FN_PCHAR_USER, |
| 65 | FILTER_PRED_FN_PCHAR, | 65 | FILTER_PRED_FN_PCHAR, |
| 66 | FILTER_PRED_FN_CPU, | 66 | FILTER_PRED_FN_CPU, |
| 67 | FILTER_PRED_FN_FUNCTION, | ||
| 67 | FILTER_PRED_FN_, | 68 | FILTER_PRED_FN_, |
| 68 | FILTER_PRED_TEST_VISITED, | 69 | FILTER_PRED_TEST_VISITED, |
| 69 | }; | 70 | }; |
| @@ -71,6 +72,7 @@ enum filter_pred_fn { · 1 unmodified line | |||
| 71 | struct filter_pred { | 72 | struct filter_pred { |
| 72 | enum filter_pred_fn fn_num; | 73 | enum filter_pred_fn fn_num; |
| 73 | u64 val; | 74 | u64 val; |
| 75 | u64 val2; | ||
| 74 | struct regex regex; | 76 | struct regex regex; |
| 75 | unsigned short *ops; | 77 | unsigned short *ops; |
| 76 | struct ftrace_event_field *field; | 78 | struct ftrace_event_field *field; |
| @@ -103,6 +105,7 @@ struct filter_pred { · 26 unmodified lines | |||
| 103 | C(INVALID_FILTER, "Meaningless filter expression"), \ | 105 | C(INVALID_FILTER, "Meaningless filter expression"), \ |
| 104 | C(IP_FIELD_ONLY, "Only 'ip' field is supported for function trace"), \ | 106 | C(IP_FIELD_ONLY, "Only 'ip' field is supported for function trace"), \ |
| 105 | C(INVALID_VALUE, "Invalid value (did you forget quotes)?"), \ | 107 | C(INVALID_VALUE, "Invalid value (did you forget quotes)?"), \ |
| 108 | C(NO_FUNCTION, "Function not found"), \ | ||
| 106 | C(ERRNO, "Error"), \ | 109 | C(ERRNO, "Error"), \ |
| 107 | C(NO_FILTER, "No filter found") | 110 | C(NO_FILTER, "No filter found") |
| 108 | 111 | ||
| @@ -876,6 +879,17 @@ static int filter_pred_comm(struct filter_pred *pred, void *event) · 767 unmodified lines | |||
| 876 | return cmp ^ pred->not; | 879 | return cmp ^ pred->not; |
| 877 | } | 880 | } |
| 878 | 881 | ||
| 882 | /* Filter predicate for functions. */ | ||
| 883 | static int filter_pred_function(struct filter_pred *pred, void *event) | ||
| 884 | { | ||
| 885 | unsigned long *addr = (unsigned long *)(event + pred->offset); | ||
| 886 | unsigned long start = (unsigned long)pred->val; | ||
| 887 | unsigned long end = (unsigned long)pred->val2; | ||
| 888 | int ret = *addr >= start && *addr < end; | ||
| 889 | |||
| 890 | return pred->op == OP_EQ ? ret : !ret; | ||
| 891 | } | ||
| 892 | |||
| 879 | /* | 893 | /* |
| 880 | * regex_match_foo - Basic regex callbacks | 894 | * regex_match_foo - Basic regex callbacks |
| 881 | * | 895 | * |
| @@ -1335,6 +1349,8 @@ static int filter_pred_fn_call(struct filter_pred *pred, void *event) · 453 unmodified lines | |||
| 1335 | return filter_pred_pchar(pred, event); | 1349 | return filter_pred_pchar(pred, event); |
| 1336 | case FILTER_PRED_FN_CPU: | 1350 | case FILTER_PRED_FN_CPU: |
| 1337 | return filter_pred_cpu(pred, event); | 1351 | return filter_pred_cpu(pred, event); |
| 1352 | case FILTER_PRED_FN_FUNCTION: | ||
| 1353 | return filter_pred_function(pred, event); | ||
| 1338 | case FILTER_PRED_TEST_VISITED: | 1354 | case FILTER_PRED_TEST_VISITED: |
| 1339 | return test_pred_visited_fn(pred, event); | 1355 | return test_pred_visited_fn(pred, event); |
| 1340 | default: | 1356 | default: |
| @@ -1350,8 +1366,13 @@ static int parse_pred(const char *str, void *data, · 9 unmodified lines | |||
| 1350 | struct trace_event_call *call = data; | 1366 | struct trace_event_call *call = data; |
| 1351 | struct ftrace_event_field *field; | 1367 | struct ftrace_event_field *field; |
| 1352 | struct filter_pred *pred = NULL; | 1368 | struct filter_pred *pred = NULL; |
| 1369 | unsigned long offset; | ||
| 1370 | unsigned long size; | ||
| 1371 | unsigned long ip; | ||
| 1353 | char num_buf[24]; /* Big enough to hold an address */ | 1372 | char num_buf[24]; /* Big enough to hold an address */ |
| 1354 | char *field_name; | 1373 | char *field_name; |
| 1374 | char *name; | ||
| 1375 | bool function = false; | ||
| 1355 | bool ustring = false; | 1376 | bool ustring = false; |
| 1356 | char q; | 1377 | char q; |
| 1357 | u64 val; | 1378 | u64 val; |
| @@ -1393,6 +1414,12 @@ static int parse_pred(const char *str, void *data, · 35 unmodified lines | |||
| 1393 | i += len; | 1414 | i += len; |
| 1394 | } | 1415 | } |
| 1395 | 1416 | ||
| 1417 | /* See if the field is a kernel function name */ | ||
| 1418 | if ((len = str_has_prefix(str + i, ".function"))) { | ||
| 1419 | function = true; | ||
| 1420 | i += len; | ||
| 1421 | } | ||
| 1422 | |||
| 1396 | while (isspace(str[i])) | 1423 | while (isspace(str[i])) |
| 1397 | i++; | 1424 | i++; |
| 1398 | 1425 | ||
| @@ -1423,7 +1450,71 @@ static int parse_pred(const char *str, void *data, · 24 unmodified lines | |||
| 1423 | pred->offset = field->offset; | 1450 | pred->offset = field->offset; |
| 1424 | pred->op = op; | 1451 | pred->op = op; |
| 1425 | 1452 | ||
| 1426 | if (ftrace_event_is_function(call)) { | 1453 | if (function) { |
| 1454 | /* The field must be the same size as long */ | ||
| 1455 | if (field->size != sizeof(long)) { | ||
| 1456 | parse_error(pe, FILT_ERR_ILLEGAL_FIELD_OP, pos + i); | ||
| 1457 | goto err_free; | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | /* Function only works with '==' or '!=' and an unquoted string */ | ||
| 1461 | switch (op) { | ||
| 1462 | case OP_NE: | ||
| 1463 | case OP_EQ: | ||
| 1464 | break; | ||
| 1465 | default: | ||
| 1466 | parse_error(pe, FILT_ERR_INVALID_OP, pos + i); | ||
| 1467 | goto err_free; | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | if (isdigit(str[i])) { | ||
| 1471 | /* We allow 0xDEADBEEF */ | ||
| 1472 | while (isalnum(str[i])) | ||
| 1473 | i++; | ||
| 1474 | |||
| 1475 | len = i - s; | ||
| 1476 | /* 0xfeedfacedeadbeef is 18 chars max */ | ||
| 1477 | if (len >= sizeof(num_buf)) { | ||
| 1478 | parse_error(pe, FILT_ERR_OPERAND_TOO_LONG, pos + i); | ||
| 1479 | goto err_free; | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | strncpy(num_buf, str + s, len); | ||
| 1483 | num_buf[len] = 0; | ||
| 1484 | |||
| 1485 | ret = kstrtoul(num_buf, 0, &ip); | ||
| 1486 | if (ret) { | ||
| 1487 | parse_error(pe, FILT_ERR_INVALID_VALUE, pos + i); | ||
| 1488 | goto err_free; | ||
| 1489 | } | ||
| 1490 | } else { | ||
| 1491 | s = i; | ||
| 1492 | for (; str[i] && !isspace(str[i]); i++) | ||
| 1493 | ; | ||
| 1494 | |||
| 1495 | len = i - s; | ||
| 1496 | name = kmemdup_nul(str + s, len, GFP_KERNEL); | ||
| 1497 | if (!name) | ||
| 1498 | goto err_mem; | ||
| 1499 | ip = kallsyms_lookup_name(name); | ||
| 1500 | kfree(name); | ||
| 1501 | if (!ip) { | ||
| 1502 | parse_error(pe, FILT_ERR_NO_FUNCTION, pos + i); | ||
| 1503 | goto err_free; | ||
| 1504 | } | ||
| 1505 | } | ||
| 1506 | |||
| 1507 | /* Now find the function start and end address */ | ||
| 1508 | if (!kallsyms_lookup_size_offset(ip, &size, &offset)) { | ||
| 1509 | parse_error(pe, FILT_ERR_NO_FUNCTION, pos + i); | ||
| 1510 | goto err_free; | ||
| 1511 | } | ||
| 1512 | |||
| 1513 | pred->fn_num = FILTER_PRED_FN_FUNCTION; | ||
| 1514 | pred->val = ip - offset; | ||
| 1515 | pred->val2 = pred->val + size; | ||
| 1516 | |||
| 1517 | } else if (ftrace_event_is_function(call)) { | ||
| 1427 | /* | 1518 | /* |
| 1428 | * Perf does things different with function events. | 1519 | * Perf does things different with function events. |
| 1429 | * It only allows an "ip" field, and expects a string. | 1520 | * It only allows an "ip" field, and expects a string. |
| @@ -135,6 +135,7 @@ enum hist_field_fn { · 134 unmodified lines | |||
| 135 | HIST_FIELD_FN_DIV_NOT_POWER2, | 135 | HIST_FIELD_FN_DIV_NOT_POWER2, |
| 136 | HIST_FIELD_FN_DIV_MULT_SHIFT, | 136 | HIST_FIELD_FN_DIV_MULT_SHIFT, |
| 137 | HIST_FIELD_FN_EXECNAME, | 137 | HIST_FIELD_FN_EXECNAME, |
| 138 | HIST_FIELD_FN_STACK, | ||
| 138 | }; | 139 | }; |
| 139 | 140 | ||
| 140 | /* | 141 | /* |
| @@ -480,10 +481,6 @@ DEFINE_HIST_FIELD_FN(u8); · 339 unmodified lines | |||
| 480 | #define for_each_hist_key_field(i, hist_data) \ | 481 | #define for_each_hist_key_field(i, hist_data) \ |
| 481 | for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++) | 482 | for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++) |
| 482 | 483 | ||
| 483 | #define HIST_STACKTRACE_DEPTH 16 | ||
| 484 | #define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long)) | ||
| 485 | #define HIST_STACKTRACE_SKIP 5 | ||
| 486 | |||
| 487 | #define HITCOUNT_IDX 0 | 484 | #define HITCOUNT_IDX 0 |
| 488 | #define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE) | 485 | #define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE) |
| 489 | 486 | ||
| @@ -1360,7 +1357,12 @@ static const char *hist_field_name(struct hist_field *field, · 870 unmodified lines | |||
| 1360 | field_name = field->name; | 1357 | field_name = field->name; |
| 1361 | } else if (field->flags & HIST_FIELD_FL_TIMESTAMP) | 1358 | } else if (field->flags & HIST_FIELD_FL_TIMESTAMP) |
| 1362 | field_name = "common_timestamp"; | 1359 | field_name = "common_timestamp"; |
| 1363 | else if (field->flags & HIST_FIELD_FL_HITCOUNT) | 1360 | else if (field->flags & HIST_FIELD_FL_STACKTRACE) { |
| 1361 | if (field->field) | ||
| 1362 | field_name = field->field->name; | ||
| 1363 | else | ||
| 1364 | field_name = "stacktrace"; | ||
| 1365 | } else if (field->flags & HIST_FIELD_FL_HITCOUNT) | ||
| 1364 | field_name = "hitcount"; | 1366 | field_name = "hitcount"; |
| 1365 | 1367 | ||
| 1366 | if (field_name == NULL) | 1368 | if (field_name == NULL) |
| @@ -1718,6 +1720,8 @@ static const char *get_hist_field_flags(struct hist_field *hist_field) · 351 unmodified lines | |||
| 1718 | flags_str = "percent"; | 1720 | flags_str = "percent"; |
| 1719 | else if (hist_field->flags & HIST_FIELD_FL_GRAPH) | 1721 | else if (hist_field->flags & HIST_FIELD_FL_GRAPH) |
| 1720 | flags_str = "graph"; | 1722 | flags_str = "graph"; |
| 1723 | else if (hist_field->flags & HIST_FIELD_FL_STACKTRACE) | ||
| 1724 | flags_str = "stacktrace"; | ||
| 1721 | 1725 | ||
| 1722 | return flags_str; | 1726 | return flags_str; |
| 1723 | } | 1727 | } |
| @@ -1979,7 +1983,14 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data, · 255 unmodified lines | |||
| 1979 | } | 1983 | } |
| 1980 | 1984 | ||
| 1981 | if (flags & HIST_FIELD_FL_STACKTRACE) { | 1985 | if (flags & HIST_FIELD_FL_STACKTRACE) { |
| 1982 | hist_field->fn_num = HIST_FIELD_FN_NOP; | 1986 | if (field) |
| 1987 | hist_field->fn_num = HIST_FIELD_FN_STACK; | ||
| 1988 | else | ||
| 1989 | hist_field->fn_num = HIST_FIELD_FN_NOP; | ||
| 1990 | hist_field->size = HIST_STACKTRACE_SIZE; | ||
| 1991 | hist_field->type = kstrdup_const("unsigned long[]", GFP_KERNEL); | ||
| 1992 | if (!hist_field->type) | ||
| 1993 | goto free; | ||
| 1983 | goto out; | 1994 | goto out; |
| 1984 | } | 1995 | } |
| 1985 | 1996 | ||
| @@ -2312,6 +2323,8 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file, · 326 unmodified lines | |||
| 2312 | *flags |= HIST_FIELD_FL_EXECNAME; | 2323 | *flags |= HIST_FIELD_FL_EXECNAME; |
| 2313 | else if (strcmp(modifier, "syscall") == 0) | 2324 | else if (strcmp(modifier, "syscall") == 0) |
| 2314 | *flags |= HIST_FIELD_FL_SYSCALL; | 2325 | *flags |= HIST_FIELD_FL_SYSCALL; |
| 2326 | else if (strcmp(modifier, "stacktrace") == 0) | ||
| 2327 | *flags |= HIST_FIELD_FL_STACKTRACE; | ||
| 2315 | else if (strcmp(modifier, "log2") == 0) | 2328 | else if (strcmp(modifier, "log2") == 0) |
| 2316 | *flags |= HIST_FIELD_FL_LOG2; | 2329 | *flags |= HIST_FIELD_FL_LOG2; |
| 2317 | else if (strcmp(modifier, "usecs") == 0) | 2330 | else if (strcmp(modifier, "usecs") == 0) |
| @@ -2351,6 +2364,8 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file, · 33 unmodified lines | |||
| 2351 | hist_data->enable_timestamps = true; | 2364 | hist_data->enable_timestamps = true; |
| 2352 | if (*flags & HIST_FIELD_FL_TIMESTAMP_USECS) | 2365 | if (*flags & HIST_FIELD_FL_TIMESTAMP_USECS) |
| 2353 | hist_data->attrs->ts_in_usecs = true; | 2366 | hist_data->attrs->ts_in_usecs = true; |
| 2367 | } else if (strcmp(field_name, "stacktrace") == 0) { | ||
| 2368 | *flags |= HIST_FIELD_FL_STACKTRACE; | ||
| 2354 | } else if (strcmp(field_name, "common_cpu") == 0) | 2369 | } else if (strcmp(field_name, "common_cpu") == 0) |
| 2355 | *flags |= HIST_FIELD_FL_CPU; | 2370 | *flags |= HIST_FIELD_FL_CPU; |
| 2356 | else if (strcmp(field_name, "hitcount") == 0) | 2371 | else if (strcmp(field_name, "hitcount") == 0) |
| @@ -3111,6 +3126,9 @@ static inline void __update_field_vars(struct tracing_map_elt *elt, · 754 unmodified lines | |||
| 3111 | unsigned int i, j, var_idx; | 3126 | unsigned int i, j, var_idx; |
| 3112 | u64 var_val; | 3127 | u64 var_val; |
| 3113 | 3128 | ||
| 3129 | /* Make sure stacktrace can fit in the string variable length */ | ||
| 3130 | BUILD_BUG_ON((HIST_STACKTRACE_DEPTH + 1) * sizeof(long) >= STR_VAR_LEN_MAX); | ||
| 3131 | |||
| 3114 | for (i = 0, j = field_var_str_start; i < n_field_vars; i++) { | 3132 | for (i = 0, j = field_var_str_start; i < n_field_vars; i++) { |
| 3115 | struct field_var *field_var = field_vars[i]; | 3133 | struct field_var *field_var = field_vars[i]; |
| 3116 | struct hist_field *var = field_var->var; | 3134 | struct hist_field *var = field_var->var; |
| @@ -3119,13 +3137,26 @@ static inline void __update_field_vars(struct tracing_map_elt *elt, · 2 unmodified lines | |||
| 3119 | var_val = hist_fn_call(val, elt, buffer, rbe, rec); | 3137 | var_val = hist_fn_call(val, elt, buffer, rbe, rec); |
| 3120 | var_idx = var->var.idx; | 3138 | var_idx = var->var.idx; |
| 3121 | 3139 | ||
| 3122 | if (val->flags & HIST_FIELD_FL_STRING) { | 3140 | if (val->flags & (HIST_FIELD_FL_STRING | |
| 3141 | HIST_FIELD_FL_STACKTRACE)) { | ||
| 3123 | char *str = elt_data->field_var_str[j++]; | 3142 | char *str = elt_data->field_var_str[j++]; |
| 3124 | char *val_str = (char *)(uintptr_t)var_val; | 3143 | char *val_str = (char *)(uintptr_t)var_val; |
| 3125 | unsigned int size; | 3144 | unsigned int size; |
| 3126 | 3145 | ||
| 3127 | size = min(val->size, STR_VAR_LEN_MAX); | 3146 | if (val->flags & HIST_FIELD_FL_STRING) { |
| 3128 | strscpy(str, val_str, size); | 3147 | size = min(val->size, STR_VAR_LEN_MAX); |
| 3148 | strscpy(str, val_str, size); | ||
| 3149 | } else { | ||
| 3150 | char *stack_start = str + sizeof(unsigned long); | ||
| 3151 | int e; | ||
| 3152 | |||
| 3153 | e = stack_trace_save((void *)stack_start, | ||
| 3154 | HIST_STACKTRACE_DEPTH, | ||
| 3155 | HIST_STACKTRACE_SKIP); | ||
| 3156 | if (e < HIST_STACKTRACE_DEPTH - 1) | ||
| 3157 | ((unsigned long *)stack_start)[e] = 0; | ||
| 3158 | *((unsigned long *)str) = e; | ||
| 3159 | } | ||
| 3129 | var_val = (u64)(uintptr_t)str; | 3160 | var_val = (u64)(uintptr_t)str; |
| 3130 | } | 3161 | } |
| 3131 | tracing_map_set_var(elt, var_idx, var_val); | 3162 | tracing_map_set_var(elt, var_idx, var_val); |
| @@ -3824,7 +3855,8 @@ static void save_field_var(struct hist_trigger_data *hist_data, · 692 unmodified lines | |||
| 3824 | { | 3855 | { |
| 3825 | hist_data->field_vars[hist_data->n_field_vars++] = field_var; | 3856 | hist_data->field_vars[hist_data->n_field_vars++] = field_var; |
| 3826 | 3857 | ||
| 3827 | if (field_var->val->flags & HIST_FIELD_FL_STRING) | 3858 | /* Stack traces are saved in the string storage too */ |
| 3859 | if (field_var->val->flags & (HIST_FIELD_FL_STRING | HIST_FIELD_FL_STACKTRACE)) | ||
| 3828 | hist_data->n_field_var_str++; | 3860 | hist_data->n_field_var_str++; |
| 3829 | } | 3861 | } |
| 3830 | 3862 | ||
| @@ -3849,6 +3881,9 @@ static int check_synth_field(struct synth_event *event, · 18 unmodified lines | |||
| 3849 | && field->is_dynamic) | 3881 | && field->is_dynamic) |
| 3850 | return 0; | 3882 | return 0; |
| 3851 | 3883 | ||
| 3884 | if (strstr(hist_field->type, "long[") && field->is_stack) | ||
| 3885 | return 0; | ||
| 3886 | |||
| 3852 | if (strcmp(field->type, hist_field->type) != 0) { | 3887 | if (strcmp(field->type, hist_field->type) != 0) { |
| 3853 | if (field->size != hist_field->size || | 3888 | if (field->size != hist_field->size || |
| 3854 | (!field->is_string && field->is_signed != hist_field->is_signed)) | 3889 | (!field->is_string && field->is_signed != hist_field->is_signed)) |
| @@ -4103,7 +4138,8 @@ static int action_create(struct hist_trigger_data *hist_data, · 248 unmodified lines | |||
| 4103 | } | 4138 | } |
| 4104 | 4139 | ||
| 4105 | hist_data->save_vars[hist_data->n_save_vars++] = field_var; | 4140 | hist_data->save_vars[hist_data->n_save_vars++] = field_var; |
| 4106 | if (field_var->val->flags & HIST_FIELD_FL_STRING) | 4141 | if (field_var->val->flags & |
| 4142 | (HIST_FIELD_FL_STRING | HIST_FIELD_FL_STACKTRACE)) | ||
| 4107 | hist_data->n_save_var_str++; | 4143 | hist_data->n_save_var_str++; |
| 4108 | kfree(param); | 4144 | kfree(param); |
| 4109 | } | 4145 | } |
| @@ -4242,6 +4278,19 @@ static u64 hist_field_execname(struct hist_field *hist_field, · 132 unmodified lines | |||
| 4242 | return (u64)(unsigned long)(elt_data->comm); | 4278 | return (u64)(unsigned long)(elt_data->comm); |
| 4243 | } | 4279 | } |
| 4244 | 4280 | ||
| 4281 | static u64 hist_field_stack(struct hist_field *hist_field, | ||
| 4282 | struct tracing_map_elt *elt, | ||
| 4283 | struct trace_buffer *buffer, | ||
| 4284 | struct ring_buffer_event *rbe, | ||
| 4285 | void *event) | ||
| 4286 | { | ||
| 4287 | u32 str_item = *(u32 *)(event + hist_field->field->offset); | ||
| 4288 | int str_loc = str_item & 0xffff; | ||
| 4289 | char *addr = (char *)(event + str_loc); | ||
| 4290 | |||
| 4291 | return (u64)(unsigned long)addr; | ||
| 4292 | } | ||
| 4293 | |||
| 4245 | static u64 hist_fn_call(struct hist_field *hist_field, | 4294 | static u64 hist_fn_call(struct hist_field *hist_field, |
| 4246 | struct tracing_map_elt *elt, | 4295 | struct tracing_map_elt *elt, |
| 4247 | struct trace_buffer *buffer, | 4296 | struct trace_buffer *buffer, |
| @@ -4305,6 +4354,8 @@ static u64 hist_fn_call(struct hist_field *hist_field, · 57 unmodified lines | |||
| 4305 | return div_by_mult_and_shift(hist_field, elt, buffer, rbe, event); | 4354 | return div_by_mult_and_shift(hist_field, elt, buffer, rbe, event); |
| 4306 | case HIST_FIELD_FN_EXECNAME: | 4355 | case HIST_FIELD_FN_EXECNAME: |
| 4307 | return hist_field_execname(hist_field, elt, buffer, rbe, event); | 4356 | return hist_field_execname(hist_field, elt, buffer, rbe, event); |
| 4357 | case HIST_FIELD_FN_STACK: | ||
| 4358 | return hist_field_stack(hist_field, elt, buffer, rbe, event); | ||
| 4308 | default: | 4359 | default: |
| 4309 | return 0; | 4360 | return 0; |
| 4310 | } | 4361 | } |
| @@ -4351,7 +4402,8 @@ static int create_var_field(struct hist_trigger_data *hist_data, · 40 unmodified lines | |||
| 4351 | if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_EXECNAME) | 4402 | if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_EXECNAME) |
| 4352 | update_var_execname(hist_data->fields[val_idx]); | 4403 | update_var_execname(hist_data->fields[val_idx]); |
| 4353 | 4404 | ||
| 4354 | if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_STRING) | 4405 | if (!ret && hist_data->fields[val_idx]->flags & |
| 4406 | (HIST_FIELD_FL_STRING | HIST_FIELD_FL_STACKTRACE)) | ||
| 4355 | hist_data->fields[val_idx]->var_str_idx = hist_data->n_var_str++; | 4407 | hist_data->fields[val_idx]->var_str_idx = hist_data->n_var_str++; |
| 4356 | 4408 | ||
| 4357 | return ret; | 4409 | return ret; |
| @@ -5092,7 +5144,8 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data, · 734 unmodified lines | |||
| 5092 | if (hist_field->flags & HIST_FIELD_FL_VAR) { | 5144 | if (hist_field->flags & HIST_FIELD_FL_VAR) { |
| 5093 | var_idx = hist_field->var.idx; | 5145 | var_idx = hist_field->var.idx; |
| 5094 | 5146 | ||
| 5095 | if (hist_field->flags & HIST_FIELD_FL_STRING) { | 5147 | if (hist_field->flags & |
| 5148 | (HIST_FIELD_FL_STRING | HIST_FIELD_FL_STACKTRACE)) { | ||
| 5096 | unsigned int str_start, var_str_idx, idx; | 5149 | unsigned int str_start, var_str_idx, idx; |
| 5097 | char *str, *val_str; | 5150 | char *str, *val_str; |
| 5098 | unsigned int size; | 5151 | unsigned int size; |
| @@ -5105,9 +5158,20 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data, · 6 unmodified lines | |||
| 5105 | str = elt_data->field_var_str[idx]; | 5158 | str = elt_data->field_var_str[idx]; |
| 5106 | val_str = (char *)(uintptr_t)hist_val; | 5159 | val_str = (char *)(uintptr_t)hist_val; |
| 5107 | 5160 | ||
| 5108 | size = min(hist_field->size, STR_VAR_LEN_MAX); | 5161 | if (hist_field->flags & HIST_FIELD_FL_STRING) { |
| 5109 | strscpy(str, val_str, size); | 5162 | size = min(hist_field->size, STR_VAR_LEN_MAX); |
| 5110 | 5163 | strscpy(str, val_str, size); | |
| 5164 | } else { | ||
| 5165 | char *stack_start = str + sizeof(unsigned long); | ||
| 5166 | int e; | ||
| 5167 | |||
| 5168 | e = stack_trace_save((void *)stack_start, | ||
| 5169 | HIST_STACKTRACE_DEPTH, | ||
| 5170 | HIST_STACKTRACE_SKIP); | ||
| 5171 | if (e < HIST_STACKTRACE_DEPTH - 1) | ||
| 5172 | ((unsigned long *)stack_start)[e] = 0; | ||
| 5173 | *((unsigned long *)str) = e; | ||
| 5174 | } | ||
| 5111 | hist_val = (u64)(uintptr_t)str; | 5175 | hist_val = (u64)(uintptr_t)str; |
| 5112 | } | 5176 | } |
| 5113 | tracing_map_set_var(elt, var_idx, hist_val); | 5177 | tracing_map_set_var(elt, var_idx, hist_val); |
| @@ -5193,8 +5257,17 @@ static void event_hist_trigger(struct event_trigger_data *data, · 79 unmodified lines | |||
| 5193 | 5257 | ||
| 5194 | if (key_field->flags & HIST_FIELD_FL_STACKTRACE) { | 5258 | if (key_field->flags & HIST_FIELD_FL_STACKTRACE) { |
| 5195 | memset(entries, 0, HIST_STACKTRACE_SIZE); | 5259 | memset(entries, 0, HIST_STACKTRACE_SIZE); |
| 5196 | stack_trace_save(entries, HIST_STACKTRACE_DEPTH, | 5260 | if (key_field->field) { |
| 5197 | HIST_STACKTRACE_SKIP); | 5261 | unsigned long *stack, n_entries; |
| 5262 | |||
| 5263 | field_contents = hist_fn_call(key_field, elt, buffer, rbe, rec); | ||
| 5264 | stack = (unsigned long *)(long)field_contents; | ||
| 5265 | n_entries = *stack; | ||
| 5266 | memcpy(entries, ++stack, n_entries * sizeof(unsigned long)); | ||
| 5267 | } else { | ||
| 5268 | stack_trace_save(entries, HIST_STACKTRACE_DEPTH, | ||
| 5269 | HIST_STACKTRACE_SKIP); | ||
| 5270 | } | ||
| 5198 | key = entries; | 5271 | key = entries; |
| 5199 | } else { | 5272 | } else { |
| 5200 | field_contents = hist_fn_call(key_field, elt, buffer, rbe, rec); | 5273 | field_contents = hist_fn_call(key_field, elt, buffer, rbe, rec); |
| @@ -5297,7 +5370,10 @@ static void hist_trigger_print_key(struct seq_file *m, · 96 unmodified lines | |||
| 5297 | seq_printf(m, "%s: %-30s[%3llu]", field_name, | 5370 | seq_printf(m, "%s: %-30s[%3llu]", field_name, |
| 5298 | syscall_name, uval); | 5371 | syscall_name, uval); |
| 5299 | } else if (key_field->flags & HIST_FIELD_FL_STACKTRACE) { | 5372 | } else if (key_field->flags & HIST_FIELD_FL_STACKTRACE) { |
| 5300 | seq_puts(m, "stacktrace:\n"); | 5373 | if (key_field->field) |
| 5374 | seq_printf(m, "%s.stacktrace", key_field->field->name); | ||
| 5375 | else | ||
| 5376 | seq_puts(m, "stacktrace:\n"); | ||
| 5301 | hist_trigger_stacktrace_print(m, | 5377 | hist_trigger_stacktrace_print(m, |
| 5302 | key + key_field->offset, | 5378 | key + key_field->offset, |
| 5303 | HIST_STACKTRACE_DEPTH); | 5379 | HIST_STACKTRACE_DEPTH); |
| @@ -5842,7 +5918,8 @@ static void hist_field_print(struct seq_file *m, struct hist_field *hist_field) · 538 unmodified lines | |||
| 5842 | 5918 | ||
| 5843 | if (hist_field->flags) { | 5919 | if (hist_field->flags) { |
| 5844 | if (!(hist_field->flags & HIST_FIELD_FL_VAR_REF) && | 5920 | if (!(hist_field->flags & HIST_FIELD_FL_VAR_REF) && |
| 5845 | !(hist_field->flags & HIST_FIELD_FL_EXPR)) { | 5921 | !(hist_field->flags & HIST_FIELD_FL_EXPR) && |
| 5922 | !(hist_field->flags & HIST_FIELD_FL_STACKTRACE)) { | ||
| 5846 | const char *flags = get_hist_field_flags(hist_field); | 5923 | const char *flags = get_hist_field_flags(hist_field); |
| 5847 | 5924 | ||
| 5848 | if (flags) | 5925 | if (flags) |
| @@ -5875,9 +5952,12 @@ static int event_hist_trigger_print(struct seq_file *m, · 26 unmodified lines | |||
| 5875 | if (i > hist_data->n_vals) | 5952 | if (i > hist_data->n_vals) |
| 5876 | seq_puts(m, ","); | 5953 | seq_puts(m, ","); |
| 5877 | 5954 | ||
| 5878 | if (field->flags & HIST_FIELD_FL_STACKTRACE) | 5955 | if (field->flags & HIST_FIELD_FL_STACKTRACE) { |
| 5879 | seq_puts(m, "stacktrace"); | 5956 | if (field->field) |
| 5880 | else | 5957 | seq_printf(m, "%s.stacktrace", field->field->name); |
| 5958 | else | ||
| 5959 | seq_puts(m, "stacktrace"); | ||
| 5960 | } else | ||
| 5881 | hist_field_print(m, field); | 5961 | hist_field_print(m, field); |
| 5882 | } | 5962 | } |
| 5883 | 5963 | ||
| @@ -173,6 +173,14 @@ static int synth_field_is_string(char *type) · 172 unmodified lines | |||
| 173 | return false; | 173 | return false; |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | static int synth_field_is_stack(char *type) | ||
| 177 | { | ||
| 178 | if (strstr(type, "long[") != NULL) | ||
| 179 | return true; | ||
| 180 | |||
| 181 | return false; | ||
| 182 | } | ||
| 183 | |||
| 176 | static int synth_field_string_size(char *type) | 184 | static int synth_field_string_size(char *type) |
| 177 | { | 185 | { |
| 178 | char buf[4], *end, *start; | 186 | char buf[4], *end, *start; |
| @@ -248,6 +256,8 @@ static int synth_field_size(char *type) · 69 unmodified lines | |||
| 248 | size = sizeof(gfp_t); | 256 | size = sizeof(gfp_t); |
| 249 | else if (synth_field_is_string(type)) | 257 | else if (synth_field_is_string(type)) |
| 250 | size = synth_field_string_size(type); | 258 | size = synth_field_string_size(type); |
| 259 | else if (synth_field_is_stack(type)) | ||
| 260 | size = 0; | ||
| 251 | 261 | ||
| 252 | return size; | 262 | return size; |
| 253 | } | 263 | } |
| @@ -292,6 +302,8 @@ static const char *synth_field_fmt(char *type) · 38 unmodified lines | |||
| 292 | fmt = "%x"; | 302 | fmt = "%x"; |
| 293 | else if (synth_field_is_string(type)) | 303 | else if (synth_field_is_string(type)) |
| 294 | fmt = "%.*s"; | 304 | fmt = "%.*s"; |
| 305 | else if (synth_field_is_stack(type)) | ||
| 306 | fmt = "%s"; | ||
| 295 | 307 | ||
| 296 | return fmt; | 308 | return fmt; |
| 297 | } | 309 | } |
| @@ -371,6 +383,23 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter, · 73 unmodified lines | |||
| 371 | i == se->n_fields - 1 ? "" : " "); | 383 | i == se->n_fields - 1 ? "" : " "); |
| 372 | n_u64 += STR_VAR_LEN_MAX / sizeof(u64); | 384 | n_u64 += STR_VAR_LEN_MAX / sizeof(u64); |
| 373 | } | 385 | } |
| 386 | } else if (se->fields[i]->is_stack) { | ||
| 387 | u32 offset, data_offset, len; | ||
| 388 | unsigned long *p, *end; | ||
| 389 | |||
| 390 | offset = (u32)entry->fields[n_u64]; | ||
| 391 | data_offset = offset & 0xffff; | ||
| 392 | len = offset >> 16; | ||
| 393 | |||
| 394 | p = (void *)entry + data_offset; | ||
| 395 | end = (void *)p + len - (sizeof(long) - 1); | ||
| 396 | |||
| 397 | trace_seq_printf(s, "%s=STACK:\n", se->fields[i]->name); | ||
| 398 | |||
| 399 | for (; *p && p < end; p++) | ||
| 400 | trace_seq_printf(s, "=> %pS\n", (void *)*p); | ||
| 401 | n_u64++; | ||
| 402 | |||
| 374 | } else { | 403 | } else { |
| 375 | struct trace_print_flags __flags[] = { | 404 | struct trace_print_flags __flags[] = { |
| 376 | __def_gfpflag_names, {-1, NULL} }; | 405 | __def_gfpflag_names, {-1, NULL} }; |
| @@ -416,8 +445,7 @@ static unsigned int trace_string(struct synth_trace_event *entry, · 39 unmodified lines | |||
| 416 | if (is_dynamic) { | 445 | if (is_dynamic) { |
| 417 | u32 data_offset; | 446 | u32 data_offset; |
| 418 | 447 | ||
| 419 | data_offset = offsetof(typeof(*entry), fields); | 448 | data_offset = struct_size(entry, fields, event->n_u64); |
| 420 | data_offset += event->n_u64 * sizeof(u64); | ||
| 421 | data_offset += data_size; | 449 | data_offset += data_size; |
| 422 | 450 | ||
| 423 | len = kern_fetch_store_strlen((unsigned long)str_val); | 451 | len = kern_fetch_store_strlen((unsigned long)str_val); |
| @@ -447,6 +475,43 @@ static unsigned int trace_string(struct synth_trace_event *entry, · 23 unmodified lines | |||
| 447 | return len; | 475 | return len; |
| 448 | } | 476 | } |
| 449 | 477 | ||
| 478 | static unsigned int trace_stack(struct synth_trace_event *entry, | ||
| 479 | struct synth_event *event, | ||
| 480 | long *stack, | ||
| 481 | unsigned int data_size, | ||
| 482 | unsigned int *n_u64) | ||
| 483 | { | ||
| 484 | unsigned int len; | ||
| 485 | u32 data_offset; | ||
| 486 | void *data_loc; | ||
| 487 | |||
| 488 | data_offset = struct_size(entry, fields, event->n_u64); | ||
| 489 | data_offset += data_size; | ||
| 490 | |||
| 491 | for (len = 0; len < HIST_STACKTRACE_DEPTH; len++) { | ||
| 492 | if (!stack[len]) | ||
| 493 | break; | ||
| 494 | } | ||
| 495 | |||
| 496 | /* Include the zero'd element if it fits */ | ||
| 497 | if (len < HIST_STACKTRACE_DEPTH) | ||
| 498 | len++; | ||
| 499 | |||
| 500 | len *= sizeof(long); | ||
| 501 | |||
| 502 | /* Find the dynamic section to copy the stack into. */ | ||
| 503 | data_loc = (void *)entry + data_offset; | ||
| 504 | memcpy(data_loc, stack, len); | ||
| 505 | |||
| 506 | /* Fill in the field that holds the offset/len combo */ | ||
| 507 | data_offset |= len << 16; | ||
| 508 | *(u32 *)&entry->fields[*n_u64] = data_offset; | ||
| 509 | |||
| 510 | (*n_u64)++; | ||
| 511 | |||
| 512 | return len; | ||
| 513 | } | ||
| 514 | |||
| 450 | static notrace void trace_event_raw_event_synth(void *__data, | 515 | static notrace void trace_event_raw_event_synth(void *__data, |
| 451 | u64 *var_ref_vals, | 516 | u64 *var_ref_vals, |
| 452 | unsigned int *var_ref_idx) | 517 | unsigned int *var_ref_idx) |
| @@ -473,7 +538,12 @@ static notrace void trace_event_raw_event_synth(void *__data, · 20 unmodified lines | |||
| 473 | val_idx = var_ref_idx[field_pos]; | 538 | val_idx = var_ref_idx[field_pos]; |
| 474 | str_val = (char *)(long)var_ref_vals[val_idx]; | 539 | str_val = (char *)(long)var_ref_vals[val_idx]; |
| 475 | 540 | ||
| 476 | len = kern_fetch_store_strlen((unsigned long)str_val); | 541 | if (event->dynamic_fields[i]->is_stack) { |
| 542 | len = *((unsigned long *)str_val); | ||
| 543 | len *= sizeof(unsigned long); | ||
| 544 | } else { | ||
| 545 | len = kern_fetch_store_strlen((unsigned long)str_val); | ||
| 546 | } | ||
| 477 | 547 | ||
| 478 | fields_size += len; | 548 | fields_size += len; |
| 479 | } | 549 | } |
| @@ -499,6 +569,12 @@ static notrace void trace_event_raw_event_synth(void *__data, · 19 unmodified lines | |||
| 499 | event->fields[i]->is_dynamic, | 569 | event->fields[i]->is_dynamic, |
| 500 | data_size, &n_u64); | 570 | data_size, &n_u64); |
| 501 | data_size += len; /* only dynamic string increments */ | 571 | data_size += len; /* only dynamic string increments */ |
| 572 | } else if (event->fields[i]->is_stack) { | ||
| 573 | long *stack = (long *)(long)var_ref_vals[val_idx]; | ||
| 574 | |||
| 575 | len = trace_stack(entry, event, stack, | ||
| 576 | data_size, &n_u64); | ||
| 577 | data_size += len; | ||
| 502 | } else { | 578 | } else { |
| 503 | struct synth_field *field = event->fields[i]; | 579 | struct synth_field *field = event->fields[i]; |
| 504 | u64 val = var_ref_vals[val_idx]; | 580 | u64 val = var_ref_vals[val_idx]; |
| @@ -561,6 +637,9 @@ static int __set_synth_event_print_fmt(struct synth_event *event, · 56 unmodified lines | |||
| 561 | event->fields[i]->is_dynamic) | 637 | event->fields[i]->is_dynamic) |
| 562 | pos += snprintf(buf + pos, LEN_OR_ZERO, | 638 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
| 563 | ", __get_str(%s)", event->fields[i]->name); | 639 | ", __get_str(%s)", event->fields[i]->name); |
| 640 | else if (event->fields[i]->is_stack) | ||
| 641 | pos += snprintf(buf + pos, LEN_OR_ZERO, | ||
| 642 | ", __get_stacktrace(%s)", event->fields[i]->name); | ||
| 564 | else | 643 | else |
| 565 | pos += snprintf(buf + pos, LEN_OR_ZERO, | 644 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
| 566 | ", REC->%s", event->fields[i]->name); | 645 | ", REC->%s", event->fields[i]->name); |
| @@ -697,7 +776,8 @@ static struct synth_field *parse_synth_field(int argc, char **argv, · 130 unmodified lines | |||
| 697 | ret = -EINVAL; | 776 | ret = -EINVAL; |
| 698 | goto free; | 777 | goto free; |
| 699 | } else if (size == 0) { | 778 | } else if (size == 0) { |
| 700 | if (synth_field_is_string(field->type)) { | 779 | if (synth_field_is_string(field->type) || |
| 780 | synth_field_is_stack(field->type)) { | ||
| 701 | char *type; | 781 | char *type; |
| 702 | 782 | ||
| 703 | len = sizeof("__data_loc ") + strlen(field->type) + 1; | 783 | len = sizeof("__data_loc ") + strlen(field->type) + 1; |
| @@ -728,6 +808,8 @@ static struct synth_field *parse_synth_field(int argc, char **argv, · 24 unmodified lines | |||
| 728 | 808 | ||
| 729 | if (synth_field_is_string(field->type)) | 809 | if (synth_field_is_string(field->type)) |
| 730 | field->is_string = true; | 810 | field->is_string = true; |
| 811 | else if (synth_field_is_stack(field->type)) | ||
| 812 | field->is_stack = true; | ||
| 731 | 813 | ||
| 732 | field->is_signed = synth_field_signed(field->type); | 814 | field->is_signed = synth_field_signed(field->type); |
| 733 | out: | 815 | out: |
| @@ -1539,7 +1539,7 @@ static void osnoise_sleep(void) · 1538 unmodified lines | |||
| 1539 | wake_time = ktime_add_us(ktime_get(), interval); | 1539 | wake_time = ktime_add_us(ktime_get(), interval); |
| 1540 | __set_current_state(TASK_INTERRUPTIBLE); | 1540 | __set_current_state(TASK_INTERRUPTIBLE); |
| 1541 | 1541 | ||
| 1542 | while (schedule_hrtimeout_range(&wake_time, 0, HRTIMER_MODE_ABS)) { | 1542 | while (schedule_hrtimeout(&wake_time, HRTIMER_MODE_ABS)) { |
| 1543 | if (kthread_should_stop()) | 1543 | if (kthread_should_stop()) |
| 1544 | break; | 1544 | break; |
| 1545 | } | 1545 | } |
| @@ -403,3 +403,26 @@ int trace_seq_hex_dump(struct trace_seq *s, const char *prefix_str, · 402 unmodified lines | |||
| 403 | return 1; | 403 | return 1; |
| 404 | } | 404 | } |
| 405 | EXPORT_SYMBOL(trace_seq_hex_dump); | 405 | EXPORT_SYMBOL(trace_seq_hex_dump); |
| 406 | |||
| 407 | /* | ||
| 408 | * trace_seq_acquire - acquire seq buffer with size len | ||
| 409 | * @s: trace sequence descriptor | ||
| 410 | * @len: size of buffer to be acquired | ||
| 411 | * | ||
| 412 | * acquire buffer with size of @len from trace_seq for output usage, | ||
| 413 | * user can fill string into that buffer. | ||
| 414 | * | ||
| 415 | * Returns start address of acquired buffer. | ||
| 416 | * | ||
| 417 | * it allow multiple usage in one trace output function call. | ||
| 418 | */ | ||
| 419 | char *trace_seq_acquire(struct trace_seq *s, unsigned int len) | ||
| 420 | { | ||
| 421 | char *ret = trace_seq_buffer_ptr(s); | ||
| 422 | |||
| 423 | if (!WARN_ON_ONCE(seq_buf_buffer_left(&s->seq) < len)) | ||
| 424 | seq_buf_commit(&s->seq, len); | ||
| 425 | |||
| 426 | return ret; | ||
| 427 | } | ||
| 428 | EXPORT_SYMBOL(trace_seq_acquire); | ||
| @@ -18,6 +18,7 @@ struct synth_field { · 17 unmodified lines | |||
| 18 | bool is_signed; | 18 | bool is_signed; |
| 19 | bool is_string; | 19 | bool is_string; |
| 20 | bool is_dynamic; | 20 | bool is_dynamic; |
| 21 | bool is_stack; | ||
| 21 | }; | 22 | }; |
| 22 | 23 | ||
| 23 | struct synth_event { | 24 | struct synth_event { |
| @@ -571,8 +571,8 @@ static void for_each_tracepoint_range( · 570 unmodified lines | |||
| 571 | bool trace_module_has_bad_taint(struct module *mod) | 571 | bool trace_module_has_bad_taint(struct module *mod) |
| 572 | { | 572 | { |
| 573 | return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP) | | 573 | return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP) | |
| 574 | (1 << TAINT_UNSIGNED_MODULE) | | 574 | (1 << TAINT_UNSIGNED_MODULE) | (1 << TAINT_TEST) | |
| 575 | (1 << TAINT_TEST)); | 575 | (1 << TAINT_LIVEPATCH)); |
| 576 | } | 576 | } |
| 577 | 577 | ||
| 578 | static BLOCKING_NOTIFIER_HEAD(tracepoint_notify_list); | 578 | static BLOCKING_NOTIFIER_HEAD(tracepoint_notify_list); |
| @@ -46,6 +46,13 @@ config SAMPLE_FTRACE_DIRECT_MULTI · 45 unmodified lines | |||
| 46 | that hooks to wake_up_process and schedule, and prints | 46 | that hooks to wake_up_process and schedule, and prints |
| 47 | the function addresses. | 47 | the function addresses. |
| 48 | 48 | ||
| 49 | config SAMPLE_FTRACE_OPS | ||
| 50 | tristate "Build custom ftrace ops example" | ||
| 51 | depends on FUNCTION_TRACER | ||
| 52 | help | ||
| 53 | This builds an ftrace ops example that hooks two functions and | ||
| 54 | measures the time taken to invoke one function a number of times. | ||
| 55 | |||
| 49 | config SAMPLE_TRACE_ARRAY | 56 | config SAMPLE_TRACE_ARRAY |
| 50 | tristate "Build sample module for kernel access to Ftrace instancess" | 57 | tristate "Build sample module for kernel access to Ftrace instancess" |
| 51 | depends on EVENT_TRACING && m | 58 | depends on EVENT_TRACING && m |
| @@ -24,6 +24,7 @@ obj-$(CONFIG_SAMPLE_TRACE_CUSTOM_EVENTS) += trace_events/ · 23 unmodified lines | |||
| 24 | obj-$(CONFIG_SAMPLE_TRACE_PRINTK) += trace_printk/ | 24 | obj-$(CONFIG_SAMPLE_TRACE_PRINTK) += trace_printk/ |
| 25 | obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace/ | 25 | obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace/ |
| 26 | obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace/ | 26 | obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace/ |
| 27 | obj-$(CONFIG_SAMPLE_FTRACE_OPS) += ftrace/ | ||
| 27 | obj-$(CONFIG_SAMPLE_TRACE_ARRAY) += ftrace/ | 28 | obj-$(CONFIG_SAMPLE_TRACE_ARRAY) += ftrace/ |
| 28 | subdir-$(CONFIG_SAMPLE_UHID) += uhid | 29 | subdir-$(CONFIG_SAMPLE_UHID) += uhid |
| 29 | obj-$(CONFIG_VIDEO_PCI_SKELETON) += v4l/ | 30 | obj-$(CONFIG_VIDEO_PCI_SKELETON) += v4l/ |
| @@ -5,6 +5,7 @@ obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-too.o · 4 unmodified lines | |||
| 5 | obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-modify.o | 5 | obj-$(CONFIG_SAMPLE_FTRACE_DIRECT) += ftrace-direct-modify.o |
| 6 | obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace-direct-multi.o | 6 | obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace-direct-multi.o |
| 7 | obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace-direct-multi-modify.o | 7 | obj-$(CONFIG_SAMPLE_FTRACE_DIRECT_MULTI) += ftrace-direct-multi-modify.o |
| 8 | obj-$(CONFIG_SAMPLE_FTRACE_OPS) += ftrace-ops.o | ||
| 8 | 9 | ||
| 9 | CFLAGS_sample-trace-array.o := -I$(src) | 10 | CFLAGS_sample-trace-array.o := -I$(src) |
| 10 | obj-$(CONFIG_SAMPLE_TRACE_ARRAY) += sample-trace-array.o | 11 | obj-$(CONFIG_SAMPLE_TRACE_ARRAY) += sample-trace-array.o |
| @@ -3,7 +3,6 @@ · 2 unmodified lines | |||
| 3 | #include <linux/kthread.h> | 3 | #include <linux/kthread.h> |
| 4 | #include <linux/ftrace.h> | 4 | #include <linux/ftrace.h> |
| 5 | #include <asm/asm-offsets.h> | 5 | #include <asm/asm-offsets.h> |
| 6 | #include <asm/nospec-branch.h> | ||
| 7 | 6 | ||
| 8 | extern void my_direct_func1(void); | 7 | extern void my_direct_func1(void); |
| 9 | extern void my_direct_func2(void); | 8 | extern void my_direct_func2(void); |
| @@ -26,6 +25,7 @@ static unsigned long my_ip = (unsigned long)schedule; · 16 unmodified lines | |||
| 26 | #ifdef CONFIG_X86_64 | 25 | #ifdef CONFIG_X86_64 |
| 27 | 26 | ||
| 28 | #include <asm/ibt.h> | 27 | #include <asm/ibt.h> |
| 28 | #include <asm/nospec-branch.h> | ||
| 29 | 29 | ||
| 30 | asm ( | 30 | asm ( |
| 31 | " .pushsection .text, \"ax\", @progbits\n" | 31 | " .pushsection .text, \"ax\", @progbits\n" |
| @@ -3,7 +3,6 @@ · 2 unmodified lines | |||
| 3 | #include <linux/kthread.h> | 3 | #include <linux/kthread.h> |
| 4 | #include <linux/ftrace.h> | 4 | #include <linux/ftrace.h> |
| 5 | #include <asm/asm-offsets.h> | 5 | #include <asm/asm-offsets.h> |
| 6 | #include <asm/nospec-branch.h> | ||
| 7 | 6 | ||
| 8 | extern void my_direct_func1(unsigned long ip); | 7 | extern void my_direct_func1(unsigned long ip); |
| 9 | extern void my_direct_func2(unsigned long ip); | 8 | extern void my_direct_func2(unsigned long ip); |
| @@ -24,6 +23,7 @@ extern void my_tramp2(void *); · 14 unmodified lines | |||
| 24 | #ifdef CONFIG_X86_64 | 23 | #ifdef CONFIG_X86_64 |
| 25 | 24 | ||
| 26 | #include <asm/ibt.h> | 25 | #include <asm/ibt.h> |
| 26 | #include <asm/nospec-branch.h> | ||
| 27 | 27 | ||
| 28 | asm ( | 28 | asm ( |
| 29 | " .pushsection .text, \"ax\", @progbits\n" | 29 | " .pushsection .text, \"ax\", @progbits\n" |
| @@ -5,7 +5,6 @@ · 4 unmodified lines | |||
| 5 | #include <linux/ftrace.h> | 5 | #include <linux/ftrace.h> |
| 6 | #include <linux/sched/stat.h> | 6 | #include <linux/sched/stat.h> |
| 7 | #include <asm/asm-offsets.h> | 7 | #include <asm/asm-offsets.h> |
| 8 | #include <asm/nospec-branch.h> | ||
| 9 | 8 | ||
| 10 | extern void my_direct_func(unsigned long ip); | 9 | extern void my_direct_func(unsigned long ip); |
| 11 | 10 | ||
| @@ -19,6 +18,7 @@ extern void my_tramp(void *); · 7 unmodified lines | |||
| 19 | #ifdef CONFIG_X86_64 | 18 | #ifdef CONFIG_X86_64 |
| 20 | 19 | ||
| 21 | #include <asm/ibt.h> | 20 | #include <asm/ibt.h> |
| 21 | #include <asm/nospec-branch.h> | ||
| 22 | 22 | ||
| 23 | asm ( | 23 | asm ( |
| 24 | " .pushsection .text, \"ax\", @progbits\n" | 24 | " .pushsection .text, \"ax\", @progbits\n" |
| @@ -4,7 +4,6 @@ · 3 unmodified lines | |||
| 4 | #include <linux/mm.h> /* for handle_mm_fault() */ | 4 | #include <linux/mm.h> /* for handle_mm_fault() */ |
| 5 | #include <linux/ftrace.h> | 5 | #include <linux/ftrace.h> |
| 6 | #include <asm/asm-offsets.h> | 6 | #include <asm/asm-offsets.h> |
| 7 | #include <asm/nospec-branch.h> | ||
| 8 | 7 | ||
| 9 | extern void my_direct_func(struct vm_area_struct *vma, | 8 | extern void my_direct_func(struct vm_area_struct *vma, |
| 10 | unsigned long address, unsigned int flags); | 9 | unsigned long address, unsigned int flags); |
| @@ -21,6 +20,7 @@ extern void my_tramp(void *); · 10 unmodified lines | |||
| 21 | #ifdef CONFIG_X86_64 | 20 | #ifdef CONFIG_X86_64 |
| 22 | 21 | ||
| 23 | #include <asm/ibt.h> | 22 | #include <asm/ibt.h> |
| 23 | #include <asm/nospec-branch.h> | ||
| 24 | 24 | ||
| 25 | asm ( | 25 | asm ( |
| 26 | " .pushsection .text, \"ax\", @progbits\n" | 26 | " .pushsection .text, \"ax\", @progbits\n" |
| @@ -4,7 +4,6 @@ · 3 unmodified lines | |||
| 4 | #include <linux/sched.h> /* for wake_up_process() */ | 4 | #include <linux/sched.h> /* for wake_up_process() */ |
| 5 | #include <linux/ftrace.h> | 5 | #include <linux/ftrace.h> |
| 6 | #include <asm/asm-offsets.h> | 6 | #include <asm/asm-offsets.h> |
| 7 | #include <asm/nospec-branch.h> | ||
| 8 | 7 | ||
| 9 | extern void my_direct_func(struct task_struct *p); | 8 | extern void my_direct_func(struct task_struct *p); |
| 10 | 9 | ||
| @@ -18,6 +17,7 @@ extern void my_tramp(void *); · 7 unmodified lines | |||
| 18 | #ifdef CONFIG_X86_64 | 17 | #ifdef CONFIG_X86_64 |
| 19 | 18 | ||
| 20 | #include <asm/ibt.h> | 19 | #include <asm/ibt.h> |
| 20 | #include <asm/nospec-branch.h> | ||
| 21 | 21 | ||
| 22 | asm ( | 22 | asm ( |
| 23 | " .pushsection .text, \"ax\", @progbits\n" | 23 | " .pushsection .text, \"ax\", @progbits\n" |
| @@ -0,0 +1,252 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | |||
| 3 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 4 | |||
| 5 | #include <linux/ftrace.h> | ||
| 6 | #include <linux/ktime.h> | ||
| 7 | #include <linux/module.h> | ||
| 8 | |||
| 9 | #include <asm/barrier.h> | ||
| 10 | |||
| 11 | /* | ||
| 12 | * Arbitrary large value chosen to be sufficiently large to minimize noise but | ||
| 13 | * sufficiently small to complete quickly. | ||
| 14 | */ | ||
| 15 | static unsigned int nr_function_calls = 100000; | ||
| 16 | module_param(nr_function_calls, uint, 0); | ||
| 17 | MODULE_PARM_DESC(nr_function_calls, "How many times to call the relevant tracee"); | ||
| 18 | |||
| 19 | /* | ||
| 20 | * The number of ops associated with a call site affects whether a tracer can | ||
| 21 | * be called directly or whether it's necessary to go via the list func, which | ||
| 22 | * can be significantly more expensive. | ||
| 23 | */ | ||
| 24 | static unsigned int nr_ops_relevant = 1; | ||
| 25 | module_param(nr_ops_relevant, uint, 0); | ||
| 26 | MODULE_PARM_DESC(nr_ops_relevant, "How many ftrace_ops to associate with the relevant tracee"); | ||
| 27 | |||
| 28 | /* | ||
| 29 | * On architectures where all call sites share the same trampoline, having | ||
| 30 | * tracers enabled for distinct functions can force the use of the list func | ||
| 31 | * and incur overhead for all call sites. | ||
| 32 | */ | ||
| 33 | static unsigned int nr_ops_irrelevant; | ||
| 34 | module_param(nr_ops_irrelevant, uint, 0); | ||
| 35 | MODULE_PARM_DESC(nr_ops_irrelevant, "How many ftrace_ops to associate with the irrelevant tracee"); | ||
| 36 | |||
| 37 | /* | ||
| 38 | * On architectures with DYNAMIC_FTRACE_WITH_REGS, saving the full pt_regs can | ||
| 39 | * be more expensive than only saving the minimal necessary regs. | ||
| 40 | */ | ||
| 41 | static bool save_regs; | ||
| 42 | module_param(save_regs, bool, 0); | ||
| 43 | MODULE_PARM_DESC(save_regs, "Register ops with FTRACE_OPS_FL_SAVE_REGS (save all registers in the trampoline)"); | ||
| 44 | |||
| 45 | static bool assist_recursion; | ||
| 46 | module_param(assist_recursion, bool, 0); | ||
| 47 | MODULE_PARM_DESC(assist_reursion, "Register ops with FTRACE_OPS_FL_RECURSION"); | ||
| 48 | |||
| 49 | static bool assist_rcu; | ||
| 50 | module_param(assist_rcu, bool, 0); | ||
| 51 | MODULE_PARM_DESC(assist_reursion, "Register ops with FTRACE_OPS_FL_RCU"); | ||
| 52 | |||
| 53 | /* | ||
| 54 | * By default, a trivial tracer is used which immediately returns to mimimize | ||
| 55 | * overhead. Sometimes a consistency check using a more expensive tracer is | ||
| 56 | * desireable. | ||
| 57 | */ | ||
| 58 | static bool check_count; | ||
| 59 | module_param(check_count, bool, 0); | ||
| 60 | MODULE_PARM_DESC(check_count, "Check that tracers are called the expected number of times\n"); | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Usually it's not interesting to leave the ops registered after the test | ||
| 64 | * runs, but sometimes it can be useful to leave them registered so that they | ||
| 65 | * can be inspected through the tracefs 'enabled_functions' file. | ||
| 66 | */ | ||
| 67 | static bool persist; | ||
| 68 | module_param(persist, bool, 0); | ||
| 69 | MODULE_PARM_DESC(persist, "Successfully load module and leave ftrace ops registered after test completes\n"); | ||
| 70 | |||
| 71 | /* | ||
| 72 | * Marked as noinline to ensure that an out-of-line traceable copy is | ||
| 73 | * generated by the compiler. | ||
| 74 | * | ||
| 75 | * The barrier() ensures the compiler won't elide calls by determining there | ||
| 76 | * are no side-effects. | ||
| 77 | */ | ||
| 78 | static noinline void tracee_relevant(void) | ||
| 79 | { | ||
| 80 | barrier(); | ||
| 81 | } | ||
| 82 | |||
| 83 | /* | ||
| 84 | * Marked as noinline to ensure that an out-of-line traceable copy is | ||
| 85 | * generated by the compiler. | ||
| 86 | * | ||
| 87 | * The barrier() ensures the compiler won't elide calls by determining there | ||
| 88 | * are no side-effects. | ||
| 89 | */ | ||
| 90 | static noinline void tracee_irrelevant(void) | ||
| 91 | { | ||
| 92 | barrier(); | ||
| 93 | } | ||
| 94 | |||
| 95 | struct sample_ops { | ||
| 96 | struct ftrace_ops ops; | ||
| 97 | unsigned int count; | ||
| 98 | }; | ||
| 99 | |||
| 100 | static void ops_func_nop(unsigned long ip, unsigned long parent_ip, | ||
| 101 | struct ftrace_ops *op, | ||
| 102 | struct ftrace_regs *fregs) | ||
| 103 | { | ||
| 104 | /* do nothing */ | ||
| 105 | } | ||
| 106 | |||
| 107 | static void ops_func_count(unsigned long ip, unsigned long parent_ip, | ||
| 108 | struct ftrace_ops *op, | ||
| 109 | struct ftrace_regs *fregs) | ||
| 110 | { | ||
| 111 | struct sample_ops *self; | ||
| 112 | |||
| 113 | self = container_of(op, struct sample_ops, ops); | ||
| 114 | self->count++; | ||
| 115 | } | ||
| 116 | |||
| 117 | static struct sample_ops *ops_relevant; | ||
| 118 | static struct sample_ops *ops_irrelevant; | ||
| 119 | |||
| 120 | static struct sample_ops *ops_alloc_init(void *tracee, ftrace_func_t func, | ||
| 121 | unsigned long flags, int nr) | ||
| 122 | { | ||
| 123 | struct sample_ops *ops; | ||
| 124 | |||
| 125 | ops = kcalloc(nr, sizeof(*ops), GFP_KERNEL); | ||
| 126 | if (WARN_ON_ONCE(!ops)) | ||
| 127 | return NULL; | ||
| 128 | |||
| 129 | for (unsigned int i = 0; i < nr; i++) { | ||
| 130 | ops[i].ops.func = func; | ||
| 131 | ops[i].ops.flags = flags; | ||
| 132 | WARN_ON_ONCE(ftrace_set_filter_ip(&ops[i].ops, (unsigned long)tracee, 0, 0)); | ||
| 133 | WARN_ON_ONCE(register_ftrace_function(&ops[i].ops)); | ||
| 134 | } | ||
| 135 | |||
| 136 | return ops; | ||
| 137 | } | ||
| 138 | |||
| 139 | static void ops_destroy(struct sample_ops *ops, int nr) | ||
| 140 | { | ||
| 141 | if (!ops) | ||
| 142 | return; | ||
| 143 | |||
| 144 | for (unsigned int i = 0; i < nr; i++) { | ||
| 145 | WARN_ON_ONCE(unregister_ftrace_function(&ops[i].ops)); | ||
| 146 | ftrace_free_filter(&ops[i].ops); | ||
| 147 | } | ||
| 148 | |||
| 149 | kfree(ops); | ||
| 150 | } | ||
| 151 | |||
| 152 | static void ops_check(struct sample_ops *ops, int nr, | ||
| 153 | unsigned int expected_count) | ||
| 154 | { | ||
| 155 | if (!ops || !check_count) | ||
| 156 | return; | ||
| 157 | |||
| 158 | for (unsigned int i = 0; i < nr; i++) { | ||
| 159 | if (ops->count == expected_count) | ||
| 160 | continue; | ||
| 161 | pr_warn("Counter called %u times (expected %u)\n", | ||
| 162 | ops->count, expected_count); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | static ftrace_func_t tracer_relevant = ops_func_nop; | ||
| 167 | static ftrace_func_t tracer_irrelevant = ops_func_nop; | ||
| 168 | |||
| 169 | static int __init ftrace_ops_sample_init(void) | ||
| 170 | { | ||
| 171 | unsigned long flags = 0; | ||
| 172 | ktime_t start, end; | ||
| 173 | u64 period; | ||
| 174 | |||
| 175 | if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS) && save_regs) { | ||
| 176 | pr_info("this kernel does not support saving registers\n"); | ||
| 177 | save_regs = false; | ||
| 178 | } else if (save_regs) { | ||
| 179 | flags |= FTRACE_OPS_FL_SAVE_REGS; | ||
| 180 | } | ||
| 181 | |||
| 182 | if (assist_recursion) | ||
| 183 | flags |= FTRACE_OPS_FL_RECURSION; | ||
| 184 | |||
| 185 | if (assist_rcu) | ||
| 186 | flags |= FTRACE_OPS_FL_RCU; | ||
| 187 | |||
| 188 | if (check_count) { | ||
| 189 | tracer_relevant = ops_func_count; | ||
| 190 | tracer_irrelevant = ops_func_count; | ||
| 191 | } | ||
| 192 | |||
| 193 | pr_info("registering:\n" | ||
| 194 | " relevant ops: %u\n" | ||
| 195 | " tracee: %ps\n" | ||
| 196 | " tracer: %ps\n" | ||
| 197 | " irrelevant ops: %u\n" | ||
| 198 | " tracee: %ps\n" | ||
| 199 | " tracer: %ps\n" | ||
| 200 | " saving registers: %s\n" | ||
| 201 | " assist recursion: %s\n" | ||
| 202 | " assist RCU: %s\n", | ||
| 203 | nr_ops_relevant, tracee_relevant, tracer_relevant, | ||
| 204 | nr_ops_irrelevant, tracee_irrelevant, tracer_irrelevant, | ||
| 205 | save_regs ? "YES" : "NO", | ||
| 206 | assist_recursion ? "YES" : "NO", | ||
| 207 | assist_rcu ? "YES" : "NO"); | ||
| 208 | |||
| 209 | ops_relevant = ops_alloc_init(tracee_relevant, tracer_relevant, | ||
| 210 | flags, nr_ops_relevant); | ||
| 211 | ops_irrelevant = ops_alloc_init(tracee_irrelevant, tracer_irrelevant, | ||
| 212 | flags, nr_ops_irrelevant); | ||
| 213 | |||
| 214 | start = ktime_get(); | ||
| 215 | for (unsigned int i = 0; i < nr_function_calls; i++) | ||
| 216 | tracee_relevant(); | ||
| 217 | end = ktime_get(); | ||
| 218 | |||
| 219 | ops_check(ops_relevant, nr_ops_relevant, nr_function_calls); | ||
| 220 | ops_check(ops_irrelevant, nr_ops_irrelevant, 0); | ||
| 221 | |||
| 222 | period = ktime_to_ns(ktime_sub(end, start)); | ||
| 223 | |||
| 224 | pr_info("Attempted %u calls to %ps in %lluns (%lluns / call)\n", | ||
| 225 | nr_function_calls, tracee_relevant, | ||
| 226 | period, div_u64(period, nr_function_calls)); | ||
| 227 | |||
| 228 | if (persist) | ||
| 229 | return 0; | ||
| 230 | |||
| 231 | ops_destroy(ops_relevant, nr_ops_relevant); | ||
| 232 | ops_destroy(ops_irrelevant, nr_ops_irrelevant); | ||
| 233 | |||
| 234 | /* | ||
| 235 | * The benchmark completed sucessfully, but there's no reason to keep | ||
| 236 | * the module around. Return an error do the user doesn't have to | ||
| 237 | * manually unload the module. | ||
| 238 | */ | ||
| 239 | return -EINVAL; | ||
| 240 | } | ||
| 241 | module_init(ftrace_ops_sample_init); | ||
| 242 | |||
| 243 | static void __exit ftrace_ops_sample_exit(void) | ||
| 244 | { | ||
| 245 | ops_destroy(ops_relevant, nr_ops_relevant); | ||
| 246 | ops_destroy(ops_irrelevant, nr_ops_irrelevant); | ||
| 247 | } | ||
| 248 | module_exit(ftrace_ops_sample_exit); | ||
| 249 | |||
| 250 | MODULE_AUTHOR("Mark Rutland"); | ||
| 251 | MODULE_DESCRIPTION("Example of using custom ftrace_ops"); | ||
| 252 | MODULE_LICENSE("GPL"); | ||
| @@ -23,8 +23,8 @@ · 22 unmodified lines | |||
| 23 | #endif | 23 | #endif |
| 24 | 24 | ||
| 25 | /* Assumes debugfs is mounted */ | 25 | /* Assumes debugfs is mounted */ |
| 26 | const char *data_file = "/sys/kernel/debug/tracing/user_events_data"; | 26 | const char *data_file = "/sys/kernel/tracing/user_events_data"; |
| 27 | const char *status_file = "/sys/kernel/debug/tracing/user_events_status"; | 27 | const char *status_file = "/sys/kernel/tracing/user_events_status"; |
| 28 | 28 | ||
| 29 | static int event_status(long **status) | 29 | static int event_status(long **status) |
| 30 | { | 30 | { |
| @@ -12,9 +12,9 @@ calls. Only the functions's names and the call time are provided. · 11 unmodified lines | |||
| 12 | 12 | ||
| 13 | Usage: | 13 | Usage: |
| 14 | Be sure that you have CONFIG_FUNCTION_TRACER | 14 | Be sure that you have CONFIG_FUNCTION_TRACER |
| 15 | # mount -t debugfs nodev /sys/kernel/debug | 15 | # mount -t tracefs nodev /sys/kernel/tracing |
| 16 | # echo function > /sys/kernel/debug/tracing/current_tracer | 16 | # echo function > /sys/kernel/tracing/current_tracer |
| 17 | $ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func | 17 | $ cat /sys/kernel/tracing/trace_pipe > ~/raw_trace_func |
| 18 | Wait some times but not too much, the script is a bit slow. | 18 | Wait some times but not too much, the script is a bit slow. |
| 19 | Break the pipe (Ctrl + Z) | 19 | Break the pipe (Ctrl + Z) |
| 20 | $ scripts/tracing/draw_functrace.py < ~/raw_trace_func > draw_functrace | 20 | $ scripts/tracing/draw_functrace.py < ~/raw_trace_func > draw_functrace |
| @@ -14,8 +14,8 @@ · 13 unmodified lines | |||
| 14 | #include "tracing_path.h" | 14 | #include "tracing_path.h" |
| 15 | 15 | ||
| 16 | static char tracing_mnt[PATH_MAX] = "/sys/kernel/debug"; | 16 | static char tracing_mnt[PATH_MAX] = "/sys/kernel/debug"; |
| 17 | static char tracing_path[PATH_MAX] = "/sys/kernel/debug/tracing"; | 17 | static char tracing_path[PATH_MAX] = "/sys/kernel/tracing"; |
| 18 | static char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events"; | 18 | static char tracing_events_path[PATH_MAX] = "/sys/kernel/tracing/events"; |
| 19 | 19 | ||
| 20 | static void __tracing_path_set(const char *tracing, const char *mountpoint) | 20 | static void __tracing_path_set(const char *tracing, const char *mountpoint) |
| 21 | { | 21 | { |
| @@ -0,0 +1,58 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | # description: event filter function - test event filtering on functions | ||
| 4 | # requires: set_event events/kmem/kmem_cache_free/filter | ||
| 5 | # flags: instance | ||
| 6 | |||
| 7 | fail() { #msg | ||
| 8 | echo $1 | ||
| 9 | exit_fail | ||
| 10 | } | ||
| 11 | |||
| 12 | echo "Test event filter function name" | ||
| 13 | echo 0 > tracing_on | ||
| 14 | echo 0 > events/enable | ||
| 15 | echo > trace | ||
| 16 | echo 'call_site.function == exit_mmap' > events/kmem/kmem_cache_free/filter | ||
| 17 | echo 1 > events/kmem/kmem_cache_free/enable | ||
| 18 | echo 1 > tracing_on | ||
| 19 | ls > /dev/null | ||
| 20 | echo 0 > events/kmem/kmem_cache_free/enable | ||
| 21 | |||
| 22 | hitcnt=`grep kmem_cache_free trace| grep exit_mmap | wc -l` | ||
| 23 | misscnt=`grep kmem_cache_free trace| grep -v exit_mmap | wc -l` | ||
| 24 | |||
| 25 | if [ $hitcnt -eq 0 ]; then | ||
| 26 | exit_fail | ||
| 27 | fi | ||
| 28 | |||
| 29 | if [ $misscnt -gt 0 ]; then | ||
| 30 | exit_fail | ||
| 31 | fi | ||
| 32 | |||
| 33 | address=`grep ' exit_mmap$' /proc/kallsyms | cut -d' ' -f1` | ||
| 34 | |||
| 35 | echo "Test event filter function address" | ||
| 36 | echo 0 > tracing_on | ||
| 37 | echo 0 > events/enable | ||
| 38 | echo > trace | ||
| 39 | echo "call_site.function == 0x$address" > events/kmem/kmem_cache_free/filter | ||
| 40 | echo 1 > events/kmem/kmem_cache_free/enable | ||
| 41 | echo 1 > tracing_on | ||
| 42 | sleep 1 | ||
| 43 | echo 0 > events/kmem/kmem_cache_free/enable | ||
| 44 | |||
| 45 | hitcnt=`grep kmem_cache_free trace| grep exit_mmap | wc -l` | ||
| 46 | misscnt=`grep kmem_cache_free trace| grep -v exit_mmap | wc -l` | ||
| 47 | |||
| 48 | if [ $hitcnt -eq 0 ]; then | ||
| 49 | exit_fail | ||
| 50 | fi | ||
| 51 | |||
| 52 | if [ $misscnt -gt 0 ]; then | ||
| 53 | exit_fail | ||
| 54 | fi | ||
| 55 | |||
| 56 | reset_events_filter | ||
| 57 | |||
| 58 | exit 0 | ||
| @@ -0,0 +1,24 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | # description: event trigger - test inter-event histogram trigger trace action with dynamic string param | ||
| 4 | # requires: set_event synthetic_events events/sched/sched_process_exec/hist "long[]' >> synthetic_events":README | ||
| 5 | |||
| 6 | fail() { #msg | ||
| 7 | echo $1 | ||
| 8 | exit_fail | ||
| 9 | } | ||
| 10 | |||
| 11 | echo "Test create synthetic event with stack" | ||
| 12 | |||
| 13 | |||
| 14 | echo 's:wake_lat pid_t pid; u64 delta; unsigned long[] stack;' > dynamic_events | ||
| 15 | echo 'hist:keys=next_pid:ts=common_timestamp.usecs,st=stacktrace if prev_state == 1||prev_state == 2' >> events/sched/sched_switch/trigger | ||
| 16 | echo 'hist:keys=prev_pid:delta=common_timestamp.usecs-$ts,s=$st:onmax($delta).trace(wake_lat,prev_pid,$delta,$s)' >> events/sched/sched_switch/trigger | ||
| 17 | echo 1 > events/synthetic/wake_lat/enable | ||
| 18 | sleep 1 | ||
| 19 | |||
| 20 | if ! grep -q "=>.*sched" trace; then | ||
| 21 | fail "Failed to create synthetic event with stack" | ||
| 22 | fi | ||
| 23 | |||
| 24 | exit 0 | ||
| @@ -70,6 +70,12 @@ grep "myevent[[:space:]]unsigned long var" synthetic_events · 69 unmodified lines | |||
| 70 | echo "myevent char var[10]" > synthetic_events | 70 | echo "myevent char var[10]" > synthetic_events |
| 71 | grep "myevent[[:space:]]char\[10\] var" synthetic_events | 71 | grep "myevent[[:space:]]char\[10\] var" synthetic_events |
| 72 | 72 | ||
| 73 | if grep -q 'long\[\]' README; then | ||
| 74 | # test stacktrace type | ||
| 75 | echo "myevent unsigned long[] var" > synthetic_events | ||
| 76 | grep "myevent[[:space:]]unsigned long\[\] var" synthetic_events | ||
| 77 | fi | ||
| 78 | |||
| 73 | do_reset | 79 | do_reset |
| 74 | 80 | ||
| 75 | exit 0 | 81 | exit 0 |
| @@ -1584,7 +1584,7 @@ static void *do_printloop(void *arg) · 1583 unmodified lines | |||
| 1584 | /* | 1584 | /* |
| 1585 | * Toss a coin to decide if we want to sleep before printing | 1585 | * Toss a coin to decide if we want to sleep before printing |
| 1586 | * out the backtrace. The reason for this is that opening | 1586 | * out the backtrace. The reason for this is that opening |
| 1587 | * /sys/kernel/debug/tracing/trace will cause a blackout of | 1587 | * /sys/kernel/tracing/trace will cause a blackout of |
| 1588 | * hundreds of ms, where no latencies will be noted by the | 1588 | * hundreds of ms, where no latencies will be noted by the |
| 1589 | * latency tracer. Thus by randomly sleeping we try to avoid | 1589 | * latency tracer. Thus by randomly sleeping we try to avoid |
| 1590 | * missing traces systematically due to this. With this option | 1590 | * missing traces systematically due to this. With this option |