Messages in this thread Patch in this message | | | Date | Mon, 25 Jun 2012 17:25:45 +0200 | Subject | [PATCH] perf: Make perf buildable for Android | From | Bernhard Rosenkränzer <> |
| |
Hi, this patch allows compiling perf for Android (with Bionic instead of glibc). Nothing overly complicated in there, just a couple of workarounds for missing functionality and header oddities in Bionic.
Signed-off-by: Bernhard Rosenkraenzer <Bernhard.Rosenkranzer@linaro.org>
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 92271d3..d15cdae 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -117,7 +117,7 @@ ifndef PERF_DEBUG endif
CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -EXTLIBS = -lpthread -lrt -lelf -lm +EXTLIBS = -lpthread -lelf -lm ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE ALL_LDFLAGS = $(LDFLAGS) STRIP ?= strip @@ -474,12 +474,23 @@ FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) ifneq ($(call try-cc,$(SOURCE_LIBELF),$(FLAGS_LIBELF)),y) FLAGS_GLIBC=$(ALL_CFLAGS) $(ALL_LDFLAGS) ifneq ($(call try-cc,$(SOURCE_GLIBC),$(FLAGS_GLIBC)),y) - msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); + ifeq ($(call try-cc,$(SOURCE_BIONIC),$(FLAGS_GLIBC)),y) + # Found Bionic instead of glibc... + # That works too, but needs a bit of special treatment + BASIC_CFLAGS += -DANDROID -include compat-android.h + ANDROID := 1 + else + msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static); + endif else msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel); endif endif
+ifneq ($(ANDROID),1) +EXTLIBS += -lrt +endif + ifneq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON)),y) BASIC_CFLAGS += -DLIBELF_NO_MMAP endif diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 223ffdc..1f20f4d 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -469,10 +469,17 @@ static int test__basic_mmap(void) .watermark = 0, }; cpu_set_t cpu_set; +#ifndef ANDROID const char *syscall_names[] = { "getsid", "getppid", "getpgrp", "getpgid", }; pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp, (void*)getpgid }; +#else + // No getsid() on Android + const char *syscall_names[] = { "getppid", "getpgrp", + "getpgid", }; + pid_t (*syscalls[])(void) = { getppid, getpgrp, (void*)getpgid }; +#endif #define nsyscalls ARRAY_SIZE(syscall_names) int ids[nsyscalls]; unsigned int nr_events[nsyscalls], diff --git a/tools/perf/compat-android.h b/tools/perf/compat-android.h new file mode 100644 index 0000000..7681f35 --- /dev/null +++ b/tools/perf/compat-android.h @@ -0,0 +1,90 @@ +/* Android compatibility header + * Provides missing bits in Bionic on Android, ignored + * on regular Linux. + * + * Written by Bernhard.Rosenkranzer@linaro.org + * + * Released into the public domain. Do with this file + * whatever you want. + */ +#ifdef ANDROID +/* Bionic has its own idea about ALIGN, and kills other definitions. + * Done outside the multiple-inclusion wrapper to make sure we + * can override Bionic's ALIGN by simply including compat-android.h + * again after including Bionic headers. + */ +#undef ALIGN +#undef __ALIGN_MASK +#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) +#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) + +#ifndef _COMPAT_ANDROID_H_ +#define _COMPAT_ANDROID_H_ 1 +#include <stdio.h> +#include <signal.h> +#include <asm/page.h> // for PAGE_SIZE +#include <asm/termios.h> // for winsize + +#ifndef __WORDSIZE +#include <stdint.h> +#define __WORDSIZE _BITSIZE +#endif + +#ifndef roundup +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) +#endif + +#ifndef __force +#define __force +#endif + +// Assorted functions that are missing from Bionic +static void psignal(int sig, const char *s) { + if(sig>=0 && sig<NSIG) { + if(s) + fprintf(stderr, "%s: %s\n", s, sys_siglist[sig]); + else + fprintf(stderr, "%s\n", sys_siglist[sig]); + } else { + if(s) + fprintf(stderr, "%s: invalid signal\n", s); + else + fputs("invalid signal\n", stderr); + } +} + +static ssize_t getline(char **lineptr, size_t *n, FILE *stream) { + size_t ret = 0; + + if (!lineptr || !n || !stream) + return -1; + + if(!*lineptr) { + *n = 128; + *lineptr = (char*)malloc(*n); + if(!*lineptr) + return -1; + } + + while(!feof(stream) && !ferror(stream)) { + int c; + if(ret == *n) { + *n += 128; + *lineptr = (char*)realloc(*lineptr, *n); + if(!*lineptr) { + *n = 0; + return -1; + } + } + c = fgetc(stream); + if(c == EOF) + break; + *lineptr[ret++] = c; + if(c == '\n') + break; + } + *lineptr[ret] = 0; + return ret; +} +#endif +#endif diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak index d9084e0..498cd4d 100644 --- a/tools/perf/config/feature-tests.mak +++ b/tools/perf/config/feature-tests.mak @@ -43,6 +43,19 @@ int main(void) } endef
+define SOURCE_BIONIC +#include <android/api-level.h> + +int main(void) +{ +#ifndef __ANDROID_API__ + error out +#else + return 0; +#endif +} +endef + define SOURCE_ELF_MMAP #include <libelf.h> int main(void) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index efa5dc8..ead88ea 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -6,6 +6,7 @@ #include "symbol.h" #include <linux/list.h> #include <linux/rbtree.h> +#include <pthread.h>
struct objdump_line { struct list_head node; diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 2a6f33c..867415a 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -6,6 +6,7 @@ #include "strlist.h" #include "thread.h" #include "thread_map.h" +#include "../compat-android.h"
static const char *perf_event__names[] = { [0] = "TOTAL", diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 1b19728..2b0554b 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -6,6 +6,7 @@
#include "../perf.h" #include "map.h" +#include "../compat-android.h"
/* * PERF_SAMPLE_IP | PERF_SAMPLE_TID | * diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 0f99f39..77c5ced 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -70,15 +70,19 @@ #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/select.h> +#ifndef ANDROID #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> +#endif #include <netdb.h> #include <pwd.h> #include <inttypes.h> #include "../../../include/linux/magic.h" #include "types.h" +#ifndef ANDROID #include <sys/ttydefaults.h> +#endif
extern const char *graph_line; extern const char *graph_dotted_line; diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 42e8aca..9eb8a4b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -32,6 +32,12 @@ #include <sched.h> #include <sys/mman.h>
+#ifdef ANDROID +// While stdlib.h has a prototype for it, +// Bionic doesn't actually implement on_exit() +static struct perf_record *__global_rec; +#endif + enum write_mode_t { WRITE_FORCE, WRITE_APPEND @@ -156,6 +162,11 @@ static void perf_record__sig_exit(int exit_status __used, void *arg) signal(signr, SIG_DFL); kill(getpid(), signr); } +#ifdef ANDROID +static void perf_record__sig_exit_android(void) { + perf_record__sig_exit(0, __global_rec); +} +#endif
static bool perf_evlist__equal(struct perf_evlist *evlist, struct perf_evlist *other) @@ -339,6 +350,11 @@ static void perf_record__exit(int status __used, void *arg) symbol__exit(); } } +#ifdef ANDROID +static void perf_record__exit_android(void) { + perf_record__exit(0, __global_rec); +} +#endif
static void perf_event__synthesize_guest_os(struct machine *machine, void *data) { @@ -412,7 +428,12 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
rec->page_size = sysconf(_SC_PAGE_SIZE);
+#ifndef ANDROID on_exit(perf_record__sig_exit, rec); +#else + __global_rec = rec; + atexit(perf_record__sig_exit_android); +#endif signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); signal(SIGUSR1, sig_handler); @@ -496,7 +517,11 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) /* * perf_session__delete(session) will be called at perf_record__exit() */ +#ifndef ANDROID on_exit(perf_record__exit, rec); +#else + atexit(perf_record__exit_android); +#endif
if (opts->pipe_output) { err = perf_header__write_pipe(output);
| |