mmap-thread-lookup.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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 machine *machine;
  118. int err, i;
  119. /*
  120. * The threads_create will not return before all threads
  121. * are spawned and all created memory map.
  122. *
  123. * They will loop until threads_destroy is called, so we
  124. * can safely run synthesizing function.
  125. */
  126. TEST_ASSERT_VAL("failed to create threads", !threads_create());
  127. machine = machine__new_host();
  128. dump_trace = verbose > 1 ? 1 : 0;
  129. err = synth(machine);
  130. dump_trace = 0;
  131. TEST_ASSERT_VAL("failed to destroy threads", !threads_destroy());
  132. TEST_ASSERT_VAL("failed to synthesize maps", !err);
  133. /*
  134. * All data is synthesized, try to find map for each
  135. * thread object.
  136. */
  137. for (i = 0; i < THREADS; i++) {
  138. struct thread_data *td = &threads[i];
  139. struct addr_location al;
  140. struct thread *thread;
  141. thread = machine__findnew_thread(machine, getpid(), td->tid);
  142. pr_debug("looking for map %p\n", td->map);
  143. thread__find_addr_map(thread,
  144. PERF_RECORD_MISC_USER, MAP__FUNCTION,
  145. (unsigned long) (td->map + 1), &al);
  146. thread__put(thread);
  147. if (!al.map) {
  148. pr_debug("failed, couldn't find map\n");
  149. err = -1;
  150. break;
  151. }
  152. pr_debug("map %p, addr %" PRIx64 "\n", al.map, al.map->start);
  153. }
  154. machine__delete_threads(machine);
  155. machine__delete(machine);
  156. return err;
  157. }
  158. /*
  159. * This test creates 'THREADS' number of threads (including
  160. * main thread) and each thread creates memory map.
  161. *
  162. * When threads are created, we synthesize them with both
  163. * (separate tests):
  164. * perf_event__synthesize_thread_map (process based)
  165. * perf_event__synthesize_threads (global)
  166. *
  167. * We test we can find all memory maps via:
  168. * thread__find_addr_map
  169. *
  170. * by using all thread objects.
  171. */
  172. int test__mmap_thread_lookup(int subtest __maybe_unused)
  173. {
  174. /* perf_event__synthesize_threads synthesize */
  175. TEST_ASSERT_VAL("failed with sythesizing all",
  176. !mmap_events(synth_all));
  177. /* perf_event__synthesize_thread_map synthesize */
  178. TEST_ASSERT_VAL("failed with sythesizing process",
  179. !mmap_events(synth_process));
  180. return 0;
  181. }