mirror of
https://github.com/adulau/aha.git
synced 2025-01-17 05:22:03 +00:00
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: perf sched: Fix build failure on sparc perf bench: Add "all" pseudo subsystem and "all" pseudo suite perf tools: Introduce perf_session class perf symbols: Ditch dso->find_symbol perf symbols: Allow lookups by symbol name too perf symbols: Add missing "Variables" entry to map_type__name perf symbols: Add support for 'variable' symtabs perf symbols: Introduce ELF counterparts to symbol_type__is_a perf symbols: Introduce symbol_type__is_a perf symbols: Rename kthreads to kmaps, using another abstraction for it perf tools: Allow building for ARM hw-breakpoints: Handle bad modify_user_hw_breakpoint off-case return value perf tools: Allow cross compiling tracing, slab: Fix no callsite ifndef CONFIG_KMEMTRACE tracing, slab: Define kmem_cache_alloc_notrace ifdef CONFIG_TRACING Trivial conflict due to different fixes to modify_user_hw_breakpoint() in include/linux/hw_breakpoint.h
This commit is contained in:
commit
2205afa7d1
31 changed files with 650 additions and 352 deletions
|
@ -93,7 +93,7 @@ register_user_hw_breakpoint(struct perf_event_attr *attr,
|
|||
struct task_struct *tsk) { return NULL; }
|
||||
static inline int
|
||||
modify_user_hw_breakpoint(struct perf_event *bp,
|
||||
struct perf_event_attr *attr) { return 0; }
|
||||
struct perf_event_attr *attr) { return -ENOSYS; }
|
||||
static inline struct perf_event *
|
||||
register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr,
|
||||
perf_overflow_handler_t triggered,
|
||||
|
|
|
@ -110,7 +110,7 @@ extern struct cache_sizes malloc_sizes[];
|
|||
void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
|
||||
void *__kmalloc(size_t size, gfp_t flags);
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
#ifdef CONFIG_TRACING
|
||||
extern void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags);
|
||||
extern size_t slab_buffer_size(struct kmem_cache *cachep);
|
||||
#else
|
||||
|
@ -166,7 +166,7 @@ found:
|
|||
extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
|
||||
extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
#ifdef CONFIG_TRACING
|
||||
extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep,
|
||||
gfp_t flags,
|
||||
int nodeid);
|
||||
|
|
|
@ -217,7 +217,7 @@ static __always_inline struct kmem_cache *kmalloc_slab(size_t size)
|
|||
void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
|
||||
void *__kmalloc(size_t size, gfp_t flags);
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
#ifdef CONFIG_TRACING
|
||||
extern void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags);
|
||||
#else
|
||||
static __always_inline void *
|
||||
|
@ -266,7 +266,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
|
|||
void *__kmalloc_node(size_t size, gfp_t flags, int node);
|
||||
void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
#ifdef CONFIG_TRACING
|
||||
extern void *kmem_cache_alloc_node_notrace(struct kmem_cache *s,
|
||||
gfp_t gfpflags,
|
||||
int node);
|
||||
|
|
12
mm/slab.c
12
mm/slab.c
|
@ -490,7 +490,7 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp)
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
#ifdef CONFIG_TRACING
|
||||
size_t slab_buffer_size(struct kmem_cache *cachep)
|
||||
{
|
||||
return cachep->buffer_size;
|
||||
|
@ -3578,7 +3578,7 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
|
|||
}
|
||||
EXPORT_SYMBOL(kmem_cache_alloc);
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
#ifdef CONFIG_TRACING
|
||||
void *kmem_cache_alloc_notrace(struct kmem_cache *cachep, gfp_t flags)
|
||||
{
|
||||
return __cache_alloc(cachep, flags, __builtin_return_address(0));
|
||||
|
@ -3641,7 +3641,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid)
|
|||
}
|
||||
EXPORT_SYMBOL(kmem_cache_alloc_node);
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
#ifdef CONFIG_TRACING
|
||||
void *kmem_cache_alloc_node_notrace(struct kmem_cache *cachep,
|
||||
gfp_t flags,
|
||||
int nodeid)
|
||||
|
@ -3669,7 +3669,7 @@ __do_kmalloc_node(size_t size, gfp_t flags, int node, void *caller)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_KMEMTRACE)
|
||||
#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_TRACING)
|
||||
void *__kmalloc_node(size_t size, gfp_t flags, int node)
|
||||
{
|
||||
return __do_kmalloc_node(size, flags, node,
|
||||
|
@ -3689,7 +3689,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
|
|||
return __do_kmalloc_node(size, flags, node, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(__kmalloc_node);
|
||||
#endif /* CONFIG_DEBUG_SLAB */
|
||||
#endif /* CONFIG_DEBUG_SLAB || CONFIG_TRACING */
|
||||
#endif /* CONFIG_NUMA */
|
||||
|
||||
/**
|
||||
|
@ -3721,7 +3721,7 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
|
|||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_KMEMTRACE)
|
||||
#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_TRACING)
|
||||
void *__kmalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
return __do_kmalloc(size, flags, __builtin_return_address(0));
|
||||
|
|
|
@ -1754,7 +1754,7 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
|
|||
}
|
||||
EXPORT_SYMBOL(kmem_cache_alloc);
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
#ifdef CONFIG_TRACING
|
||||
void *kmem_cache_alloc_notrace(struct kmem_cache *s, gfp_t gfpflags)
|
||||
{
|
||||
return slab_alloc(s, gfpflags, -1, _RET_IP_);
|
||||
|
@ -1775,7 +1775,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
|
|||
EXPORT_SYMBOL(kmem_cache_alloc_node);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KMEMTRACE
|
||||
#ifdef CONFIG_TRACING
|
||||
void *kmem_cache_alloc_node_notrace(struct kmem_cache *s,
|
||||
gfp_t gfpflags,
|
||||
int node)
|
||||
|
|
|
@ -237,8 +237,8 @@ lib = lib
|
|||
|
||||
export prefix bindir sharedir sysconfdir
|
||||
|
||||
CC = gcc
|
||||
AR = ar
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
AR = $(CROSS_COMPILE)ar
|
||||
RM = rm -f
|
||||
TAR = tar
|
||||
FIND = find
|
||||
|
@ -356,7 +356,9 @@ LIB_H += util/parse-options.h
|
|||
LIB_H += util/parse-events.h
|
||||
LIB_H += util/quote.h
|
||||
LIB_H += util/util.h
|
||||
LIB_H += util/header.h
|
||||
LIB_H += util/help.h
|
||||
LIB_H += util/session.h
|
||||
LIB_H += util/strbuf.h
|
||||
LIB_H += util/string.h
|
||||
LIB_H += util/strlist.h
|
||||
|
@ -405,6 +407,7 @@ LIB_OBJS += util/callchain.o
|
|||
LIB_OBJS += util/values.o
|
||||
LIB_OBJS += util/debug.o
|
||||
LIB_OBJS += util/map.o
|
||||
LIB_OBJS += util/session.o
|
||||
LIB_OBJS += util/thread.o
|
||||
LIB_OBJS += util/trace-event-parse.o
|
||||
LIB_OBJS += util/trace-event-read.o
|
||||
|
@ -492,8 +495,10 @@ else
|
|||
LIB_OBJS += util/probe-finder.o
|
||||
endif
|
||||
|
||||
ifndef NO_LIBPERL
|
||||
PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
|
||||
PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
|
||||
endif
|
||||
|
||||
ifneq ($(shell sh -c "(echo '\#include <EXTERN.h>'; echo '\#include <perl.h>'; echo 'int main(void) { perl_alloc(); return 0; }') | $(CC) -x c - $(PERL_EMBED_CCOPTS) -o /dev/null $(PERL_EMBED_LDOPTS) > /dev/null 2>&1 && echo y"), y)
|
||||
BASIC_CFLAGS += -DNO_LIBPERL
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*
|
||||
* builtin-bench-messaging.c
|
||||
* sched-messaging.c
|
||||
*
|
||||
* messaging: Benchmark for scheduler and IPC mechanisms
|
||||
*
|
||||
|
@ -320,10 +320,12 @@ int bench_sched_messaging(int argc, const char **argv,
|
|||
num_groups, num_groups * 2 * num_fds,
|
||||
thread_mode ? "threads" : "processes");
|
||||
printf(" %14s: %lu.%03lu [sec]\n", "Total time",
|
||||
diff.tv_sec, diff.tv_usec/1000);
|
||||
diff.tv_sec,
|
||||
(unsigned long) (diff.tv_usec/1000));
|
||||
break;
|
||||
case BENCH_FORMAT_SIMPLE:
|
||||
printf("%lu.%03lu\n", diff.tv_sec, diff.tv_usec/1000);
|
||||
printf("%lu.%03lu\n", diff.tv_sec,
|
||||
(unsigned long) (diff.tv_usec/1000));
|
||||
break;
|
||||
default:
|
||||
/* reaching here is something disaster */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
*
|
||||
* builtin-bench-pipe.c
|
||||
* sched-pipe.c
|
||||
*
|
||||
* pipe: Benchmark for pipe()
|
||||
*
|
||||
|
@ -87,7 +87,8 @@ int bench_sched_pipe(int argc, const char **argv,
|
|||
if (pid) {
|
||||
retpid = waitpid(pid, &wait_stat, 0);
|
||||
assert((retpid == pid) && WIFEXITED(wait_stat));
|
||||
return 0;
|
||||
} else {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
switch (bench_format) {
|
||||
|
@ -99,7 +100,8 @@ int bench_sched_pipe(int argc, const char **argv,
|
|||
result_usec += diff.tv_usec;
|
||||
|
||||
printf(" %14s: %lu.%03lu [sec]\n\n", "Total time",
|
||||
diff.tv_sec, diff.tv_usec/1000);
|
||||
diff.tv_sec,
|
||||
(unsigned long) (diff.tv_usec/1000));
|
||||
|
||||
printf(" %14lf usecs/op\n",
|
||||
(double)result_usec / (double)loops);
|
||||
|
@ -110,7 +112,8 @@ int bench_sched_pipe(int argc, const char **argv,
|
|||
|
||||
case BENCH_FORMAT_SIMPLE:
|
||||
printf("%lu.%03lu\n",
|
||||
diff.tv_sec, diff.tv_usec / 1000);
|
||||
diff.tv_sec,
|
||||
(unsigned long) (diff.tv_usec / 1000));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "util/thread.h"
|
||||
#include "util/sort.h"
|
||||
#include "util/hist.h"
|
||||
#include "util/session.h"
|
||||
#include "util/data_map.h"
|
||||
|
||||
static char const *input_name = "perf.data";
|
||||
|
@ -462,21 +463,23 @@ static struct perf_file_handler file_handler = {
|
|||
|
||||
static int __cmd_annotate(void)
|
||||
{
|
||||
struct perf_header *header;
|
||||
struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
|
||||
struct thread *idle;
|
||||
int ret;
|
||||
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
idle = register_idle_thread();
|
||||
register_perf_file_handler(&file_handler);
|
||||
|
||||
ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
|
||||
&event__cwdlen, &event__cwd);
|
||||
ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out_delete;
|
||||
|
||||
if (dump_trace) {
|
||||
event__print_totals();
|
||||
return 0;
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
if (verbose > 3)
|
||||
|
@ -489,6 +492,8 @@ static int __cmd_annotate(void)
|
|||
output__resort(event__total[0]);
|
||||
|
||||
find_annotations();
|
||||
out_delete:
|
||||
perf_session__delete(session);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ struct bench_suite {
|
|||
const char *summary;
|
||||
int (*fn)(int, const char **, const char *);
|
||||
};
|
||||
\
|
||||
/* sentinel: easy for help */
|
||||
#define suite_all { "all", "test all suite (pseudo suite)", NULL }
|
||||
|
||||
static struct bench_suite sched_suites[] = {
|
||||
{ "messaging",
|
||||
|
@ -39,6 +42,7 @@ static struct bench_suite sched_suites[] = {
|
|||
{ "pipe",
|
||||
"Flood of communication over pipe() between two processes",
|
||||
bench_sched_pipe },
|
||||
suite_all,
|
||||
{ NULL,
|
||||
NULL,
|
||||
NULL }
|
||||
|
@ -48,6 +52,7 @@ static struct bench_suite mem_suites[] = {
|
|||
{ "memcpy",
|
||||
"Simple memory copy in various ways",
|
||||
bench_mem_memcpy },
|
||||
suite_all,
|
||||
{ NULL,
|
||||
NULL,
|
||||
NULL }
|
||||
|
@ -66,6 +71,9 @@ static struct bench_subsys subsystems[] = {
|
|||
{ "mem",
|
||||
"memory access performance",
|
||||
mem_suites },
|
||||
{ "all", /* sentinel: easy for help */
|
||||
"test all subsystem (pseudo subsystem)",
|
||||
NULL },
|
||||
{ NULL,
|
||||
NULL,
|
||||
NULL }
|
||||
|
@ -75,11 +83,11 @@ static void dump_suites(int subsys_index)
|
|||
{
|
||||
int i;
|
||||
|
||||
printf("List of available suites for %s...\n\n",
|
||||
printf("# List of available suites for %s...\n\n",
|
||||
subsystems[subsys_index].name);
|
||||
|
||||
for (i = 0; subsystems[subsys_index].suites[i].name; i++)
|
||||
printf("\t%s: %s\n",
|
||||
printf("%14s: %s\n",
|
||||
subsystems[subsys_index].suites[i].name,
|
||||
subsystems[subsys_index].suites[i].summary);
|
||||
|
||||
|
@ -110,10 +118,10 @@ static void print_usage(void)
|
|||
printf("\t%s\n", bench_usage[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("List of available subsystems...\n\n");
|
||||
printf("# List of available subsystems...\n\n");
|
||||
|
||||
for (i = 0; subsystems[i].name; i++)
|
||||
printf("\t%s: %s\n",
|
||||
printf("%14s: %s\n",
|
||||
subsystems[i].name, subsystems[i].summary);
|
||||
printf("\n");
|
||||
}
|
||||
|
@ -131,6 +139,37 @@ static int bench_str2int(char *str)
|
|||
return BENCH_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
static void all_suite(struct bench_subsys *subsys) /* FROM HERE */
|
||||
{
|
||||
int i;
|
||||
const char *argv[2];
|
||||
struct bench_suite *suites = subsys->suites;
|
||||
|
||||
argv[1] = NULL;
|
||||
/*
|
||||
* TODO:
|
||||
* preparing preset parameters for
|
||||
* embedded, ordinary PC, HPC, etc...
|
||||
* will be helpful
|
||||
*/
|
||||
for (i = 0; suites[i].fn; i++) {
|
||||
printf("# Running %s/%s benchmark...\n",
|
||||
subsys->name,
|
||||
suites[i].name);
|
||||
|
||||
argv[1] = suites[i].name;
|
||||
suites[i].fn(1, argv, NULL);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void all_subsystem(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; subsystems[i].suites; i++)
|
||||
all_suite(&subsystems[i]);
|
||||
}
|
||||
|
||||
int cmd_bench(int argc, const char **argv, const char *prefix __used)
|
||||
{
|
||||
int i, j, status = 0;
|
||||
|
@ -155,6 +194,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __used)
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "all")) {
|
||||
all_subsystem();
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (i = 0; subsystems[i].name; i++) {
|
||||
if (strcmp(subsystems[i].name, argv[0]))
|
||||
continue;
|
||||
|
@ -165,6 +209,11 @@ int cmd_bench(int argc, const char **argv, const char *prefix __used)
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "all")) {
|
||||
all_suite(&subsystems[i]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (j = 0; subsystems[i].suites[j].name; j++) {
|
||||
if (strcmp(subsystems[i].suites[j].name, argv[1]))
|
||||
continue;
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#include "util/cache.h"
|
||||
#include "util/data_map.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/header.h"
|
||||
#include "util/parse-options.h"
|
||||
#include "util/session.h"
|
||||
#include "util/symbol.h"
|
||||
|
||||
static char const *input_name = "perf.data";
|
||||
|
@ -55,56 +55,17 @@ static int perf_file_section__process_buildids(struct perf_file_section *self,
|
|||
static int __cmd_buildid_list(void)
|
||||
{
|
||||
int err = -1;
|
||||
struct perf_header *header;
|
||||
struct perf_file_header f_header;
|
||||
struct stat input_stat;
|
||||
int input = open(input_name, O_RDONLY);
|
||||
struct perf_session *session = perf_session__new(input_name, O_RDONLY, force);
|
||||
|
||||
if (input < 0) {
|
||||
pr_err("failed to open file: %s", input_name);
|
||||
if (!strcmp(input_name, "perf.data"))
|
||||
pr_err(" (try 'perf record' first)");
|
||||
pr_err("\n");
|
||||
goto out;
|
||||
}
|
||||
if (session == NULL)
|
||||
return -1;
|
||||
|
||||
err = fstat(input, &input_stat);
|
||||
if (err < 0) {
|
||||
perror("failed to stat file");
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
|
||||
pr_err("file %s not owned by current user or root\n",
|
||||
input_name);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (!input_stat.st_size) {
|
||||
pr_info("zero-sized file, nothing to do!\n");
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
err = -1;
|
||||
header = perf_header__new();
|
||||
if (header == NULL)
|
||||
goto out_close;
|
||||
|
||||
if (perf_file_header__read(&f_header, header, input) < 0) {
|
||||
pr_warning("incompatible file format");
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
err = perf_header__process_sections(header, input,
|
||||
err = perf_header__process_sections(&session->header, session->fd,
|
||||
perf_file_section__process_buildids);
|
||||
if (err >= 0)
|
||||
dsos__fprintf_buildid(stdout);
|
||||
|
||||
if (err < 0)
|
||||
goto out_close;
|
||||
|
||||
dsos__fprintf_buildid(stdout);
|
||||
out_close:
|
||||
close(input);
|
||||
out:
|
||||
perf_session__delete(session);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "util/symbol.h"
|
||||
#include "util/thread.h"
|
||||
#include "util/header.h"
|
||||
#include "util/session.h"
|
||||
|
||||
#include "util/parse-options.h"
|
||||
#include "util/trace-event.h"
|
||||
|
@ -20,7 +21,6 @@ typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *);
|
|||
|
||||
static char const *input_name = "perf.data";
|
||||
|
||||
static struct perf_header *header;
|
||||
static u64 sample_type;
|
||||
|
||||
static int alloc_flag;
|
||||
|
@ -367,11 +367,18 @@ static struct perf_file_handler file_handler = {
|
|||
|
||||
static int read_events(void)
|
||||
{
|
||||
int err;
|
||||
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
|
||||
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
register_idle_thread();
|
||||
register_perf_file_handler(&file_handler);
|
||||
|
||||
return mmap_dispatch_perf_file(&header, input_name, 0, 0,
|
||||
&event__cwdlen, &event__cwd);
|
||||
err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
|
||||
perf_session__delete(session);
|
||||
return err;
|
||||
}
|
||||
|
||||
static double fragmentation(unsigned long n_req, unsigned long n_alloc)
|
||||
|
@ -403,7 +410,7 @@ static void __print_result(struct rb_root *root, int n_lines, int is_caller)
|
|||
if (is_caller) {
|
||||
addr = data->call_site;
|
||||
if (!raw_ip)
|
||||
sym = thread__find_function(kthread, addr, NULL);
|
||||
sym = map_groups__find_function(kmaps, addr, NULL);
|
||||
} else
|
||||
addr = data->ptr;
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "util/header.h"
|
||||
#include "util/event.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/session.h"
|
||||
#include "util/symbol.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
@ -62,7 +63,7 @@ static int nr_cpu = 0;
|
|||
|
||||
static int file_new = 1;
|
||||
|
||||
struct perf_header *header = NULL;
|
||||
static struct perf_session *session;
|
||||
|
||||
struct mmap_data {
|
||||
int counter;
|
||||
|
@ -216,12 +217,12 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
|
|||
{
|
||||
struct perf_header_attr *h_attr;
|
||||
|
||||
if (nr < header->attrs) {
|
||||
h_attr = header->attr[nr];
|
||||
if (nr < session->header.attrs) {
|
||||
h_attr = session->header.attr[nr];
|
||||
} else {
|
||||
h_attr = perf_header_attr__new(a);
|
||||
if (h_attr != NULL)
|
||||
if (perf_header__add_attr(header, h_attr) < 0) {
|
||||
if (perf_header__add_attr(&session->header, h_attr) < 0) {
|
||||
perf_header_attr__delete(h_attr);
|
||||
h_attr = NULL;
|
||||
}
|
||||
|
@ -395,9 +396,9 @@ static void open_counters(int cpu, pid_t pid)
|
|||
|
||||
static void atexit_header(void)
|
||||
{
|
||||
header->data_size += bytes_written;
|
||||
session->header.data_size += bytes_written;
|
||||
|
||||
perf_header__write(header, output, true);
|
||||
perf_header__write(&session->header, output, true);
|
||||
}
|
||||
|
||||
static int __cmd_record(int argc, const char **argv)
|
||||
|
@ -440,24 +441,24 @@ static int __cmd_record(int argc, const char **argv)
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
header = perf_header__new();
|
||||
if (header == NULL) {
|
||||
session = perf_session__new(output_name, O_WRONLY, force);
|
||||
if (session == NULL) {
|
||||
pr_err("Not enough memory for reading perf file header\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!file_new) {
|
||||
err = perf_header__read(header, output);
|
||||
err = perf_header__read(&session->header, output);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (raw_samples) {
|
||||
perf_header__set_feat(header, HEADER_TRACE_INFO);
|
||||
perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
|
||||
} else {
|
||||
for (i = 0; i < nr_counters; i++) {
|
||||
if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
|
||||
perf_header__set_feat(header, HEADER_TRACE_INFO);
|
||||
perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -481,7 +482,7 @@ static int __cmd_record(int argc, const char **argv)
|
|||
}
|
||||
|
||||
if (file_new) {
|
||||
err = perf_header__write(header, output, false);
|
||||
err = perf_header__write(&session->header, output, false);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "perf.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/header.h"
|
||||
#include "util/session.h"
|
||||
|
||||
#include "util/parse-options.h"
|
||||
#include "util/parse-events.h"
|
||||
|
@ -52,7 +53,7 @@ static int exclude_other = 1;
|
|||
|
||||
static char callchain_default_opt[] = "fractal,0.5";
|
||||
|
||||
static struct perf_header *header;
|
||||
static struct perf_session *session;
|
||||
|
||||
static u64 sample_type;
|
||||
|
||||
|
@ -701,7 +702,7 @@ static int process_read_event(event_t *event)
|
|||
{
|
||||
struct perf_event_attr *attr;
|
||||
|
||||
attr = perf_header__find_attr(event->read.id, header);
|
||||
attr = perf_header__find_attr(event->read.id, &session->header);
|
||||
|
||||
if (show_threads) {
|
||||
const char *name = attr ? __event_name(attr->type, attr->config)
|
||||
|
@ -766,6 +767,10 @@ static int __cmd_report(void)
|
|||
struct thread *idle;
|
||||
int ret;
|
||||
|
||||
session = perf_session__new(input_name, O_RDONLY, force);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
idle = register_idle_thread();
|
||||
thread__comm_adjust(idle);
|
||||
|
||||
|
@ -774,14 +779,14 @@ static int __cmd_report(void)
|
|||
|
||||
register_perf_file_handler(&file_handler);
|
||||
|
||||
ret = mmap_dispatch_perf_file(&header, input_name, force,
|
||||
full_paths, &event__cwdlen, &event__cwd);
|
||||
ret = perf_session__process_events(session, full_paths,
|
||||
&event__cwdlen, &event__cwd);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out_delete;
|
||||
|
||||
if (dump_trace) {
|
||||
event__print_totals();
|
||||
return 0;
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
if (verbose > 3)
|
||||
|
@ -796,7 +801,8 @@ static int __cmd_report(void)
|
|||
|
||||
if (show_threads)
|
||||
perf_read_values_destroy(&show_threads_values);
|
||||
|
||||
out_delete:
|
||||
perf_session__delete(session);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "util/symbol.h"
|
||||
#include "util/thread.h"
|
||||
#include "util/header.h"
|
||||
#include "util/session.h"
|
||||
|
||||
#include "util/parse-options.h"
|
||||
#include "util/trace-event.h"
|
||||
|
@ -21,7 +22,6 @@
|
|||
|
||||
static char const *input_name = "perf.data";
|
||||
|
||||
static struct perf_header *header;
|
||||
static u64 sample_type;
|
||||
|
||||
static char default_sort_order[] = "avg, max, switch, runtime";
|
||||
|
@ -1663,11 +1663,18 @@ static struct perf_file_handler file_handler = {
|
|||
|
||||
static int read_events(void)
|
||||
{
|
||||
int err;
|
||||
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
|
||||
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
register_idle_thread();
|
||||
register_perf_file_handler(&file_handler);
|
||||
|
||||
return mmap_dispatch_perf_file(&header, input_name, 0, 0,
|
||||
&event__cwdlen, &event__cwd);
|
||||
err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
|
||||
perf_session__delete(session);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void print_bad_events(void)
|
||||
|
|
|
@ -1059,15 +1059,17 @@ static struct perf_file_handler file_handler = {
|
|||
|
||||
static int __cmd_timechart(void)
|
||||
{
|
||||
struct perf_header *header;
|
||||
struct perf_session *session = perf_session__new(input_name, O_RDONLY, 0);
|
||||
int ret;
|
||||
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
register_perf_file_handler(&file_handler);
|
||||
|
||||
ret = mmap_dispatch_perf_file(&header, input_name, 0, 0,
|
||||
&event__cwdlen, &event__cwd);
|
||||
ret = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
|
||||
if (ret)
|
||||
return EXIT_FAILURE;
|
||||
goto out_delete;
|
||||
|
||||
process_samples();
|
||||
|
||||
|
@ -1079,8 +1081,9 @@ static int __cmd_timechart(void)
|
|||
|
||||
pr_info("Written %2.1f seconds of trace to %s.\n",
|
||||
(last_time - first_time) / 1000000000.0, output_name);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
out_delete:
|
||||
perf_session__delete(session);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char * const timechart_usage[] = {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "util/header.h"
|
||||
#include "util/exec_cmd.h"
|
||||
#include "util/trace-event.h"
|
||||
#include "util/session.h"
|
||||
|
||||
static char const *script_name;
|
||||
static char const *generate_script_lang;
|
||||
|
@ -61,7 +62,7 @@ static int cleanup_scripting(void)
|
|||
|
||||
static char const *input_name = "perf.data";
|
||||
|
||||
static struct perf_header *header;
|
||||
static struct perf_session *session;
|
||||
static u64 sample_type;
|
||||
|
||||
static int process_sample_event(event_t *event)
|
||||
|
@ -126,11 +127,18 @@ static struct perf_file_handler file_handler = {
|
|||
|
||||
static int __cmd_trace(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
session = perf_session__new(input_name, O_RDONLY, 0);
|
||||
if (session == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
register_idle_thread();
|
||||
register_perf_file_handler(&file_handler);
|
||||
|
||||
return mmap_dispatch_perf_file(&header, input_name,
|
||||
0, 0, &event__cwdlen, &event__cwd);
|
||||
err = perf_session__process_events(session, 0, &event__cwdlen, &event__cwd);
|
||||
perf_session__delete(session);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct script_spec {
|
||||
|
@ -348,11 +356,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
|
|||
return -1;
|
||||
}
|
||||
|
||||
header = perf_header__new();
|
||||
if (header == NULL)
|
||||
return -1;
|
||||
|
||||
perf_header__read(header, input);
|
||||
perf_header__read(&session->header, input);
|
||||
err = scripting_ops->generate_script("perf-trace");
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,18 @@
|
|||
#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
#include "../../arch/arm/include/asm/unistd.h"
|
||||
/*
|
||||
* Use the __kuser_memory_barrier helper in the CPU helper page. See
|
||||
* arch/arm/kernel/entry-armv.S in the kernel source for details.
|
||||
*/
|
||||
#define rmb() asm volatile("mov r0, #0xffff0fff; mov lr, pc;" \
|
||||
"sub pc, r0, #95" ::: "r0", "lr", "cc", \
|
||||
"memory")
|
||||
#define cpu_relax() asm volatile("":::"memory")
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
|
|
@ -129,23 +129,16 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
int mmap_dispatch_perf_file(struct perf_header **pheader,
|
||||
const char *input_name,
|
||||
int force,
|
||||
int full_paths,
|
||||
int *cwdlen,
|
||||
char **cwd)
|
||||
int perf_session__process_events(struct perf_session *self,
|
||||
int full_paths, int *cwdlen, char **cwd)
|
||||
{
|
||||
int err;
|
||||
struct perf_header *header;
|
||||
unsigned long head, shift;
|
||||
unsigned long offset = 0;
|
||||
struct stat input_stat;
|
||||
size_t page_size;
|
||||
u64 sample_type;
|
||||
event_t *event;
|
||||
uint32_t size;
|
||||
int input;
|
||||
char *buf;
|
||||
|
||||
if (curr_handler == NULL) {
|
||||
|
@ -155,56 +148,19 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
|
|||
|
||||
page_size = getpagesize();
|
||||
|
||||
input = open(input_name, O_RDONLY);
|
||||
if (input < 0) {
|
||||
pr_err("Failed to open file: %s", input_name);
|
||||
if (!strcmp(input_name, "perf.data"))
|
||||
pr_err(" (try 'perf record' first)");
|
||||
pr_err("\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (fstat(input, &input_stat) < 0) {
|
||||
pr_err("failed to stat file");
|
||||
err = -errno;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
err = -EACCES;
|
||||
if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
|
||||
pr_err("file: %s not owned by current user or root\n",
|
||||
input_name);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (input_stat.st_size == 0) {
|
||||
pr_info("zero-sized file, nothing to do!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
header = perf_header__new();
|
||||
if (header == NULL)
|
||||
goto out_close;
|
||||
|
||||
err = perf_header__read(header, input);
|
||||
if (err < 0)
|
||||
goto out_delete;
|
||||
*pheader = header;
|
||||
head = header->data_offset;
|
||||
|
||||
sample_type = perf_header__sample_type(header);
|
||||
head = self->header.data_offset;
|
||||
sample_type = perf_header__sample_type(&self->header);
|
||||
|
||||
err = -EINVAL;
|
||||
if (curr_handler->sample_type_check &&
|
||||
curr_handler->sample_type_check(sample_type) < 0)
|
||||
goto out_delete;
|
||||
goto out_err;
|
||||
|
||||
if (!full_paths) {
|
||||
if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
|
||||
pr_err("failed to get the current directory\n");
|
||||
err = -errno;
|
||||
goto out_delete;
|
||||
goto out_err;
|
||||
}
|
||||
*cwd = __cwd;
|
||||
*cwdlen = strlen(*cwd);
|
||||
|
@ -219,11 +175,11 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
|
|||
|
||||
remap:
|
||||
buf = mmap(NULL, page_size * mmap_window, PROT_READ,
|
||||
MAP_SHARED, input, offset);
|
||||
MAP_SHARED, self->fd, offset);
|
||||
if (buf == MAP_FAILED) {
|
||||
pr_err("failed to mmap file\n");
|
||||
err = -errno;
|
||||
goto out_delete;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
more:
|
||||
|
@ -273,19 +229,14 @@ more:
|
|||
|
||||
head += size;
|
||||
|
||||
if (offset + head >= header->data_offset + header->data_size)
|
||||
if (offset + head >= self->header.data_offset + self->header.data_size)
|
||||
goto done;
|
||||
|
||||
if (offset + head < (unsigned long)input_stat.st_size)
|
||||
if (offset + head < self->size)
|
||||
goto more;
|
||||
|
||||
done:
|
||||
err = 0;
|
||||
out_close:
|
||||
close(input);
|
||||
|
||||
out_err:
|
||||
return err;
|
||||
out_delete:
|
||||
perf_header__delete(header);
|
||||
goto out_close;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "event.h"
|
||||
#include "header.h"
|
||||
#include "session.h"
|
||||
|
||||
typedef int (*event_type_handler_t)(event_t *);
|
||||
|
||||
|
@ -21,12 +22,8 @@ struct perf_file_handler {
|
|||
};
|
||||
|
||||
void register_perf_file_handler(struct perf_file_handler *handler);
|
||||
int mmap_dispatch_perf_file(struct perf_header **pheader,
|
||||
const char *input_name,
|
||||
int force,
|
||||
int full_paths,
|
||||
int *cwdlen,
|
||||
char **cwd);
|
||||
int perf_session__process_events(struct perf_session *self,
|
||||
int full_paths, int *cwdlen, char **cwd);
|
||||
int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -254,13 +254,14 @@ void thread__find_addr_location(struct thread *self, u8 cpumode,
|
|||
struct addr_location *al,
|
||||
symbol_filter_t filter)
|
||||
{
|
||||
struct thread *thread = al->thread = self;
|
||||
struct map_groups *mg = &self->mg;
|
||||
|
||||
al->thread = self;
|
||||
al->addr = addr;
|
||||
|
||||
if (cpumode & PERF_RECORD_MISC_KERNEL) {
|
||||
al->level = 'k';
|
||||
thread = kthread;
|
||||
mg = kmaps;
|
||||
} else if (cpumode & PERF_RECORD_MISC_USER)
|
||||
al->level = '.';
|
||||
else {
|
||||
|
@ -270,7 +271,7 @@ void thread__find_addr_location(struct thread *self, u8 cpumode,
|
|||
return;
|
||||
}
|
||||
try_again:
|
||||
al->map = thread__find_map(thread, type, al->addr);
|
||||
al->map = map_groups__find(mg, type, al->addr);
|
||||
if (al->map == NULL) {
|
||||
/*
|
||||
* If this is outside of all known maps, and is a negative
|
||||
|
@ -281,8 +282,8 @@ try_again:
|
|||
* "[vdso]" dso, but for now lets use the old trick of looking
|
||||
* in the whole kernel symbol list.
|
||||
*/
|
||||
if ((long long)al->addr < 0 && thread != kthread) {
|
||||
thread = kthread;
|
||||
if ((long long)al->addr < 0 && mg != kmaps) {
|
||||
mg = kmaps;
|
||||
goto try_again;
|
||||
}
|
||||
al->sym = NULL;
|
||||
|
|
|
@ -103,10 +103,11 @@ void event__print_totals(void);
|
|||
|
||||
enum map_type {
|
||||
MAP__FUNCTION = 0,
|
||||
|
||||
MAP__NR_TYPES,
|
||||
MAP__VARIABLE,
|
||||
};
|
||||
|
||||
#define MAP__NR_TYPES (MAP__VARIABLE + 1)
|
||||
|
||||
struct map {
|
||||
union {
|
||||
struct rb_node rb_node;
|
||||
|
@ -150,6 +151,8 @@ int map__overlap(struct map *l, struct map *r);
|
|||
size_t map__fprintf(struct map *self, FILE *fp);
|
||||
struct symbol *map__find_symbol(struct map *self, u64 addr,
|
||||
symbol_filter_t filter);
|
||||
struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
|
||||
symbol_filter_t filter);
|
||||
void map__fixup_start(struct map *self);
|
||||
void map__fixup_end(struct map *self);
|
||||
|
||||
|
|
|
@ -58,35 +58,19 @@ int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create new perf.data header:
|
||||
*/
|
||||
struct perf_header *perf_header__new(void)
|
||||
int perf_header__init(struct perf_header *self)
|
||||
{
|
||||
struct perf_header *self = zalloc(sizeof(*self));
|
||||
|
||||
if (self != NULL) {
|
||||
self->size = 1;
|
||||
self->attr = malloc(sizeof(void *));
|
||||
|
||||
if (self->attr == NULL) {
|
||||
free(self);
|
||||
self = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
self->size = 1;
|
||||
self->attr = malloc(sizeof(void *));
|
||||
return self->attr == NULL ? -ENOMEM : 0;
|
||||
}
|
||||
|
||||
void perf_header__delete(struct perf_header *self)
|
||||
void perf_header__exit(struct perf_header *self)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < self->attrs; ++i)
|
||||
perf_header_attr__delete(self->attr[i]);
|
||||
|
||||
perf_header_attr__delete(self->attr[i]);
|
||||
free(self->attr);
|
||||
free(self);
|
||||
}
|
||||
|
||||
int perf_header__add_attr(struct perf_header *self,
|
||||
|
|
|
@ -55,8 +55,8 @@ struct perf_header {
|
|||
DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
|
||||
};
|
||||
|
||||
struct perf_header *perf_header__new(void);
|
||||
void perf_header__delete(struct perf_header *self);
|
||||
int perf_header__init(struct perf_header *self);
|
||||
void perf_header__exit(struct perf_header *self);
|
||||
|
||||
int perf_header__read(struct perf_header *self, int fd);
|
||||
int perf_header__write(struct perf_header *self, int fd, bool at_exit);
|
||||
|
|
|
@ -104,43 +104,64 @@ void map__fixup_end(struct map *self)
|
|||
|
||||
#define DSO__DELETED "(deleted)"
|
||||
|
||||
static int map__load(struct map *self, symbol_filter_t filter)
|
||||
{
|
||||
const char *name = self->dso->long_name;
|
||||
int nr = dso__load(self->dso, self, filter);
|
||||
|
||||
if (nr < 0) {
|
||||
if (self->dso->has_build_id) {
|
||||
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
|
||||
|
||||
build_id__sprintf(self->dso->build_id,
|
||||
sizeof(self->dso->build_id),
|
||||
sbuild_id);
|
||||
pr_warning("%s with build id %s not found",
|
||||
name, sbuild_id);
|
||||
} else
|
||||
pr_warning("Failed to open %s", name);
|
||||
|
||||
pr_warning(", continuing without symbols\n");
|
||||
return -1;
|
||||
} else if (nr == 0) {
|
||||
const size_t len = strlen(name);
|
||||
const size_t real_len = len - sizeof(DSO__DELETED);
|
||||
|
||||
if (len > sizeof(DSO__DELETED) &&
|
||||
strcmp(name + real_len + 1, DSO__DELETED) == 0) {
|
||||
pr_warning("%.*s was updated, restart the long "
|
||||
"running apps that use it!\n",
|
||||
(int)real_len, name);
|
||||
} else {
|
||||
pr_warning("no symbols found in %s, maybe install "
|
||||
"a debug package?\n", name);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct symbol *map__find_symbol(struct map *self, u64 addr,
|
||||
symbol_filter_t filter)
|
||||
{
|
||||
if (!dso__loaded(self->dso, self->type)) {
|
||||
int nr = dso__load(self->dso, self, filter);
|
||||
if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
|
||||
return NULL;
|
||||
|
||||
if (nr < 0) {
|
||||
if (self->dso->has_build_id) {
|
||||
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
|
||||
return dso__find_symbol(self->dso, self->type, addr);
|
||||
}
|
||||
|
||||
build_id__sprintf(self->dso->build_id,
|
||||
sizeof(self->dso->build_id),
|
||||
sbuild_id);
|
||||
pr_warning("%s with build id %s not found",
|
||||
self->dso->long_name, sbuild_id);
|
||||
} else
|
||||
pr_warning("Failed to open %s",
|
||||
self->dso->long_name);
|
||||
pr_warning(", continuing without symbols\n");
|
||||
return NULL;
|
||||
} else if (nr == 0) {
|
||||
const char *name = self->dso->long_name;
|
||||
const size_t len = strlen(name);
|
||||
const size_t real_len = len - sizeof(DSO__DELETED);
|
||||
struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
|
||||
symbol_filter_t filter)
|
||||
{
|
||||
if (!dso__loaded(self->dso, self->type) && map__load(self, filter) < 0)
|
||||
return NULL;
|
||||
|
||||
if (len > sizeof(DSO__DELETED) &&
|
||||
strcmp(name + real_len + 1, DSO__DELETED) == 0) {
|
||||
pr_warning("%.*s was updated, restart the long running apps that use it!\n",
|
||||
(int)real_len, name);
|
||||
} else {
|
||||
pr_warning("no symbols found in %s, maybe install a debug package?\n", name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (!dso__sorted_by_name(self->dso, self->type))
|
||||
dso__sort_by_name(self->dso, self->type);
|
||||
|
||||
return self->dso->find_symbol(self->dso, self->type, addr);
|
||||
return dso__find_symbol_by_name(self->dso, self->type, name);
|
||||
}
|
||||
|
||||
struct map *map__clone(struct map *self)
|
||||
|
|
80
tools/perf/util/session.c
Normal file
80
tools/perf/util/session.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
#include <linux/kernel.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "session.h"
|
||||
#include "util.h"
|
||||
|
||||
static int perf_session__open(struct perf_session *self, bool force)
|
||||
{
|
||||
struct stat input_stat;
|
||||
|
||||
self->fd = open(self->filename, O_RDONLY);
|
||||
if (self->fd < 0) {
|
||||
pr_err("failed to open file: %s", self->filename);
|
||||
if (!strcmp(self->filename, "perf.data"))
|
||||
pr_err(" (try 'perf record' first)");
|
||||
pr_err("\n");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (fstat(self->fd, &input_stat) < 0)
|
||||
goto out_close;
|
||||
|
||||
if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
|
||||
pr_err("file %s not owned by current user or root\n",
|
||||
self->filename);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||