mmap-thread-lookup.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <inttypes.h>
  3. #include <unistd.h>
  4. #include <sys/syscall.h>
  5. #include <sys/types.h>
  6. #include <sys/mman.h>
  7. #include <pthread.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include "debug.h"
  11. #include "tests.h"
  12. #include "machine.h"
  13. #include "thread_map.h"
  14. #include "symbol.h"
  15. #include "thread.h"
  16. #include "util.h"
  17. #define THREADS 4
  18. static int go_away;
  19. struct thread_data {
  20. pthread_t pt;
  21. pid_t tid;
  22. void *map;
  23. int ready[2];
  24. };
  25. static struct thread_data threads[THREADS];
  26. static int thread_init(struct thread_data *td)
  27. {
  28. void *map;
  29. map = mmap(NULL, page_size,
  30. PROT_READ|PROT_WRITE|PROT_EXEC,
  31. MAP_SHARED|MAP_ANONYMOUS, -1, 0);
  32. if (map == MAP_FAILED) {
  33. perror("mmap failed");
  34. return -1;
  35. }
  36. td->map = map;
  37. td->tid = syscall(SYS_gettid);
  38. pr_debug("tid = %d, map = %p\n", td->tid, map);
  39. return 0;
  40. }
  41. static void *thread_fn(void *arg)
  42. {
  43. struct thread_data *td = arg;
  44. ssize_t ret;
  45. int go = 0;
  46. if (thread_init(td))
  47. return NULL;
  48. /* Signal thread_create thread is initialized. */
  49. ret = write(td->ready[1], &go, sizeof(int));
  50. if (ret != sizeof(int)) {
  51. pr_err("failed to notify\n");
  52. return NULL;
  53. }
  54. while (!go_away) {
  55. /* Waiting for main thread to kill us. */
  56. usleep(100);
  57. }
  58. munmap(td->map, page_size);
  59. return NULL;
  60. }
  61. static int thread_create(int i)
  62. {
  63. struct thread_data *td = &threads[i];
  64. int err, go;
  65. if (pipe(td->ready))
  66. return -1;
  67. err = pthread_create(&td->pt, NULL, thread_fn, td);
  68. if (!err) {
  69. /* Wait for thread initialization. */
  70. ssize_t ret = read(td->ready[0], &go, sizeof(int));
  71. err = ret != sizeof(int);
  72. }
  73. close(td->ready[0]);
  74. close(td->ready[1]);
  75. return err;
  76. }
  77. static int threads_create(void)
  78. {
  79. struct thread_data *td0 = &threads[0];
  80. int i, err = 0;
  81. go_away = 0;
  82. /* 0 is main thread */
  83. if (thread_init(td0))
  84. return -1;
  85. for (i = 1; !err && i < THREADS; i++)
  86. err = thread_create(i);
  87. return err;
  88. }
  89. static int threads_destroy(void)
  90. {
  91. struct thread_data *td0 = &threads[0];
  92. int i, err = 0;
  93. /* cleanup the main thread */
  94. munmap(td0->map, page_size);
  95. go_away = 1;
  96. for (i = 1; !err && i < THREADS; i++)
  97. err = pthread_join(threads[i].pt, NULL);
  98. return err;
  99. }
  100. typedef int (*synth_cb)(struct machine *machine);
  101. static int synth_all(struct machine *machine)
  102. {
  103. return perf_event__synthesize_threads(NULL,
  104. perf_event__process,
  105. machine, 0, 500, 1);
  106. }
  107. static int synth_process(struct machine *machine)
  108. {
  109. struct thread_map *map;
  110. int err;
  111. map = thread_map__new_by_pid(getpid());
  112. err = perf_event__synthesize_thread_map(NULL, map,
  113. perf_event__process,
  114. machine, 0, 500);
  115. thread_map__put(map);
  116. return err;
  117. }
  118. static int mmap_events(synth_cb synth)
  119. {
  120. struct machine *machine;
  121. int err, i;
  122. /*
  123. * The threads_create will not return before all threads
  124. * are spawned and all created memory map.
  125. *
  126. * They will loop until threads_destroy is called, so we
  127. * can safely run synthesizing function.
  128. */
  129. TEST_ASSERT_VAL("failed to create threads", !threads_create());
  130. machine = machine__new_host();
  131. dump_trace = verbose > 1 ? 1 : 0;
  132. err = synth(machine);
  133. dump_trace = 0;
  134. TEST_ASSERT_VAL("failed to destroy threads", !threads_destroy());
  135. TEST_ASSERT_VAL("failed to synthesize maps", !err);
  136. /*
  137. * All data is synthesized, try to find map for each
  138. * thread object.
  139. */
  140. for (i = 0; i < THREADS; i++) {
  141. struct thread_data *td = &threads[i];
  142. struct addr_location al;
  143. struct thread *thread;
  144. thread = machine__findnew_thread(machine, getpid(), td->tid);
  145. pr_debug("looking for map %p\n", td->map);
  146. thread__find_map(thread, PERF_RECORD_MISC_USER,
  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. machine__delete(machine);
  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_map
  171. *
  172. * by using all thread objects.
  173. */
  174. int test__mmap_thread_lookup(struct test *test __maybe_unused, int subtest __maybe_unused)
  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. }