mmap-thread-lookup.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #include <unistd.h>
  2. #include <sys/syscall.h>
  3. #include <sys/types.h>
  4. #include <sys/mman.h>
  5. #include <pthread.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include "debug.h"
  9. #include "tests.h"
  10. #include "machine.h"
  11. #include "thread_map.h"
  12. #include "symbol.h"
  13. #include "thread.h"
  14. #define THREADS 4
  15. static int go_away;
  16. struct thread_data {
  17. pthread_t pt;
  18. pid_t tid;
  19. void *map;
  20. int ready[2];
  21. };
  22. static struct thread_data threads[THREADS];
  23. static int thread_init(struct thread_data *td)
  24. {
  25. void *map;
  26. map = mmap(NULL, page_size,
  27. PROT_READ|PROT_WRITE|PROT_EXEC,
  28. MAP_SHARED|MAP_ANONYMOUS, -1, 0);
  29. if (map == MAP_FAILED) {
  30. perror("mmap failed");
  31. return -1;
  32. }
  33. td->map = map;
  34. td->tid = syscall(SYS_gettid);
  35. pr_debug("tid = %d, map = %p\n", td->tid, map);
  36. return 0;
  37. }
  38. static void *thread_fn(void *arg)
  39. {
  40. struct thread_data *td = arg;
  41. ssize_t ret;
  42. int go;
  43. if (thread_init(td))
  44. return NULL;
  45. /* Signal thread_create thread is initialized. */
  46. ret = write(td->ready[1], &go, sizeof(int));
  47. if (ret != sizeof(int)) {
  48. pr_err("failed to notify\n");
  49. return NULL;
  50. }
  51. while (!go_away) {
  52. /* Waiting for main thread to kill us. */
  53. usleep(100);
  54. }
  55. munmap(td->map, page_size);
  56. return NULL;
  57. }
  58. static int thread_create(int i)
  59. {
  60. struct thread_data *td = &threads[i];
  61. int err, go;
  62. if (pipe(td->ready))
  63. return -1;
  64. err = pthread_create(&td->pt, NULL, thread_fn, td);
  65. if (!err) {
  66. /* Wait for thread initialization. */
  67. ssize_t ret = read(td->ready[0], &go, sizeof(int));
  68. err = ret != sizeof(int);
  69. }
  70. close(td->ready[0]);
  71. close(td->ready[1]);
  72. return err;
  73. }
  74. static int threads_create(void)
  75. {
  76. struct thread_data *td0 = &threads[0];
  77. int i, err = 0;
  78. go_away = 0;
  79. /* 0 is main thread */
  80. if (thread_init(td0))
  81. return -1;
  82. for (i = 1; !err && i < THREADS; i++)
  83. err = thread_create(i);
  84. return err;
  85. }
  86. static int threads_destroy(void)
  87. {
  88. struct thread_data *td0 = &threads[0];
  89. int i, err = 0;
  90. /* cleanup the main thread */
  91. munmap(td0->map, page_size);
  92. go_away = 1;
  93. for (i = 1; !err && i < THREADS; i++)
  94. err = pthread_join(threads[i].pt, NULL);
  95. return err;
  96. }
  97. typedef int (*synth_cb)(struct machine *machine);
  98. static int synth_all(struct machine *machine)
  99. {
  100. return perf_event__synthesize_threads(NULL,
  101. perf_event__process,
  102. machine, 0, 500);
  103. }
  104. static int synth_process(struct machine *machine)
  105. {
  106. struct thread_map *map;
  107. int err;
  108. map = thread_map__new_by_pid(getpid());
  109. err = perf_event__synthesize_thread_map(NULL, map,
  110. perf_event__process,
  111. machine, 0, 500);
  112. thread_map__put(map);
  113. return err;
  114. }
  115. static int mmap_events(synth_cb synth)
  116. {
  117. struct machines machines;
  118. struct machine *machine;
  119. int err, i;
  120. /*
  121. * The threads_create will not return before all threads
  122. * are spawned and all created memory map.
  123. *
  124. * They will loop until threads_destroy is called, so we
  125. * can safely run synthesizing function.
  126. */
  127. TEST_ASSERT_VAL("failed to create threads", !threads_create());
  128. machines__init(&machines);
  129. machine = &machines.host;
  130. dump_trace = verbose > 1 ? 1 : 0;
  131. err = synth(machine);
  132. dump_trace = 0;
  133. TEST_ASSERT_VAL("failed to destroy threads", !threads_destroy());
  134. TEST_ASSERT_VAL("failed to synthesize maps", !err);
  135. /*
  136. * All data is synthesized, try to find map for each
  137. * thread object.
  138. */
  139. for (i = 0; i < THREADS; i++) {
  140. struct thread_data *td = &threads[i];
  141. struct addr_location al;
  142. struct thread *thread;
  143. thread = machine__findnew_thread(machine, getpid(), td->tid);
  144. pr_debug("looking for map %p\n", td->map);
  145. thread__find_addr_map(thread,
  146. PERF_RECORD_MISC_USER, MAP__FUNCTION,
  147. (unsigned long) (td->map + 1), &al);
  148. thread__put(thread);
  149. if (!al.map) {
  150. pr_debug("failed, couldn't find map\n");
  151. err = -1;
  152. break;
  153. }
  154. pr_debug("map %p, addr %" PRIx64 "\n", al.map, al.map->start);
  155. }
  156. machine__delete_threads(machine);
  157. machines__exit(&machines);
  158. return err;
  159. }
  160. /*
  161. * This test creates 'THREADS' number of threads (including
  162. * main thread) and each thread creates memory map.
  163. *
  164. * When threads are created, we synthesize them with both
  165. * (separate tests):
  166. * perf_event__synthesize_thread_map (process based)
  167. * perf_event__synthesize_threads (global)
  168. *
  169. * We test we can find all memory maps via:
  170. * thread__find_addr_map
  171. *
  172. * by using all thread objects.
  173. */
  174. int test__mmap_thread_lookup(void)
  175. {
  176. /* perf_event__synthesize_threads synthesize */
  177. TEST_ASSERT_VAL("failed with sythesizing all",
  178. !mmap_events(synth_all));
  179. /* perf_event__synthesize_thread_map synthesize */
  180. TEST_ASSERT_VAL("failed with sythesizing process",
  181. !mmap_events(synth_process));
  182. return 0;
  183. }