root/tools/perf/tests/mmap-thread-lookup.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. thread_init
  2. thread_fn
  3. thread_create
  4. threads_create
  5. threads_destroy
  6. synth_all
  7. synth_process
  8. mmap_events
  9. test__mmap_thread_lookup

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

/* [<][>][^][v][top][bottom][index][help] */