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

perf tools: Ensure thread-stack is flushed

The thread-stack represents a thread's current stack. When a thread
exits there can still be many functions on the stack e.g. exit() can be
called many levels deep, so all the callers will never return. To get
that information output, the thread-stack must be flushed.

Previously it was assumed the thread-stack would be flushed when the
struct thread was deleted. With thread ref-counting it is no longer
clear when that will be, if ever. So instead explicitly flush all the
thread-stacks at the end of a session.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/1432906425-9911-3-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Adrian Hunter and committed by
Arnaldo Carvalho de Melo
a5499b37 79928928

+58 -5
+21
tools/perf/util/machine.c
··· 1890 1890 return rc; 1891 1891 } 1892 1892 1893 + int machines__for_each_thread(struct machines *machines, 1894 + int (*fn)(struct thread *thread, void *p), 1895 + void *priv) 1896 + { 1897 + struct rb_node *nd; 1898 + int rc = 0; 1899 + 1900 + rc = machine__for_each_thread(&machines->host, fn, priv); 1901 + if (rc != 0) 1902 + return rc; 1903 + 1904 + for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { 1905 + struct machine *machine = rb_entry(nd, struct machine, rb_node); 1906 + 1907 + rc = machine__for_each_thread(machine, fn, priv); 1908 + if (rc != 0) 1909 + return rc; 1910 + } 1911 + return rc; 1912 + } 1913 + 1893 1914 int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 1894 1915 struct target *target, struct thread_map *threads, 1895 1916 perf_event__handler_t process, bool data_mmap)
+3
tools/perf/util/machine.h
··· 216 216 int machine__for_each_thread(struct machine *machine, 217 217 int (*fn)(struct thread *thread, void *p), 218 218 void *priv); 219 + int machines__for_each_thread(struct machines *machines, 220 + int (*fn)(struct thread *thread, void *p), 221 + void *priv); 219 222 220 223 int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, 221 224 struct target *target, struct thread_map *threads,
+20
tools/perf/util/session.c
··· 16 16 #include "perf_regs.h" 17 17 #include "asm/bug.h" 18 18 #include "auxtrace.h" 19 + #include "thread-stack.h" 19 20 20 21 static int perf_session__deliver_event(struct perf_session *session, 21 22 union perf_event *event, ··· 1362 1361 events_stats__auxtrace_error_warn(stats); 1363 1362 } 1364 1363 1364 + static int perf_session__flush_thread_stack(struct thread *thread, 1365 + void *p __maybe_unused) 1366 + { 1367 + return thread_stack__flush(thread); 1368 + } 1369 + 1370 + static int perf_session__flush_thread_stacks(struct perf_session *session) 1371 + { 1372 + return machines__for_each_thread(&session->machines, 1373 + perf_session__flush_thread_stack, 1374 + NULL); 1375 + } 1376 + 1365 1377 volatile int session_done; 1366 1378 1367 1379 static int __perf_session__process_pipe_events(struct perf_session *session) ··· 1464 1450 if (err) 1465 1451 goto out_err; 1466 1452 err = auxtrace__flush_events(session, tool); 1453 + if (err) 1454 + goto out_err; 1455 + err = perf_session__flush_thread_stacks(session); 1467 1456 out_err: 1468 1457 free(buf); 1469 1458 perf_session__warn_about_errors(session); ··· 1617 1600 if (err) 1618 1601 goto out_err; 1619 1602 err = auxtrace__flush_events(session, tool); 1603 + if (err) 1604 + goto out_err; 1605 + err = perf_session__flush_thread_stacks(session); 1620 1606 out_err: 1621 1607 ui_progress__finish(); 1622 1608 perf_session__warn_about_errors(session);
+13 -5
tools/perf/util/thread-stack.c
··· 219 219 return crp->process(&cr, crp->data); 220 220 } 221 221 222 - static int thread_stack__flush(struct thread *thread, struct thread_stack *ts) 222 + static int __thread_stack__flush(struct thread *thread, struct thread_stack *ts) 223 223 { 224 224 struct call_return_processor *crp = ts->crp; 225 225 int err; ··· 238 238 return err; 239 239 } 240 240 } 241 + 242 + return 0; 243 + } 244 + 245 + int thread_stack__flush(struct thread *thread) 246 + { 247 + if (thread->ts) 248 + return __thread_stack__flush(thread, thread->ts); 241 249 242 250 return 0; 243 251 } ··· 272 264 */ 273 265 if (trace_nr != thread->ts->trace_nr) { 274 266 if (thread->ts->trace_nr) 275 - thread_stack__flush(thread, thread->ts); 267 + __thread_stack__flush(thread, thread->ts); 276 268 thread->ts->trace_nr = trace_nr; 277 269 } 278 270 ··· 305 297 306 298 if (trace_nr != thread->ts->trace_nr) { 307 299 if (thread->ts->trace_nr) 308 - thread_stack__flush(thread, thread->ts); 300 + __thread_stack__flush(thread, thread->ts); 309 301 thread->ts->trace_nr = trace_nr; 310 302 } 311 303 } ··· 313 305 void thread_stack__free(struct thread *thread) 314 306 { 315 307 if (thread->ts) { 316 - thread_stack__flush(thread, thread->ts); 308 + __thread_stack__flush(thread, thread->ts); 317 309 zfree(&thread->ts->stack); 318 310 zfree(&thread->ts); 319 311 } ··· 697 689 698 690 /* Flush stack on exec */ 699 691 if (ts->comm != comm && thread->pid_ == thread->tid) { 700 - err = thread_stack__flush(thread, ts); 692 + err = __thread_stack__flush(thread, ts); 701 693 if (err) 702 694 return err; 703 695 ts->comm = comm;
+1
tools/perf/util/thread-stack.h
··· 96 96 void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr); 97 97 void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, 98 98 size_t sz, u64 ip); 99 + int thread_stack__flush(struct thread *thread); 99 100 void thread_stack__free(struct thread *thread); 100 101 101 102 struct call_return_processor *