From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932546AbaD2Gqn (ORCPT ); Tue, 29 Apr 2014 02:46:43 -0400 Received: from terminus.zytor.com ([198.137.202.10]:56878 "EHLO terminus.zytor.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932097AbaD2Gqk (ORCPT ); Tue, 29 Apr 2014 02:46:40 -0400 Date: Mon, 28 Apr 2014 23:46:05 -0700 From: tip-bot for Jiri Olsa Message-ID: Cc: eranian@google.com, mingo@kernel.org, jolsa@kernel.org, a.p.zijlstra@chello.nl, efault@gmx.de, acme@kernel.org, fweisbec@gmail.com, dsahern@gmail.com, tglx@linutronix.de, cjashfor@linux.vnet.ibm.com, dzickus@redhat.com, hpa@zytor.com, paulus@samba.org, linux-kernel@vger.kernel.org, namhyung@kernel.org, adrian.hunter@intel.com Reply-To: mingo@kernel.org, eranian@google.com, jolsa@kernel.org, a.p.zijlstra@chello.nl, efault@gmx.de, acme@kernel.org, fweisbec@gmail.com, dsahern@gmail.com, tglx@linutronix.de, cjashfor@linux.vnet.ibm.com, dzickus@redhat.com, hpa@zytor.com, paulus@samba.org, linux-kernel@vger.kernel.org, namhyung@kernel.org, adrian.hunter@intel.com In-Reply-To: <1397490723-1992-2-git-send-email-jolsa@redhat.com> References: <1397490723-1992-2-git-send-email-jolsa@redhat.com> To: linux-tip-commits@vger.kernel.org Subject: [tip:perf/core] perf tests: Add thread maps lookup automated tests Git-Commit-ID: 4e85edfc3f5c0e016a960c1dcbe0217e86602525 X-Mailer: tip-git-log-daemon Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=UTF-8 Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit-ID: 4e85edfc3f5c0e016a960c1dcbe0217e86602525 Gitweb: http://git.kernel.org/tip/4e85edfc3f5c0e016a960c1dcbe0217e86602525 Author: Jiri Olsa AuthorDate: Wed, 5 Mar 2014 17:20:31 +0100 Committer: Jiri Olsa CommitDate: Mon, 28 Apr 2014 13:42:52 +0200 perf tests: Add thread maps lookup automated tests Adding automated test for memory maps lookup within multiple machines threads. The test creates 4 threads and separated memory maps. It checks that we could use thread__find_addr_map function with thread object based on TID to find memory maps. Acked-by: Namhyung Kim Cc: Adrian Hunter Cc: Arnaldo Carvalho de Melo Cc: Corey Ashford Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1397490723-1992-2-git-send-email-jolsa@redhat.com Signed-off-by: Jiri Olsa --- tools/perf/Makefile.perf | 1 + tools/perf/perf.h | 6 + tools/perf/tests/builtin-test.c | 4 + tools/perf/tests/mmap-thread-lookup.c | 233 ++++++++++++++++++++++++++++++++++ tools/perf/tests/tests.h | 1 + 5 files changed, 245 insertions(+) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 0807e4c..16d4f4e 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -416,6 +416,7 @@ ifeq ($(ARCH),x86) LIB_OBJS += $(OUTPUT)tests/dwarf-unwind.o endif endif +LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o BUILTIN_OBJS += $(OUTPUT)builtin-bench.o diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 5c11eca..ebdad33 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -15,6 +15,9 @@ #ifndef __NR_futex # define __NR_futex 240 #endif +#ifndef __NR_gettid +# define __NR_gettid 224 +#endif #endif #if defined(__x86_64__) @@ -29,6 +32,9 @@ #ifndef __NR_futex # define __NR_futex 202 #endif +#ifndef __NR_gettid +# define __NR_gettid 186 +#endif #endif #ifdef __powerpc__ diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index ceb9dae..bb60792 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -128,6 +128,10 @@ static struct test { .func = test__hists_filter, }, { + .desc = "Test mmap thread lookup", + .func = test__mmap_thread_lookup, + }, + { .func = NULL, }, }; diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c new file mode 100644 index 0000000..4a456fe --- /dev/null +++ b/tools/perf/tests/mmap-thread-lookup.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include +#include +#include "debug.h" +#include "tests.h" +#include "machine.h" +#include "thread_map.h" +#include "symbol.h" +#include "thread.h" + +#define THREADS 4 + +static int go_away; + +struct thread_data { + pthread_t pt; + pid_t tid; + void *map; + int ready[2]; +}; + +static struct thread_data threads[THREADS]; + +static int thread_init(struct thread_data *td) +{ + void *map; + + map = mmap(NULL, page_size, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_SHARED|MAP_ANONYMOUS, -1, 0); + + if (map == MAP_FAILED) { + perror("mmap failed"); + return -1; + } + + td->map = map; + td->tid = syscall(SYS_gettid); + + pr_debug("tid = %d, map = %p\n", td->tid, map); + return 0; +} + +static void *thread_fn(void *arg) +{ + struct thread_data *td = arg; + ssize_t ret; + int go; + + if (thread_init(td)) + return NULL; + + /* Signal thread_create thread is initialized. */ + ret = write(td->ready[1], &go, sizeof(int)); + if (ret != sizeof(int)) { + pr_err("failed to notify\n"); + return NULL; + } + + while (!go_away) { + /* Waiting for main thread to kill us. */ + usleep(100); + } + + munmap(td->map, page_size); + return NULL; +} + +static int thread_create(int i) +{ + struct thread_data *td = &threads[i]; + int err, go; + + if (pipe(td->ready)) + return -1; + + err = pthread_create(&td->pt, NULL, thread_fn, td); + if (!err) { + /* Wait for thread initialization. */ + ssize_t ret = read(td->ready[0], &go, sizeof(int)); + err = ret != sizeof(int); + } + + close(td->ready[0]); + close(td->ready[1]); + return err; +} + +static int threads_create(void) +{ + struct thread_data *td0 = &threads[0]; + int i, err = 0; + + go_away = 0; + + /* 0 is main thread */ + if (thread_init(td0)) + return -1; + + for (i = 1; !err && i < THREADS; i++) + err = thread_create(i); + + return err; +} + +static int threads_destroy(void) +{ + struct thread_data *td0 = &threads[0]; + int i, err = 0; + + /* cleanup the main thread */ + munmap(td0->map, page_size); + + go_away = 1; + + for (i = 1; !err && i < THREADS; i++) + err = pthread_join(threads[i].pt, NULL); + + return err; +} + +typedef int (*synth_cb)(struct machine *machine); + +static int synth_all(struct machine *machine) +{ + return perf_event__synthesize_threads(NULL, + perf_event__process, + machine, 0); +} + +static int synth_process(struct machine *machine) +{ + struct thread_map *map; + int err; + + map = thread_map__new_by_pid(getpid()); + + err = perf_event__synthesize_thread_map(NULL, map, + perf_event__process, + machine, 0); + + thread_map__delete(map); + return err; +} + +static int mmap_events(synth_cb synth) +{ + struct machines machines; + struct machine *machine; + int err, i; + + /* + * The threads_create will not return before all threads + * are spawned and all created memory map. + * + * They will loop until threads_destroy is called, so we + * can safely run synthesizing function. + */ + TEST_ASSERT_VAL("failed to create threads", !threads_create()); + + machines__init(&machines); + machine = &machines.host; + + dump_trace = verbose > 1 ? 1 : 0; + + err = synth(machine); + + dump_trace = 0; + + TEST_ASSERT_VAL("failed to destroy threads", !threads_destroy()); + TEST_ASSERT_VAL("failed to synthesize maps", !err); + + /* + * All data is synthesized, try to find map for each + * thread object. + */ + for (i = 0; i < THREADS; i++) { + struct thread_data *td = &threads[i]; + struct addr_location al; + struct thread *thread; + + thread = machine__findnew_thread(machine, getpid(), td->tid); + + pr_debug("looking for map %p\n", td->map); + + thread__find_addr_map(thread, machine, + PERF_RECORD_MISC_USER, MAP__FUNCTION, + (unsigned long) (td->map + 1), &al); + + if (!al.map) { + pr_debug("failed, couldn't find map\n"); + err = -1; + break; + } + + pr_debug("map %p, addr %" PRIx64 "\n", al.map, al.map->start); + } + + machine__delete_threads(machine); + machines__exit(&machines); + return err; +} + +/* + * This test creates 'THREADS' number of threads (including + * main thread) and each thread creates memory map. + * + * When threads are created, we synthesize them with both + * (separate tests): + * perf_event__synthesize_thread_map (process based) + * perf_event__synthesize_threads (global) + * + * We test we can find all memory maps via: + * thread__find_addr_map + * + * by using all thread objects. + */ +int test__mmap_thread_lookup(void) +{ + /* perf_event__synthesize_threads synthesize */ + TEST_ASSERT_VAL("failed with sythesizing all", + !mmap_events(synth_all)); + + /* perf_event__synthesize_thread_map synthesize */ + TEST_ASSERT_VAL("failed with sythesizing process", + !mmap_events(synth_process)); + + return 0; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index fe39163..82e8061 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -42,6 +42,7 @@ int test__keep_tracking(void); int test__parse_no_sample_id_all(void); int test__dwarf_unwind(void); int test__hists_filter(void); +int test__mmap_thread_lookup(void); #if defined(__x86_64__) || defined(__i386__) #ifdef HAVE_DWARF_UNWIND_SUPPORT