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