mmap-thread-lookup.c 4.7 KB

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