thread-stack.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*
  2. * thread-stack.c: Synthesize a thread's stack using call / return events
  3. * Copyright (c) 2014, Intel Corporation.
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms and conditions of the GNU General Public License,
  7. * version 2, as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. */
  15. #include "thread.h"
  16. #include "event.h"
  17. #include "util.h"
  18. #include "debug.h"
  19. #include "thread-stack.h"
  20. #define STACK_GROWTH 4096
  21. struct thread_stack_entry {
  22. u64 ret_addr;
  23. };
  24. struct thread_stack {
  25. struct thread_stack_entry *stack;
  26. size_t cnt;
  27. size_t sz;
  28. u64 trace_nr;
  29. };
  30. static int thread_stack__grow(struct thread_stack *ts)
  31. {
  32. struct thread_stack_entry *new_stack;
  33. size_t sz, new_sz;
  34. new_sz = ts->sz + STACK_GROWTH;
  35. sz = new_sz * sizeof(struct thread_stack_entry);
  36. new_stack = realloc(ts->stack, sz);
  37. if (!new_stack)
  38. return -ENOMEM;
  39. ts->stack = new_stack;
  40. ts->sz = new_sz;
  41. return 0;
  42. }
  43. static struct thread_stack *thread_stack__new(void)
  44. {
  45. struct thread_stack *ts;
  46. ts = zalloc(sizeof(struct thread_stack));
  47. if (!ts)
  48. return NULL;
  49. if (thread_stack__grow(ts)) {
  50. free(ts);
  51. return NULL;
  52. }
  53. return ts;
  54. }
  55. static int thread_stack__push(struct thread_stack *ts, u64 ret_addr)
  56. {
  57. int err = 0;
  58. if (ts->cnt == ts->sz) {
  59. err = thread_stack__grow(ts);
  60. if (err) {
  61. pr_warning("Out of memory: discarding thread stack\n");
  62. ts->cnt = 0;
  63. }
  64. }
  65. ts->stack[ts->cnt++].ret_addr = ret_addr;
  66. return err;
  67. }
  68. static void thread_stack__pop(struct thread_stack *ts, u64 ret_addr)
  69. {
  70. size_t i;
  71. /*
  72. * In some cases there may be functions which are not seen to return.
  73. * For example when setjmp / longjmp has been used. Or the perf context
  74. * switch in the kernel which doesn't stop and start tracing in exactly
  75. * the same code path. When that happens the return address will be
  76. * further down the stack. If the return address is not found at all,
  77. * we assume the opposite (i.e. this is a return for a call that wasn't
  78. * seen for some reason) and leave the stack alone.
  79. */
  80. for (i = ts->cnt; i; ) {
  81. if (ts->stack[--i].ret_addr == ret_addr) {
  82. ts->cnt = i;
  83. return;
  84. }
  85. }
  86. }
  87. int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
  88. u64 to_ip, u16 insn_len, u64 trace_nr)
  89. {
  90. if (!thread)
  91. return -EINVAL;
  92. if (!thread->ts) {
  93. thread->ts = thread_stack__new();
  94. if (!thread->ts) {
  95. pr_warning("Out of memory: no thread stack\n");
  96. return -ENOMEM;
  97. }
  98. thread->ts->trace_nr = trace_nr;
  99. }
  100. /*
  101. * When the trace is discontinuous, the trace_nr changes. In that case
  102. * the stack might be completely invalid. Better to report nothing than
  103. * to report something misleading, so reset the stack count to zero.
  104. */
  105. if (trace_nr != thread->ts->trace_nr) {
  106. thread->ts->trace_nr = trace_nr;
  107. thread->ts->cnt = 0;
  108. }
  109. if (flags & PERF_IP_FLAG_CALL) {
  110. u64 ret_addr;
  111. if (!to_ip)
  112. return 0;
  113. ret_addr = from_ip + insn_len;
  114. if (ret_addr == to_ip)
  115. return 0; /* Zero-length calls are excluded */
  116. return thread_stack__push(thread->ts, ret_addr);
  117. } else if (flags & PERF_IP_FLAG_RETURN) {
  118. if (!from_ip)
  119. return 0;
  120. thread_stack__pop(thread->ts, to_ip);
  121. }
  122. return 0;
  123. }
  124. void thread_stack__free(struct thread *thread)
  125. {
  126. if (thread->ts) {
  127. zfree(&thread->ts->stack);
  128. zfree(&thread->ts);
  129. }
  130. }
  131. void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
  132. size_t sz, u64 ip)
  133. {
  134. size_t i;
  135. if (!thread || !thread->ts)
  136. chain->nr = 1;
  137. else
  138. chain->nr = min(sz, thread->ts->cnt + 1);
  139. chain->ips[0] = ip;
  140. for (i = 1; i < chain->nr; i++)
  141. chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr;
  142. }