Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf script: Add callchain to generic and tracepoint events

This provides valuable information for tracing performance problems.

Since this change alters the interface for the python scripts, also
adjust the script generation and the provided scripts.

Signed-off-by: Joseph Schuchart <joseph.schuchart@tu-dresden.de>
Acked-by: Thomas Ilsche <thomas.ilsche@tu-dresden.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Thomas Ilsche <thomas.ilsche@tu-dresden.de>
Link: http://lkml.kernel.org/r/53BE7E1B.10503@tu-dresden.de
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Joseph Schuchart and committed by
Arnaldo Carvalho de Melo
0f5f5bcd 05f832e3

+146 -48
+2 -1
tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Core.py
··· 107 107 108 108 class EventHeaders: 109 109 def __init__(self, common_cpu, common_secs, common_nsecs, 110 - common_pid, common_comm): 110 + common_pid, common_comm, common_callchain): 111 111 self.cpu = common_cpu 112 112 self.secs = common_secs 113 113 self.nsecs = common_nsecs 114 114 self.pid = common_pid 115 115 self.comm = common_comm 116 + self.callchain = common_callchain 116 117 117 118 def ts(self): 118 119 return (self.secs * (10 ** 9)) + self.nsecs
+2 -2
tools/perf/scripts/python/check-perf-trace.py
··· 27 27 28 28 def irq__softirq_entry(event_name, context, common_cpu, 29 29 common_secs, common_nsecs, common_pid, common_comm, 30 - vec): 30 + common_callchain, vec): 31 31 print_header(event_name, common_cpu, common_secs, common_nsecs, 32 32 common_pid, common_comm) 33 33 ··· 38 38 39 39 def kmem__kmalloc(event_name, context, common_cpu, 40 40 common_secs, common_nsecs, common_pid, common_comm, 41 - call_site, ptr, bytes_req, bytes_alloc, 41 + common_callchain, call_site, ptr, bytes_req, bytes_alloc, 42 42 gfp_flags): 43 43 print_header(event_name, common_cpu, common_secs, common_nsecs, 44 44 common_pid, common_comm)
+1 -1
tools/perf/scripts/python/failed-syscalls-by-pid.py
··· 39 39 40 40 def raw_syscalls__sys_exit(event_name, context, common_cpu, 41 41 common_secs, common_nsecs, common_pid, common_comm, 42 - id, ret): 42 + common_callchain, id, ret): 43 43 if (for_comm and common_comm != for_comm) or \ 44 44 (for_pid and common_pid != for_pid ): 45 45 return
+2 -2
tools/perf/scripts/python/futex-contention.py
··· 21 21 lock_waits = {} # long-lived stats on (tid,lock) blockage elapsed time 22 22 process_names = {} # long-lived pid-to-execname mapping 23 23 24 - def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, 24 + def syscalls__sys_enter_futex(event, ctxt, cpu, s, ns, tid, comm, callchain, 25 25 nr, uaddr, op, val, utime, uaddr2, val3): 26 26 cmd = op & FUTEX_CMD_MASK 27 27 if cmd != FUTEX_WAIT: ··· 31 31 thread_thislock[tid] = uaddr 32 32 thread_blocktime[tid] = nsecs(s, ns) 33 33 34 - def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, 34 + def syscalls__sys_exit_futex(event, ctxt, cpu, s, ns, tid, comm, callchain, 35 35 nr, ret): 36 36 if thread_blocktime.has_key(tid): 37 37 elapsed = nsecs(s, ns) - thread_blocktime[tid]
+1 -1
tools/perf/scripts/python/net_dropmonitor.py
··· 66 66 print_drop_table() 67 67 68 68 # called from perf, when it finds a correspoinding event 69 - def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, 69 + def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain, 70 70 skbaddr, location, protocol): 71 71 slocation = str(location) 72 72 try:
+13 -13
tools/perf/scripts/python/netdev-times.py
··· 224 224 (len(rx_skb_list), of_count_rx_skb_list) 225 225 226 226 # called from perf, when it finds a correspoinding event 227 - def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, vec): 227 + def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, callchain, vec): 228 228 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 229 229 return 230 230 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 231 231 all_event_list.append(event_info) 232 232 233 - def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, vec): 233 + def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, callchain, vec): 234 234 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 235 235 return 236 236 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 237 237 all_event_list.append(event_info) 238 238 239 - def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, vec): 239 + def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, callchain, vec): 240 240 if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX": 241 241 return 242 242 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec) 243 243 all_event_list.append(event_info) 244 244 245 245 def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm, 246 - irq, irq_name): 246 + callchain, irq, irq_name): 247 247 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 248 248 irq, irq_name) 249 249 all_event_list.append(event_info) 250 250 251 - def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, irq, ret): 251 + def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, callchain, irq, ret): 252 252 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret) 253 253 all_event_list.append(event_info) 254 254 255 - def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, napi, dev_name): 255 + def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, callchain, napi, dev_name): 256 256 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 257 257 napi, dev_name) 258 258 all_event_list.append(event_info) 259 259 260 - def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr, 260 + def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, 261 261 skblen, dev_name): 262 262 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 263 263 skbaddr, skblen, dev_name) 264 264 all_event_list.append(event_info) 265 265 266 - def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, skbaddr, 266 + def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr, 267 267 skblen, dev_name): 268 268 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 269 269 skbaddr, skblen, dev_name) 270 270 all_event_list.append(event_info) 271 271 272 - def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, 272 + def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm, callchain, 273 273 skbaddr, skblen, dev_name): 274 274 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 275 275 skbaddr, skblen, dev_name) 276 276 all_event_list.append(event_info) 277 277 278 - def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, 278 + def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm, callchain, 279 279 skbaddr, skblen, rc, dev_name): 280 280 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 281 281 skbaddr, skblen, rc ,dev_name) 282 282 all_event_list.append(event_info) 283 283 284 - def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, 284 + def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm, callchain, 285 285 skbaddr, protocol, location): 286 286 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 287 287 skbaddr, protocol, location) 288 288 all_event_list.append(event_info) 289 289 290 - def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr): 290 + def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, callchain, skbaddr): 291 291 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 292 292 skbaddr) 293 293 all_event_list.append(event_info) 294 294 295 - def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, 295 + def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm, callchain, 296 296 skbaddr, skblen): 297 297 event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, 298 298 skbaddr, skblen)
+20 -21
tools/perf/scripts/python/sched-migration.py
··· 369 369 370 370 def sched__sched_stat_runtime(event_name, context, common_cpu, 371 371 common_secs, common_nsecs, common_pid, common_comm, 372 - comm, pid, runtime, vruntime): 372 + common_callchain, comm, pid, runtime, vruntime): 373 373 pass 374 374 375 375 def sched__sched_stat_iowait(event_name, context, common_cpu, 376 376 common_secs, common_nsecs, common_pid, common_comm, 377 - comm, pid, delay): 377 + common_callchain, comm, pid, delay): 378 378 pass 379 379 380 380 def sched__sched_stat_sleep(event_name, context, common_cpu, 381 381 common_secs, common_nsecs, common_pid, common_comm, 382 - comm, pid, delay): 382 + common_callchain, comm, pid, delay): 383 383 pass 384 384 385 385 def sched__sched_stat_wait(event_name, context, common_cpu, 386 386 common_secs, common_nsecs, common_pid, common_comm, 387 - comm, pid, delay): 387 + common_callchain, comm, pid, delay): 388 388 pass 389 389 390 390 def sched__sched_process_fork(event_name, context, common_cpu, 391 391 common_secs, common_nsecs, common_pid, common_comm, 392 - parent_comm, parent_pid, child_comm, child_pid): 392 + common_callchain, parent_comm, parent_pid, child_comm, child_pid): 393 393 pass 394 394 395 395 def sched__sched_process_wait(event_name, context, common_cpu, 396 396 common_secs, common_nsecs, common_pid, common_comm, 397 - comm, pid, prio): 397 + common_callchain, comm, pid, prio): 398 398 pass 399 399 400 400 def sched__sched_process_exit(event_name, context, common_cpu, 401 401 common_secs, common_nsecs, common_pid, common_comm, 402 - comm, pid, prio): 402 + common_callchain, comm, pid, prio): 403 403 pass 404 404 405 405 def sched__sched_process_free(event_name, context, common_cpu, 406 406 common_secs, common_nsecs, common_pid, common_comm, 407 - comm, pid, prio): 407 + common_callchain, comm, pid, prio): 408 408 pass 409 409 410 410 def sched__sched_migrate_task(event_name, context, common_cpu, 411 411 common_secs, common_nsecs, common_pid, common_comm, 412 - comm, pid, prio, orig_cpu, 412 + common_callchain, comm, pid, prio, orig_cpu, 413 413 dest_cpu): 414 414 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 415 - common_pid, common_comm) 415 + common_pid, common_comm, common_callchain) 416 416 parser.migrate(headers, pid, prio, orig_cpu, dest_cpu) 417 417 418 418 def sched__sched_switch(event_name, context, common_cpu, 419 - common_secs, common_nsecs, common_pid, common_comm, 419 + common_secs, common_nsecs, common_pid, common_comm, common_callchain, 420 420 prev_comm, prev_pid, prev_prio, prev_state, 421 421 next_comm, next_pid, next_prio): 422 422 423 423 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 424 - common_pid, common_comm) 424 + common_pid, common_comm, common_callchain) 425 425 parser.sched_switch(headers, prev_comm, prev_pid, prev_prio, prev_state, 426 426 next_comm, next_pid, next_prio) 427 427 428 428 def sched__sched_wakeup_new(event_name, context, common_cpu, 429 429 common_secs, common_nsecs, common_pid, common_comm, 430 - comm, pid, prio, success, 430 + common_callchain, comm, pid, prio, success, 431 431 target_cpu): 432 432 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 433 - common_pid, common_comm) 433 + common_pid, common_comm, common_callchain) 434 434 parser.wake_up(headers, comm, pid, success, target_cpu, 1) 435 435 436 436 def sched__sched_wakeup(event_name, context, common_cpu, 437 437 common_secs, common_nsecs, common_pid, common_comm, 438 - comm, pid, prio, success, 438 + common_callchain, comm, pid, prio, success, 439 439 target_cpu): 440 440 headers = EventHeaders(common_cpu, common_secs, common_nsecs, 441 - common_pid, common_comm) 441 + common_pid, common_comm, common_callchain) 442 442 parser.wake_up(headers, comm, pid, success, target_cpu, 0) 443 443 444 444 def sched__sched_wait_task(event_name, context, common_cpu, 445 445 common_secs, common_nsecs, common_pid, common_comm, 446 - comm, pid, prio): 446 + common_callchain, comm, pid, prio): 447 447 pass 448 448 449 449 def sched__sched_kthread_stop_ret(event_name, context, common_cpu, 450 450 common_secs, common_nsecs, common_pid, common_comm, 451 - ret): 451 + common_callchain, ret): 452 452 pass 453 453 454 454 def sched__sched_kthread_stop(event_name, context, common_cpu, 455 455 common_secs, common_nsecs, common_pid, common_comm, 456 - comm, pid): 456 + common_callchain, comm, pid): 457 457 pass 458 458 459 - def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs, 460 - common_pid, common_comm): 459 + def trace_unhandled(event_name, context, event_fields_dict): 461 460 pass
+1 -1
tools/perf/scripts/python/sctop.py
··· 44 44 45 45 def raw_syscalls__sys_enter(event_name, context, common_cpu, 46 46 common_secs, common_nsecs, common_pid, common_comm, 47 - id, args): 47 + common_callchain, id, args): 48 48 if for_comm is not None: 49 49 if common_comm != for_comm: 50 50 return
+1 -1
tools/perf/scripts/python/syscall-counts-by-pid.py
··· 38 38 39 39 def raw_syscalls__sys_enter(event_name, context, common_cpu, 40 40 common_secs, common_nsecs, common_pid, common_comm, 41 - id, args): 41 + common_callchain, id, args): 42 42 43 43 if (for_comm and common_comm != for_comm) or \ 44 44 (for_pid and common_pid != for_pid ):
+1 -1
tools/perf/scripts/python/syscall-counts.py
··· 35 35 36 36 def raw_syscalls__sys_enter(event_name, context, common_cpu, 37 37 common_secs, common_nsecs, common_pid, common_comm, 38 - id, args): 38 + common_callchain, id, args): 39 39 if for_comm is not None: 40 40 if common_comm != for_comm: 41 41 return
+102 -4
tools/perf/util/scripting-engines/trace-event-python.c
··· 32 32 #include "../event.h" 33 33 #include "../thread.h" 34 34 #include "../trace-event.h" 35 + #include "../machine.h" 35 36 36 37 PyMODINIT_FUNC initperf_trace_context(void); 37 38 ··· 279 278 return obj; 280 279 } 281 280 281 + 282 + static PyObject *python_process_callchain(struct perf_sample *sample, 283 + struct perf_evsel *evsel, 284 + struct addr_location *al) 285 + { 286 + PyObject *pylist; 287 + 288 + pylist = PyList_New(0); 289 + if (!pylist) 290 + Py_FatalError("couldn't create Python list"); 291 + 292 + if (!symbol_conf.use_callchain || !sample->callchain) 293 + goto exit; 294 + 295 + if (machine__resolve_callchain(al->machine, evsel, al->thread, 296 + sample, NULL, NULL, 297 + PERF_MAX_STACK_DEPTH) != 0) { 298 + pr_err("Failed to resolve callchain. Skipping\n"); 299 + goto exit; 300 + } 301 + callchain_cursor_commit(&callchain_cursor); 302 + 303 + 304 + while (1) { 305 + PyObject *pyelem; 306 + struct callchain_cursor_node *node; 307 + node = callchain_cursor_current(&callchain_cursor); 308 + if (!node) 309 + break; 310 + 311 + pyelem = PyDict_New(); 312 + if (!pyelem) 313 + Py_FatalError("couldn't create Python dictionary"); 314 + 315 + 316 + pydict_set_item_string_decref(pyelem, "ip", 317 + PyLong_FromUnsignedLongLong(node->ip)); 318 + 319 + if (node->sym) { 320 + PyObject *pysym = PyDict_New(); 321 + if (!pysym) 322 + Py_FatalError("couldn't create Python dictionary"); 323 + pydict_set_item_string_decref(pysym, "start", 324 + PyLong_FromUnsignedLongLong(node->sym->start)); 325 + pydict_set_item_string_decref(pysym, "end", 326 + PyLong_FromUnsignedLongLong(node->sym->end)); 327 + pydict_set_item_string_decref(pysym, "binding", 328 + PyInt_FromLong(node->sym->binding)); 329 + pydict_set_item_string_decref(pysym, "name", 330 + PyString_FromStringAndSize(node->sym->name, 331 + node->sym->namelen)); 332 + pydict_set_item_string_decref(pyelem, "sym", pysym); 333 + } 334 + 335 + if (node->map) { 336 + struct map *map = node->map; 337 + const char *dsoname = "[unknown]"; 338 + if (map && map->dso && (map->dso->name || map->dso->long_name)) { 339 + if (symbol_conf.show_kernel_path && map->dso->long_name) 340 + dsoname = map->dso->long_name; 341 + else if (map->dso->name) 342 + dsoname = map->dso->name; 343 + } 344 + pydict_set_item_string_decref(pyelem, "dso", 345 + PyString_FromString(dsoname)); 346 + } 347 + 348 + callchain_cursor_advance(&callchain_cursor); 349 + PyList_Append(pylist, pyelem); 350 + Py_DECREF(pyelem); 351 + } 352 + 353 + exit: 354 + return pylist; 355 + } 356 + 357 + 282 358 static void python_process_tracepoint(struct perf_sample *sample, 283 359 struct perf_evsel *evsel, 284 360 struct thread *thread, 285 361 struct addr_location *al) 286 362 { 287 - PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 363 + PyObject *handler, *retval, *context, *t, *obj, *callchain; 364 + PyObject *dict = NULL; 288 365 static char handler_name[256]; 289 366 struct format_field *field; 290 367 unsigned long s, ns; ··· 405 326 PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); 406 327 PyTuple_SetItem(t, n++, context); 407 328 329 + /* ip unwinding */ 330 + callchain = python_process_callchain(sample, evsel, al); 331 + 408 332 if (handler) { 409 333 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); 410 334 PyTuple_SetItem(t, n++, PyInt_FromLong(s)); 411 335 PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); 412 336 PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); 413 337 PyTuple_SetItem(t, n++, PyString_FromString(comm)); 338 + PyTuple_SetItem(t, n++, callchain); 414 339 } else { 415 340 pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu)); 416 341 pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s)); 417 342 pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns)); 418 343 pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid)); 419 344 pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm)); 345 + pydict_set_item_string_decref(dict, "common_callchain", callchain); 420 346 } 421 347 for (field = event->format.fields; field; field = field->next) { 422 348 if (field->flags & FIELD_IS_STRING) { ··· 441 357 pydict_set_item_string_decref(dict, field->name, obj); 442 358 443 359 } 360 + 444 361 if (!handler) 445 362 PyTuple_SetItem(t, n++, dict); 446 363 ··· 473 388 struct thread *thread, 474 389 struct addr_location *al) 475 390 { 476 - PyObject *handler, *retval, *t, *dict; 391 + PyObject *handler, *retval, *t, *dict, *callchain; 477 392 static char handler_name[64]; 478 393 unsigned n = 0; 479 394 ··· 512 427 pydict_set_item_string_decref(dict, "symbol", 513 428 PyString_FromString(al->sym->name)); 514 429 } 430 + 431 + /* ip unwinding */ 432 + callchain = python_process_callchain(sample, evsel, al); 433 + pydict_set_item_string_decref(dict, "callchain", callchain); 515 434 516 435 PyTuple_SetItem(t, n++, dict); 517 436 if (_PyTuple_Resize(&t, n) == -1) ··· 713 624 fprintf(ofp, "common_nsecs, "); 714 625 fprintf(ofp, "common_pid, "); 715 626 fprintf(ofp, "common_comm,\n\t"); 627 + fprintf(ofp, "common_callchain, "); 716 628 717 629 not_first = 0; 718 630 count = 0; ··· 757 667 fprintf(ofp, "%%u"); 758 668 } 759 669 760 - fprintf(ofp, "\\n\" %% \\\n\t\t("); 670 + fprintf(ofp, "\" %% \\\n\t\t("); 761 671 762 672 not_first = 0; 763 673 count = 0; ··· 793 703 fprintf(ofp, "%s", f->name); 794 704 } 795 705 796 - fprintf(ofp, "),\n\n"); 706 + fprintf(ofp, ")\n\n"); 707 + 708 + fprintf(ofp, "\t\tfor node in common_callchain:"); 709 + fprintf(ofp, "\n\t\t\tif 'sym' in node:"); 710 + fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])"); 711 + fprintf(ofp, "\n\t\t\telse:"); 712 + fprintf(ofp, "\n\t\t\t\tprint \"\t[%%x]\" %% (node['ip'])\n\n"); 713 + fprintf(ofp, "\t\tprint \"\\n\"\n\n"); 714 + 797 715 } 798 716 799 717 fprintf(ofp, "def trace_unhandled(event_name, context, "