diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-02-18 00:35:34 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-02-19 06:33:21 -0500 |
commit | 985ec20ad531f2641ab9d5193e37891fe959fc7d (patch) | |
tree | 64a5e774ad60dbb32af4450bf4d6802d969f14b0 /Documentation/ftrace.txt | |
parent | d1f9cbd78841f1a797c77e9117e4882f932c2ef6 (diff) |
tracing/function-graph-tracer: provide documentation for the function graph tracer
Update documentation for the function graph tracer.
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'Documentation/ftrace.txt')
-rw-r--r-- | Documentation/ftrace.txt | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/Documentation/ftrace.txt b/Documentation/ftrace.txt index 758fb42a1b68..055bcd2992da 100644 --- a/Documentation/ftrace.txt +++ b/Documentation/ftrace.txt | |||
@@ -129,6 +129,10 @@ of ftrace. Here is a list of some of the key files: | |||
129 | 129 | ||
130 | set_ftrace_pid: Have the function tracer only trace a single thread. | 130 | set_ftrace_pid: Have the function tracer only trace a single thread. |
131 | 131 | ||
132 | set_graph_function: Select the function where the trace have to start | ||
133 | with the function graph tracer (See the section | ||
134 | "dynamic ftrace" for more details). | ||
135 | |||
132 | available_filter_functions: This lists the functions that ftrace | 136 | available_filter_functions: This lists the functions that ftrace |
133 | has processed and can trace. These are the function | 137 | has processed and can trace. These are the function |
134 | names that you can pass to "set_ftrace_filter" or | 138 | names that you can pass to "set_ftrace_filter" or |
@@ -143,6 +147,12 @@ Here is the list of current tracers that may be configured. | |||
143 | 147 | ||
144 | function - function tracer that uses mcount to trace all functions. | 148 | function - function tracer that uses mcount to trace all functions. |
145 | 149 | ||
150 | function_graph_tracer - similar to the function tracer except that the | ||
151 | function tracer probes the functions on their entry whereas the | ||
152 | function graph tracer traces on both entry and exit of the | ||
153 | functions. It then provides the ability to draw a graph of | ||
154 | function calls like a primitive C code source. | ||
155 | |||
146 | sched_switch - traces the context switches between tasks. | 156 | sched_switch - traces the context switches between tasks. |
147 | 157 | ||
148 | irqsoff - traces the areas that disable interrupts and saves | 158 | irqsoff - traces the areas that disable interrupts and saves |
@@ -1226,6 +1236,163 @@ kernel module: | |||
1226 | [...] | 1236 | [...] |
1227 | 1237 | ||
1228 | 1238 | ||
1239 | function graph tracer | ||
1240 | --------------------------- | ||
1241 | |||
1242 | This tracer is similar to the function tracer except that it probes | ||
1243 | a function on its entry and its exit. | ||
1244 | This is done by setting a dynamically allocated stack of return addresses on each | ||
1245 | task_struct. Then the tracer overwrites the return address of each function traced | ||
1246 | to set a custom probe. Thus the original return address is stored on the stack of return | ||
1247 | address in the task_struct. | ||
1248 | |||
1249 | Probing on both extremities of a function leads to special features such as | ||
1250 | |||
1251 | _ measure of function's time execution | ||
1252 | _ having a reliable call stack to draw function calls graph | ||
1253 | |||
1254 | This tracer is useful in several situations: | ||
1255 | |||
1256 | _ you want to find the reason of a strange kernel behavior and need to see | ||
1257 | what happens in detail on any areas (or specific ones). | ||
1258 | _ you are experiencing weird latencies but it's difficult to find its origin. | ||
1259 | _ you want to find quickly which path is taken by a specific function | ||
1260 | _ you just want to see what happens inside your kernel | ||
1261 | |||
1262 | # tracer: function_graph | ||
1263 | # | ||
1264 | # CPU DURATION FUNCTION CALLS | ||
1265 | # | | | | | | | | ||
1266 | |||
1267 | 0) | sys_open() { | ||
1268 | 0) | do_sys_open() { | ||
1269 | 0) | getname() { | ||
1270 | 0) | kmem_cache_alloc() { | ||
1271 | 0) 1.382 us | __might_sleep(); | ||
1272 | 0) 2.478 us | } | ||
1273 | 0) | strncpy_from_user() { | ||
1274 | 0) | might_fault() { | ||
1275 | 0) 1.389 us | __might_sleep(); | ||
1276 | 0) 2.553 us | } | ||
1277 | 0) 3.807 us | } | ||
1278 | 0) 7.876 us | } | ||
1279 | 0) | alloc_fd() { | ||
1280 | 0) 0.668 us | _spin_lock(); | ||
1281 | 0) 0.570 us | expand_files(); | ||
1282 | 0) 0.586 us | _spin_unlock(); | ||
1283 | |||
1284 | |||
1285 | There are several columns that can be dynamically enabled/disabled. | ||
1286 | You can use every combination of options you want, depending on your needs. | ||
1287 | |||
1288 | _ The cpu number on which the function executed is default enabled. | ||
1289 | It is sometimes better to only trace one cpu (see tracing_cpu_mask file) | ||
1290 | or you might sometimes see unordered function calls while cpu tracing switch. | ||
1291 | |||
1292 | hide: echo nofuncgraph-cpu > /debug/tracing/trace_options | ||
1293 | show: echo funcgraph-cpu > /debug/tracing/trace_options | ||
1294 | |||
1295 | _ The duration (function's time of execution) is displayed on the closing bracket | ||
1296 | line of a function or on the same line than the current function in case of a leaf | ||
1297 | one. It is default enabled. | ||
1298 | |||
1299 | hide: echo nofuncgraph-duration > /debug/tracing/trace_options | ||
1300 | show: echo funcgraph-duration > /debug/tracing/trace_options | ||
1301 | |||
1302 | _ The overhead field precedes the duration one in case of reached duration thresholds. | ||
1303 | |||
1304 | hide: echo nofuncgraph-overhead > /debug/tracing/trace_options | ||
1305 | show: echo funcgraph-overhead > /debug/tracing/trace_options | ||
1306 | depends on: funcgraph-duration | ||
1307 | |||
1308 | ie: | ||
1309 | |||
1310 | 0) | up_write() { | ||
1311 | 0) 0.646 us | _spin_lock_irqsave(); | ||
1312 | 0) 0.684 us | _spin_unlock_irqrestore(); | ||
1313 | 0) 3.123 us | } | ||
1314 | 0) 0.548 us | fput(); | ||
1315 | 0) + 58.628 us | } | ||
1316 | |||
1317 | [...] | ||
1318 | |||
1319 | 0) | putname() { | ||
1320 | 0) | kmem_cache_free() { | ||
1321 | 0) 0.518 us | __phys_addr(); | ||
1322 | 0) 1.757 us | } | ||
1323 | 0) 2.861 us | } | ||
1324 | 0) ! 115.305 us | } | ||
1325 | 0) ! 116.402 us | } | ||
1326 | |||
1327 | + means that the function exceeded 10 usecs. | ||
1328 | ! means that the function exceeded 100 usecs. | ||
1329 | |||
1330 | |||
1331 | _ The task/pid field displays the thread cmdline and pid which executed the function. | ||
1332 | It is default disabled. | ||
1333 | |||
1334 | hide: echo nofuncgraph-proc > /debug/tracing/trace_options | ||
1335 | show: echo funcgraph-proc > /debug/tracing/trace_options | ||
1336 | |||
1337 | ie: | ||
1338 | |||
1339 | # tracer: function_graph | ||
1340 | # | ||
1341 | # CPU TASK/PID DURATION FUNCTION CALLS | ||
1342 | # | | | | | | | | | | ||
1343 | 0) sh-4802 | | d_free() { | ||
1344 | 0) sh-4802 | | call_rcu() { | ||
1345 | 0) sh-4802 | | __call_rcu() { | ||
1346 | 0) sh-4802 | 0.616 us | rcu_process_gp_end(); | ||
1347 | 0) sh-4802 | 0.586 us | check_for_new_grace_period(); | ||
1348 | 0) sh-4802 | 2.899 us | } | ||
1349 | 0) sh-4802 | 4.040 us | } | ||
1350 | 0) sh-4802 | 5.151 us | } | ||
1351 | 0) sh-4802 | + 49.370 us | } | ||
1352 | |||
1353 | |||
1354 | _ The absolute time field is an absolute timestamp given by the clock since | ||
1355 | it started. A snapshot of this time is given on each entry/exit of functions | ||
1356 | |||
1357 | hide: echo nofuncgraph-abstime > /debug/tracing/trace_options | ||
1358 | show: echo funcgraph-abstime > /debug/tracing/trace_options | ||
1359 | |||
1360 | ie: | ||
1361 | |||
1362 | # | ||
1363 | # TIME CPU DURATION FUNCTION CALLS | ||
1364 | # | | | | | | | | | ||
1365 | 360.774522 | 1) 0.541 us | } | ||
1366 | 360.774522 | 1) 4.663 us | } | ||
1367 | 360.774523 | 1) 0.541 us | __wake_up_bit(); | ||
1368 | 360.774524 | 1) 6.796 us | } | ||
1369 | 360.774524 | 1) 7.952 us | } | ||
1370 | 360.774525 | 1) 9.063 us | } | ||
1371 | 360.774525 | 1) 0.615 us | journal_mark_dirty(); | ||
1372 | 360.774527 | 1) 0.578 us | __brelse(); | ||
1373 | 360.774528 | 1) | reiserfs_prepare_for_journal() { | ||
1374 | 360.774528 | 1) | unlock_buffer() { | ||
1375 | 360.774529 | 1) | wake_up_bit() { | ||
1376 | 360.774529 | 1) | bit_waitqueue() { | ||
1377 | 360.774530 | 1) 0.594 us | __phys_addr(); | ||
1378 | |||
1379 | |||
1380 | You can put some comments on specific functions by using ftrace_printk() | ||
1381 | For example, if you want to put a comment inside the __might_sleep() function, | ||
1382 | you just have to include <linux/ftrace.h> and call ftrace_printk() inside __might_sleep() | ||
1383 | |||
1384 | ftrace_printk("I'm a comment!\n") | ||
1385 | |||
1386 | will produce: | ||
1387 | |||
1388 | 1) | __might_sleep() { | ||
1389 | 1) | /* I'm a comment! */ | ||
1390 | 1) 1.449 us | } | ||
1391 | |||
1392 | |||
1393 | You might find other useful features for this tracer on the "dynamic ftrace" | ||
1394 | section such as tracing only specific functions or tasks. | ||
1395 | |||
1229 | dynamic ftrace | 1396 | dynamic ftrace |
1230 | -------------- | 1397 | -------------- |
1231 | 1398 | ||
@@ -1427,6 +1594,65 @@ Produces: | |||
1427 | 1594 | ||
1428 | We can see that there's no more lock or preempt tracing. | 1595 | We can see that there's no more lock or preempt tracing. |
1429 | 1596 | ||
1597 | |||
1598 | * Dynamic ftrace with the function graph tracer * | ||
1599 | |||
1600 | |||
1601 | Although what has been explained above concerns both the function tracer and | ||
1602 | the function_graph_tracer, the following concerns only the latter. | ||
1603 | |||
1604 | If you want to trace only one function and all of its childs, you just have | ||
1605 | to echo its name on set_graph_function: | ||
1606 | |||
1607 | echo __do_fault > set_graph_function | ||
1608 | |||
1609 | will produce the following: | ||
1610 | |||
1611 | 0) | __do_fault() { | ||
1612 | 0) | filemap_fault() { | ||
1613 | 0) | find_lock_page() { | ||
1614 | 0) 0.804 us | find_get_page(); | ||
1615 | 0) | __might_sleep() { | ||
1616 | 0) 1.329 us | } | ||
1617 | 0) 3.904 us | } | ||
1618 | 0) 4.979 us | } | ||
1619 | 0) 0.653 us | _spin_lock(); | ||
1620 | 0) 0.578 us | page_add_file_rmap(); | ||
1621 | 0) 0.525 us | native_set_pte_at(); | ||
1622 | 0) 0.585 us | _spin_unlock(); | ||
1623 | 0) | unlock_page() { | ||
1624 | 0) 0.541 us | page_waitqueue(); | ||
1625 | 0) 0.639 us | __wake_up_bit(); | ||
1626 | 0) 2.786 us | } | ||
1627 | 0) + 14.237 us | } | ||
1628 | 0) | __do_fault() { | ||
1629 | 0) | filemap_fault() { | ||
1630 | 0) | find_lock_page() { | ||
1631 | 0) 0.698 us | find_get_page(); | ||
1632 | 0) | __might_sleep() { | ||
1633 | 0) 1.412 us | } | ||
1634 | 0) 3.950 us | } | ||
1635 | 0) 5.098 us | } | ||
1636 | 0) 0.631 us | _spin_lock(); | ||
1637 | 0) 0.571 us | page_add_file_rmap(); | ||
1638 | 0) 0.526 us | native_set_pte_at(); | ||
1639 | 0) 0.586 us | _spin_unlock(); | ||
1640 | 0) | unlock_page() { | ||
1641 | 0) 0.533 us | page_waitqueue(); | ||
1642 | 0) 0.638 us | __wake_up_bit(); | ||
1643 | 0) 2.793 us | } | ||
1644 | 0) + 14.012 us | } | ||
1645 | |||
1646 | You can also select several functions: | ||
1647 | |||
1648 | echo sys_open > set_graph_function | ||
1649 | echo sys_close >> set_graph_function | ||
1650 | |||
1651 | Now if you want to go back to trace all functions | ||
1652 | |||
1653 | echo > set_graph_function | ||
1654 | |||
1655 | |||
1430 | trace_pipe | 1656 | trace_pipe |
1431 | ---------- | 1657 | ---------- |
1432 | 1658 | ||