mmap-thread-lookup.c 4.9 KB

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