Commit 00f1762d authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

  * Backport libtraceevent plugin support from trace-cmd repository, with
    plugins for jbd2, hrtimer, kmem, kvm, mac80211, sched_switch, function,
    xen, scsi, cfg80211. From Jiri Olsa.

  * Retain bfd reference to lookup source line numbers, greatly optimizing, among
    other use cases, 'perf report -s srcline', from Adrian Hunter.

  * Do not disable source line lookup just because of one failure, from Adrian Hunter.

  * Fix random fd closing with no libelf, from Adrian Hunter.

  * Do not call perf_event__preprocess_sample() twice in 'perf script',
    from Adrian Hunter.

  * Several 'perf kvm' man page corrections, from Dongsheng Yang.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 89e3bbd5 6d65894b
......@@ -43,6 +43,30 @@ man_dir_SQ = '$(subst ','\'',$(man_dir))'
export man_dir man_dir_SQ INSTALL
export DESTDIR DESTDIR_SQ
set_plugin_dir := 1
# Set plugin_dir to preffered global plugin location
# If we install under $HOME directory we go under
# $(HOME)/.traceevent/plugins
#
# We dont set PLUGIN_DIR in case we install under $HOME
# directory, because by default the code looks under:
# $(HOME)/.traceevent/plugins by default.
#
ifeq ($(plugin_dir),)
ifeq ($(prefix),$(HOME))
override plugin_dir = $(HOME)/.traceevent/plugins
set_plugin_dir := 0
else
override plugin_dir = $(prefix)/lib/traceevent/plugins
endif
endif
ifeq ($(set_plugin_dir),1)
PLUGIN_DIR = -DPLUGIN_DIR="$(DESTDIR)/$(plugin_dir)"
PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))'
endif
# copy a bit from Linux kbuild
ifeq ("$(origin V)", "command line")
......@@ -96,6 +120,7 @@ export prefix bindir src obj
# Shell quotes
bindir_SQ = $(subst ','\'',$(bindir))
bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
plugin_dir_SQ = $(subst ','\'',$(plugin_dir))
LIB_FILE = libtraceevent.a libtraceevent.so
......@@ -138,10 +163,10 @@ else
print_app_build = echo ' BUILD '$(OBJ);
print_fpic_compile = echo ' CC FPIC '$(OBJ);
print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ);
print_plugin_build = echo ' BUILD PLUGIN '$(OBJ);
print_plugin_obj_compile = echo ' CC FPIC '$(OBJ);
print_plugin_build = echo ' BUILD PLUGIN '$(OBJ);
print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ);
print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2';
print_install = echo ' INSTALL '$1;
endif
do_fpic_compile = \
......@@ -180,12 +205,29 @@ $(obj)/%.o: $(src)/%.c
%.o: $(src)/%.c
$(Q)$(call do_compile)
PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
PEVENT_LIB_OBJS = event-parse.o
PEVENT_LIB_OBJS += event-plugin.o
PEVENT_LIB_OBJS += trace-seq.o
PEVENT_LIB_OBJS += parse-filter.o
PEVENT_LIB_OBJS += parse-utils.o
PEVENT_LIB_OBJS += kbuffer-parse.o
ALL_OBJS = $(PEVENT_LIB_OBJS)
PLUGIN_OBJS = plugin_jbd2.o
PLUGIN_OBJS += plugin_hrtimer.o
PLUGIN_OBJS += plugin_kmem.o
PLUGIN_OBJS += plugin_kvm.o
PLUGIN_OBJS += plugin_mac80211.o
PLUGIN_OBJS += plugin_sched_switch.o
PLUGIN_OBJS += plugin_function.o
PLUGIN_OBJS += plugin_xen.o
PLUGIN_OBJS += plugin_scsi.o
PLUGIN_OBJS += plugin_cfg80211.o
PLUGINS := $(PLUGIN_OBJS:.o=.so)
CMD_TARGETS = $(LIB_FILE)
ALL_OBJS = $(PEVENT_LIB_OBJS) $(PLUGIN_OBJS)
CMD_TARGETS = $(LIB_FILE) $(PLUGINS)
TARGETS = $(CMD_TARGETS)
......@@ -200,9 +242,17 @@ libtraceevent.so: $(PEVENT_LIB_OBJS)
libtraceevent.a: $(PEVENT_LIB_OBJS)
$(Q)$(do_build_static_lib)
plugins: $(PLUGINS)
$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS
$(Q)$(do_fpic_compile)
$(PLUGIN_OBJS): %.o : $(src)/%.c
$(Q)$(do_compile_plugin_obj)
$(PLUGINS): %.so: %.o
$(Q)$(do_plugin_build)
define make_version.h
(echo '/* This file is automatically generated. Do not modify. */'; \
echo \#define VERSION_CODE $(shell \
......@@ -290,9 +340,16 @@ define do_install
$(INSTALL) $1 '$(DESTDIR_SQ)$2'
endef
install_lib: all_cmd
install_lib: all_cmd install_plugins
$(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
PLUGINS_INSTALL = $(subst .so,.install,$(PLUGINS))
$(PLUGINS_INSTALL): %.install : %.so force
$(Q)$(call do_install,$<,$(plugin_dir_SQ))
install_plugins: $(PLUGINS_INSTALL)
install: install_lib
clean:
......
......@@ -5121,8 +5121,38 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp,
return ret;
}
static enum pevent_errno
__pevent_parse_event(struct pevent *pevent,
struct event_format **eventp,
const char *buf, unsigned long size,
const char *sys)
{
int ret = __pevent_parse_format(eventp, pevent, buf, size, sys);
struct event_format *event = *eventp;
if (event == NULL)
return ret;
if (pevent && add_event(pevent, event)) {
ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
goto event_add_failed;
}
#define PRINT_ARGS 0
if (PRINT_ARGS && event->print_fmt.args)
print_args(event->print_fmt.args);
return 0;
event_add_failed:
pevent_free_format(event);
return ret;
}
/**
* pevent_parse_format - parse the event format
* @pevent: the handle to the pevent
* @eventp: returned format
* @buf: the buffer storing the event format string
* @size: the size of @buf
* @sys: the system the event belongs to
......@@ -5134,10 +5164,12 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp,
*
* /sys/kernel/debug/tracing/events/.../.../format
*/
enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf,
enum pevent_errno pevent_parse_format(struct pevent *pevent,
struct event_format **eventp,
const char *buf,
unsigned long size, const char *sys)
{
return __pevent_parse_format(eventp, NULL, buf, size, sys);
return __pevent_parse_event(pevent, eventp, buf, size, sys);
}
/**
......@@ -5158,25 +5190,7 @@ enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
unsigned long size, const char *sys)
{
struct event_format *event = NULL;
int ret = __pevent_parse_format(&event, pevent, buf, size, sys);
if (event == NULL)
return ret;
if (add_event(pevent, event)) {
ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
goto event_add_failed;
}
#define PRINT_ARGS 0
if (PRINT_ARGS && event->print_fmt.args)
print_args(event->print_fmt.args);
return 0;
event_add_failed:
pevent_free_format(event);
return ret;
return __pevent_parse_event(pevent, &event, buf, size, sys);
}
#undef _PE
......
......@@ -23,6 +23,7 @@
#include <stdbool.h>
#include <stdarg.h>
#include <regex.h>
#include <string.h>
#ifndef __maybe_unused
#define __maybe_unused __attribute__((unused))
......@@ -377,6 +378,11 @@ enum pevent_errno {
};
#undef _PE
struct plugin_list;
struct plugin_list *traceevent_load_plugins(struct pevent *pevent);
void traceevent_unload_plugins(struct plugin_list *plugin_list);
struct cmdline;
struct cmdline_list;
struct func_map;
......@@ -522,6 +528,15 @@ __data2host8(struct pevent *pevent, unsigned long long data)
__data2host8(pevent, __val); \
})
static inline int traceevent_host_bigendian(void)
{
unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
unsigned int val;
memcpy(&val, str, 4);
return val == 0x01020304;
}
/* taken from kernel/trace/trace.h */
enum trace_flag_type {
TRACE_FLAG_IRQS_OFF = 0x01,
......@@ -547,7 +562,9 @@ int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long siz
enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
unsigned long size, const char *sys);
enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf,
enum pevent_errno pevent_parse_format(struct pevent *pevent,
struct event_format **eventp,
const char *buf,
unsigned long size, const char *sys);
void pevent_free_format(struct event_format *event);
......
/*
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <string.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include "event-parse.h"
#include "event-utils.h"
#define LOCAL_PLUGIN_DIR ".traceevent/plugins"
struct plugin_list {
struct plugin_list *next;
char *name;
void *handle;
};
static void
load_plugin(struct pevent *pevent, const char *path,
const char *file, void *data)
{
struct plugin_list **plugin_list = data;
pevent_plugin_load_func func;
struct plugin_list *list;
const char *alias;
char *plugin;
void *handle;
plugin = malloc(strlen(path) + strlen(file) + 2);
if (!plugin) {
warning("could not allocate plugin memory\n");
return;
}
strcpy(plugin, path);
strcat(plugin, "/");
strcat(plugin, file);
handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
warning("could not load plugin '%s'\n%s\n",
plugin, dlerror());
goto out_free;
}
alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME);
if (!alias)
alias = file;
func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME);
if (!func) {
warning("could not find func '%s' in plugin '%s'\n%s\n",
PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror());
goto out_free;
}
list = malloc(sizeof(*list));
if (!list) {
warning("could not allocate plugin memory\n");
goto out_free;
}
list->next = *plugin_list;
list->handle = handle;
list->name = plugin;
*plugin_list = list;
pr_stat("registering plugin: %s", plugin);
func(pevent);
return;
out_free:
free(plugin);
}
static void
load_plugins_dir(struct pevent *pevent, const char *suffix,
const char *path,
void (*load_plugin)(struct pevent *pevent,
const char *path,
const char *name,
void *data),
void *data)
{
struct dirent *dent;
struct stat st;
DIR *dir;
int ret;
ret = stat(path, &st);
if (ret < 0)
return;
if (!S_ISDIR(st.st_mode))
return;
dir = opendir(path);
if (!dir)
return;
while ((dent = readdir(dir))) {
const char *name = dent->d_name;
if (strcmp(name, ".") == 0 ||
strcmp(name, "..") == 0)
continue;
/* Only load plugins that end in suffix */
if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0)
continue;
load_plugin(pevent, path, name, data);
}
closedir(dir);
}
static void
load_plugins(struct pevent *pevent, const char *suffix,
void (*load_plugin)(struct pevent *pevent,
const char *path,
const char *name,
void *data),
void *data)
{
char *home;
char *path;
char *envdir;
/*
* If a system plugin directory was defined,
* check that first.
*/
#ifdef PLUGIN_DIR
load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data);
#endif
/*
* Next let the environment-set plugin directory
* override the system defaults.
*/
envdir = getenv("TRACEEVENT_PLUGIN_DIR");
if (envdir)
load_plugins_dir(pevent, suffix, envdir, load_plugin, data);
/*
* Now let the home directory override the environment
* or system defaults.
*/
home = getenv("HOME");
if (!home)
return;
path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2);
if (!path) {
warning("could not allocate plugin memory\n");
return;
}
strcpy(path, home);
strcat(path, "/");
strcat(path, LOCAL_PLUGIN_DIR);
load_plugins_dir(pevent, suffix, path, load_plugin, data);
free(path);
}
struct plugin_list*
traceevent_load_plugins(struct pevent *pevent)
{
struct plugin_list *list = NULL;
load_plugins(pevent, ".so", load_plugin, &list);
return list;
}
void
traceevent_unload_plugins(struct plugin_list *plugin_list)
{
pevent_plugin_unload_func func;
struct plugin_list *list;
while (plugin_list) {
list = plugin_list;
plugin_list = list->next;
func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME);
if (func)
func();
dlclose(list->handle);
free(list->name);
free(list);
}
}
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <endian.h>
#include "event-parse.h"
static unsigned long long
process___le16_to_cpup(struct trace_seq *s,
unsigned long long *args)
{
uint16_t *val = (uint16_t *) args[0];
return val ? (long long) le16toh(*val) : 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
{
pevent_register_print_function(pevent,
process___le16_to_cpup,
PEVENT_FUNC_ARG_INT,
"__le16_to_cpup",
PEVENT_FUNC_ARG_PTR,
PEVENT_FUNC_ARG_VOID);
return 0;
}
/*
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "event-parse.h"
#include "event-utils.h"
static struct func_stack {
int size;
char **stack;
} *fstack;
static int cpus = -1;
#define STK_BLK 10
static void add_child(struct func_stack *stack, const char *child, int pos)
{
int i;
if (!child)
return;
if (pos < stack->size)
free(stack->stack[pos]);
else {
char **ptr;
ptr = realloc(stack->stack, sizeof(char *) *
(stack->size + STK_BLK));
if (!ptr) {
warning("could not allocate plugin memory\n");
return;
}
stack->stack = ptr;
for (i = stack->size; i < stack->size + STK_BLK; i++)
stack->stack[i] = NULL;
stack->size += STK_BLK;
}
stack->stack[pos] = strdup(child);
}
static int add_and_get_index(const char *parent, const char *child, int cpu)
{
int i;
if (cpu < 0)
return 0;
if (cpu > cpus) {
struct func_stack *ptr;
ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1));
if (!ptr) {
warning("could not allocate plugin memory\n");
return 0;
}
fstack = ptr;
/* Account for holes in the cpu count */
for (i = cpus + 1; i <= cpu; i++)
memset(&fstack[i], 0, sizeof(fstack[i]));
cpus = cpu;
}
for (i = 0; i < fstack[cpu].size && fstack[cpu].stack[i]; i++) {
if (strcmp(parent, fstack[cpu].stack[i]) == 0) {
add_child(&fstack[cpu], child, i+1);
return i;
}
}
/* Not found */
add_child(&fstack[cpu], parent, 0);
add_child(&fstack[cpu], child, 1);
return 0;
}
static int function_handler(struct trace_seq *s, struct pevent_record *record,
struct event_format *event, void *context)
{
struct pevent *pevent = event->pevent;
unsigned long long function;
unsigned long long pfunction;
const char *func;
const char *parent;
int index;
if (pevent_get_field_val(s, event, "ip", record, &function, 1))
return trace_seq_putc(s, '!');
func = pevent_find_function(pevent, function);
if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
return trace_seq_putc(s, '!');
parent = pevent_find_function(pevent, pfunction);
index = add_and_get_index(parent, func, record->cpu);
trace_seq_printf(s, "%*s", index*3, "");
if (func)
trace_seq_printf(s, "%s", func);
else
trace_seq_printf(s, "0x%llx", function);
trace_seq_printf(s, " <-- ");
if (parent)
trace_seq_printf(s, "%s", parent);
else
trace_seq_printf(s, "0x%llx", pfunction);
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
{
pevent_register_event_handler(pevent, -1, "ftrace", "function",
function_handler, NULL);
return 0;
}
void PEVENT_PLUGIN_UNLOADER(void)
{
int i, x;
for (i = 0; i <= cpus; i++) {
for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++)
free(fstack[i].stack[x]);
free(fstack[i].stack);
}
free(fstack);
fstack = NULL;
cpus = -1;
}
/*
* Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
* Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "event-parse.h"
static int timer_expire_handler(struct trace_seq *s,
struct pevent_record *record,
struct event_format *event, void *context)
{
trace_seq_printf(s, "hrtimer=");
if (pevent_print_num_field(s, "0x%llx", event, "timer",
record, 0) == -1)
pevent_print_num_field(s, "0x%llx", event, "hrtimer",
record, 1);
trace_seq_printf(s, " now=");
pevent_print_num_field(s, "%llu", event, "now", record, 1);
pevent_print_func_field(s, " function=%s", event, "function",
record, 0);
return 0;
}
static int timer_start_handler(struct trace_seq *s,
struct pevent_record *record,
struct event_format *event, void *context)
{
trace_seq_printf(s, "hrtimer=");
if (pevent_print_num_field(s, "0x%llx", event, "timer",
record, 0) == -1)
pevent_print_num_field(s, "0x%llx", event, "hrtimer",
record, 1);
pevent_print_func_field(s, " function=%s", event, "function",
record, 0);
trace_seq_printf(s, " expires=");
pevent_print_num_field(s, "%llu", event, "expires", record, 1);
trace_seq_printf(s, " softexpires=");
pevent_print_num_field(s, "%llu", event, "softexpires", record, 1);
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
{
pevent_register_event_handler(pevent, -1,
"timer", "hrtimer_expire_entry",
timer_expire_handler, NULL);
pevent_register_event_handler(pevent, -1, "timer", "hrtimer_start",
timer_start_handler, NULL);
return 0;
}
/*
* Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "event-parse.h"
#define MINORBITS 20
#define MINORMASK ((1U << MINORBITS) - 1)
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
static unsigned long long
process_jbd2_dev_to_name(struct trace_seq *s,
unsigned long long *args)
{
unsigned int dev = args[0];
trace_seq_printf(s, "%d:%d", MAJOR(dev), MINOR(dev));
return 0;
}
static unsigned long long
process_jiffies_to_msecs(struct trace_seq *s,
unsigned long long *args)
{
unsigned long long jiffies = args[0];
trace_seq_printf(s, "%lld", jiffies);
return jiffies;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
{
pevent_register_print_function(pevent,
process_jbd2_dev_to_name,
PEVENT_FUNC_ARG_STRING,
"jbd2_dev_to_name",
PEVENT_FUNC_ARG_INT,
PEVENT_FUNC_ARG_VOID);
pevent_register_print_function(pevent,
process_jiffies_to_msecs,
PEVENT_FUNC_ARG_LONG,
"jiffies_to_msecs",
PEVENT_FUNC_ARG_LONG,
PEVENT_FUNC_ARG_VOID);
return 0;
}
/*
* Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "event-parse.h"
static int call_site_handler(struct trace_seq *s, struct pevent_record *record,
struct event_format *event, void *context)
{
struct format_field *field;
unsigned long long val, addr;
void *data = record->data;
const char *func;
field = pevent_find_field(event, "call_site");
if (!field)
return 1;
if (pevent_read_number_field(field, data, &val))
return 1;
func = pevent_find_function(event->pevent, val);
if (!func)
return 1;
addr = pevent_find_function_address(event->pevent, val);
trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr));
return 1;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
{
pevent_register_event_handler(pevent, -1, "kmem", "kfree",
call_site_handler, NULL);
pevent_register_event_handler(pevent, -1, "kmem", "kmalloc",
call_site_handler, NULL);
pevent_register_event_handler(pevent, -1, "kmem", "kmalloc_node",
call_site_handler, NULL);
pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
call_site_handler, NULL);
pevent_register_event_handler(pevent, -1, "kmem",
"kmem_cache_alloc_node",
call_site_handler, NULL);
pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_free",
call_site_handler, NULL);
return 0;
}
This diff is collapsed.
/*
* Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "event-parse.h"
#define INDENT 65
static void print_string(struct trace_seq *s, struct event_format *event,
const char *name, const void *data)
{
struct format_field *f = pevent_find_field(event, name);
int offset;
int length;
if (!f) {
trace_seq_printf(s, "NOTFOUND:%s", name);
return;
}
offset = f->offset;
length = f->size;
if (!strncmp(f->type, "__data_loc", 10)) {
unsigned long long v;
if (pevent_read_number_field(f, data, &v)) {
trace_seq_printf(s, "invalid_data_loc");
return;
}
offset = v & 0xffff;
length = v >> 16;
}
trace_seq_printf(s, "%.*s", length, (char *)data + offset);
}
#define SF(fn) pevent_print_num_field(s, fn ":%d", event, fn, record, 0)
#define SFX(fn) pevent_print_num_field(s, fn ":%#x", event, fn, record, 0)
#define SP() trace_seq_putc(s, ' ')
static int drv_bss_info_changed(struct trace_seq *s,
struct pevent_record *record,
struct event_format *event, void *context)
{
void *data = record->data;
print_string(s, event, "wiphy_name", data);
trace_seq_printf(s, " vif:");
print_string(s, event, "vif_name", data);
pevent_print_num_field(s, "(%d)", event, "vif_type", record, 1);
trace_seq_printf(s, "\n%*s", INDENT, "");
SF("assoc"); SP();
SF("aid"); SP();
SF("cts"); SP();
SF("shortpre"); SP();
SF("shortslot"); SP();
SF("dtimper"); SP();
trace_seq_printf(s, "\n%*s", INDENT, "");
SF("bcnint"); SP();
SFX("assoc_cap"); SP();
SFX("basic_rates"); SP();
SF("enable_beacon");
trace_seq_printf(s, "\n%*s", INDENT, "");
SF("ht_operation_mode");
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
{
pevent_register_event_handler(pevent, -1, "mac80211",
"drv_bss_info_changed",
drv_bss_info_changed, NULL);
return 0;
}
/*
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "event-parse.h"
static void write_state(struct trace_seq *s, int val)
{
const char states[] = "SDTtZXxW";
int found = 0;
int i;
for (i = 0; i < (sizeof(states) - 1); i++) {
if (!(val & (1 << i)))
continue;
if (found)
trace_seq_putc(s, '|');
found = 1;
trace_seq_putc(s, states[i]);
}
if (!found)
trace_seq_putc(s, 'R');
}
static void write_and_save_comm(struct format_field *field,
struct pevent_record *record,
struct trace_seq *s, int pid)
{
const char *comm;
int len;
comm = (char *)(record->data + field->offset);
len = s->len;
trace_seq_printf(s, "%.*s",
field->size, comm);
/* make sure the comm has a \0 at the end. */
trace_seq_terminate(s);
comm = &s->buffer[len];
/* Help out the comm to ids. This will handle dups */
pevent_register_comm(field->event->pevent, comm, pid);
}
static int sched_wakeup_handler(struct trace_seq *s,
struct pevent_record *record,
struct event_format *event, void *context)
{
struct format_field *field;
unsigned long long val;
if (pevent_get_field_val(s, event, "pid", record, &val, 1))
return trace_seq_putc(s, '!');
field = pevent_find_any_field(event, "comm");
if (field) {
write_and_save_comm(field, record, s, val);
trace_seq_putc(s, ':');
}
trace_seq_printf(s, "%lld", val);
if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0)
trace_seq_printf(s, " [%lld]", val);
if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0)
trace_seq_printf(s, " success=%lld", val);
if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0)
trace_seq_printf(s, " CPU:%03llu", val);
return 0;
}
static int sched_switch_handler(struct trace_seq *s,
struct pevent_record *record,
struct event_format *event, void *context)
{
struct format_field *field;
unsigned long long val;
if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1))
return trace_seq_putc(s, '!');
field = pevent_find_any_field(event, "prev_comm");
if (field) {
write_and_save_comm(field, record, s, val);
trace_seq_putc(s, ':');
}
trace_seq_printf(s, "%lld ", val);
if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
trace_seq_printf(s, "[%lld] ", val);
if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0)
write_state(s, val);
trace_seq_puts(s, " ==> ");
if (pevent_get_field_val(s, event, "next_pid", record, &val, 1))
return trace_seq_putc(s, '!');
field = pevent_find_any_field(event, "next_comm");
if (field) {
write_and_save_comm(field, record, s, val);
trace_seq_putc(s, ':');
}
trace_seq_printf(s, "%lld", val);
if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
trace_seq_printf(s, " [%lld]", val);
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
{
pevent_register_event_handler(pevent, -1, "sched", "sched_switch",
sched_switch_handler, NULL);
pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup",
sched_wakeup_handler, NULL);
pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new",
sched_wakeup_handler, NULL);
return 0;
}
This diff is collapsed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "event-parse.h"
#define __HYPERVISOR_set_trap_table 0
#define __HYPERVISOR_mmu_update 1
#define __HYPERVISOR_set_gdt 2
#define __HYPERVISOR_stack_switch 3
#define __HYPERVISOR_set_callbacks 4
#define __HYPERVISOR_fpu_taskswitch 5
#define __HYPERVISOR_sched_op_compat 6
#define __HYPERVISOR_dom0_op 7
#define __HYPERVISOR_set_debugreg 8
#define __HYPERVISOR_get_debugreg 9
#define __HYPERVISOR_update_descriptor 10
#define __HYPERVISOR_memory_op 12
#define __HYPERVISOR_multicall 13
#define __HYPERVISOR_update_va_mapping 14
#define __HYPERVISOR_set_timer_op 15
#define __HYPERVISOR_event_channel_op_compat 16
#define __HYPERVISOR_xen_version 17
#define __HYPERVISOR_console_io 18
#define __HYPERVISOR_physdev_op_compat 19
#define __HYPERVISOR_grant_table_op 20
#define __HYPERVISOR_vm_assist 21
#define __HYPERVISOR_update_va_mapping_otherdomain 22
#define __HYPERVISOR_iret 23 /* x86 only */
#define __HYPERVISOR_vcpu_op 24
#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
#define __HYPERVISOR_mmuext_op 26
#define __HYPERVISOR_acm_op 27
#define __HYPERVISOR_nmi_op 28
#define __HYPERVISOR_sched_op 29
#define __HYPERVISOR_callback_op 30
#define __HYPERVISOR_xenoprof_op 31
#define __HYPERVISOR_event_channel_op 32
#define __HYPERVISOR_physdev_op 33
#define __HYPERVISOR_hvm_op 34
#define __HYPERVISOR_tmem_op 38
/* Architecture-specific hypercall definitions. */
#define __HYPERVISOR_arch_0 48
#define __HYPERVISOR_arch_1 49
#define __HYPERVISOR_arch_2 50
#define __HYPERVISOR_arch_3 51
#define __HYPERVISOR_arch_4 52
#define __HYPERVISOR_arch_5 53
#define __HYPERVISOR_arch_6 54
#define __HYPERVISOR_arch_7 55
#define N(x) [__HYPERVISOR_##x] = "("#x")"
static const char *xen_hypercall_names[] = {
N(set_trap_table),
N(mmu_update),
N(set_gdt),
N(stack_switch),
N(set_callbacks),
N(fpu_taskswitch),
N(sched_op_compat),
N(dom0_op),
N(set_debugreg),
N(get_debugreg),
N(update_descriptor),
N(memory_op),
N(multicall),
N(update_va_mapping),
N(set_timer_op),
N(event_channel_op_compat),
N(xen_version),
N(console_io),
N(physdev_op_compat),
N(grant_table_op),
N(vm_assist),
N(update_va_mapping_otherdomain),
N(iret),
N(vcpu_op),
N(set_segment_base),
N(mmuext_op),
N(acm_op),
N(nmi_op),
N(sched_op),
N(callback_op),
N(xenoprof_op),
N(event_channel_op),
N(physdev_op),
N(hvm_op),
/* Architecture-specific hypercall definitions. */
N(arch_0),
N(arch_1),
N(arch_2),
N(arch_3),
N(arch_4),
N(arch_5),
N(arch_6),
N(arch_7),
};
#undef N
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static const char *xen_hypercall_name(unsigned op)
{
if (op < ARRAY_SIZE(xen_hypercall_names) &&
xen_hypercall_names[op] != NULL)
return xen_hypercall_names[op];
return "";
}
unsigned long long process_xen_hypercall_name(struct trace_seq *s,
unsigned long long *args)
{
unsigned int op = args[0];
trace_seq_printf(s, "%s", xen_hypercall_name(op));
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
{
pevent_register_print_function(pevent,
process_xen_hypercall_name,
PEVENT_FUNC_ARG_STRING,
"xen_hypercall_name",
PEVENT_FUNC_ARG_INT,
PEVENT_FUNC_ARG_VOID);
return 0;
}
......@@ -24,10 +24,17 @@ There are a couple of variants of perf kvm:
of an arbitrary workload.
'perf kvm record <command>' to record the performance counter profile
of an arbitrary workload and save it into a perf data file. If both
--host and --guest are input, the perf data file name is perf.data.kvm.
If there is no --host but --guest, the file name is perf.data.guest.
If there is no --guest but --host, the file name is perf.data.host.
of an arbitrary workload and save it into a perf data file. We set the
default behavior of perf kvm as --guest, so if neither --host nor --guest
is input, the perf data file name is perf.data.guest. If --host is input,
the perf data file name is perf.data.kvm. If you want to record data into
perf.data.host, please input --host --no-guest. The behaviors are shown as
following:
Default('') -> perf.data.guest
--host -> perf.data.kvm
--guest -> perf.data.guest
--host --guest -> perf.data.kvm
--host --no-guest -> perf.data.host
'perf kvm report' to display the performance counter profile information
recorded via perf kvm record.
......@@ -37,7 +44,9 @@ There are a couple of variants of perf kvm:
'perf kvm buildid-list' to display the buildids found in a perf data file,
so that other tools can be used to fetch packages with matching symbol tables
for use by perf report.
for use by perf report. As buildid is read from /sys/kernel/notes in os, then
if you want to list the buildid for guest, please make sure your perf data file
was captured with --guestmount in perf kvm record.
'perf kvm stat <command>' to run a command and gather performance counter
statistics.
......@@ -58,14 +67,14 @@ There are a couple of variants of perf kvm:
OPTIONS
-------
-i::
--input=::
--input=<path>::
Input file name.
-o::
--output::
--output=<path>::
Output file name.
--host=::
--host::
Collect host side performance profile.
--guest=::
--guest::
Collect guest side performance profile.
--guestmount=<path>::
Guest os root file system mount directory. Users mounts guest os
......
......@@ -105,7 +105,7 @@ ifeq ($(config),1)
include config/Makefile
endif
export prefix bindir sharedir sysconfdir
export prefix bindir sharedir sysconfdir DESTDIR
# sparse is architecture-neutral, which means that we need to tell it
# explicitly what architecture to check for. Fix this up for yours..
......@@ -353,6 +353,7 @@ LIB_OBJS += $(OUTPUT)util/pmu-bison.o
LIB_OBJS += $(OUTPUT)util/trace-event-read.o
LIB_OBJS += $(OUTPUT)util/trace-event-info.o
LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
LIB_OBJS += $(OUTPUT)util/trace-event.o
LIB_OBJS += $(OUTPUT)util/svghelper.o
LIB_OBJS += $(OUTPUT)util/sort.o
LIB_OBJS += $(OUTPUT)util/hist.o
......@@ -710,13 +711,20 @@ $(LIB_FILE): $(LIB_OBJS)
# libtraceevent.a
TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch])
$(LIBTRACEEVENT): $(TE_SOURCES)
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a
LIBTRACEEVENT_FLAGS = $(QUIET_SUBDIR1) O=$(OUTPUT)
LIBTRACEEVENT_FLAGS += CFLAGS="-g -Wall $(EXTRA_CFLAGS)"
LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ)
$(LIBTRACEEVENT): $(TE_SOURCES) $(OUTPUT)PERF-CFLAGS
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) libtraceevent.a plugins
$(LIBTRACEEVENT)-clean:
$(call QUIET_CLEAN, libtraceevent)
@$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
install-traceevent-plugins:
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins
LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch])
# if subdir is set, we've been called from above so target has been built
......@@ -785,7 +793,7 @@ cscope:
### Detect prefix changes
TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
$(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
$(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):$(plugindir_SQ)
$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
@FLAGS='$(TRACK_CFLAGS)'; \
......@@ -849,7 +857,7 @@ endif
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
$(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
install: install-bin try-install-man
install: install-bin try-install-man install-traceevent-plugins
install-python_ext:
$(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
......
......@@ -414,7 +414,8 @@ static void print_sample_bts(union perf_event *event,
struct perf_sample *sample,
struct perf_evsel *evsel,
struct machine *machine,
struct thread *thread)
struct thread *thread,
struct addr_location *al)
{
struct perf_event_attr *attr = &evsel->attr;
......@@ -424,7 +425,7 @@ static void print_sample_bts(union perf_event *event,
printf(" ");
else
printf("\n");
perf_evsel__print_ip(evsel, event, sample, machine,
perf_evsel__print_ip(evsel, sample, machine, al,
output[attr->type].print_ip_opts,
PERF_MAX_STACK_DEPTH);
}
......@@ -443,7 +444,7 @@ static void print_sample_bts(union perf_event *event,
static void process_event(union perf_event *event, struct perf_sample *sample,
struct perf_evsel *evsel, struct machine *machine,
struct thread *thread,
struct addr_location *al __maybe_unused)
struct addr_location *al)
{
struct perf_event_attr *attr = &evsel->attr;
......@@ -458,7 +459,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
}
if (is_bts_event(attr)) {
print_sample_bts(event, sample, evsel, machine, thread);
print_sample_bts(event, sample, evsel, machine, thread, al);
return;
}
......@@ -474,7 +475,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
else
printf("\n");
perf_evsel__print_ip(evsel, event, sample, machine,
perf_evsel__print_ip(evsel, sample, machine, al,
output[attr->type].print_ip_opts,
PERF_MAX_STACK_DEPTH);
}
......@@ -1785,7 +1786,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
return -1;
}
err = scripting_ops->generate_script(session->pevent,
err = scripting_ops->generate_script(session->tevent.pevent,
"perf-script");
goto out;
}
......
......@@ -11,6 +11,7 @@
#include "util/intlist.h"
#include "util/thread_map.h"
#include "util/stat.h"
#include "trace-event.h"
#include <libaudit.h>
#include <stdlib.h>
......@@ -1430,11 +1431,11 @@ static int trace__read_syscall_info(struct trace *trace, int id)
sc->fmt = syscall_fmt__find(sc->name);
snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
sc->tp_format = event_format__new("syscalls", tp_name);
sc->tp_format = trace_event__tp_format("syscalls", tp_name);
if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
sc->tp_format = event_format__new("syscalls", tp_name);
sc->tp_format = trace_event__tp_format("syscalls", tp_name);
}
if (sc->tp_format == NULL)
......
......@@ -141,7 +141,6 @@ CORE_FEATURE_TESTS = \
libslang \
libunwind \
on-exit \
stackprotector \
stackprotector-all \
timerfd
......@@ -209,10 +208,6 @@ ifeq ($(feature-stackprotector-all), 1)
CFLAGS += -fstack-protector-all
endif
ifeq ($(feature-stackprotector), 1)
CFLAGS += -Wstack-protector
endif
ifeq ($(DEBUG),0)
ifeq ($(feature-fortify-source), 1)
CFLAGS += -D_FORTIFY_SOURCE=2
......@@ -598,3 +593,11 @@ else
perfexec_instdir = $(prefix)/$(perfexecdir)
endif
perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
# If we install to $(HOME) we keep the traceevent default:
# $(HOME)/.traceevent/plugins
# Otherwise we install plugins into the global $(libdir).
ifdef DESTDIR
plugindir=$(libdir)/traceevent/plugins
plugindir_SQ= $(subst ','\'',$(prefix)/$(plugindir))
endif
......@@ -26,7 +26,6 @@ FILES= \
test-libunwind-debug-frame \
test-on-exit \
test-stackprotector-all \
test-stackprotector \
test-timerfd
CC := $(CC) -MD
......@@ -38,7 +37,7 @@ BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c
###############################
test-all:
$(BUILD) -Werror -fstack-protector -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
$(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
test-hello:
$(BUILD)
......@@ -46,9 +45,6 @@ test-hello:
test-stackprotector-all:
$(BUILD) -Werror -fstack-protector-all
test-stackprotector:
$(BUILD) -Werror -fstack-protector -Wstack-protector
test-fortify-source:
$(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2
......
#include <stdio.h>
int main(void)
{
return puts("hi");
}
......@@ -16,13 +16,11 @@
int verbose;
bool dump_trace = false, quiet = false;
int eprintf(int level, const char *fmt, ...)
static int _eprintf(int level, const char *fmt, va_list args)
{
va_list args;
int ret = 0;
if (verbose >= level) {
va_start(args, fmt);
if (use_browser >= 1)
ui_helpline__vshow(fmt, args);
else
......@@ -33,6 +31,32 @@ int eprintf(int level, const char *fmt, ...)
return ret;
}
int eprintf(int level, const char *fmt, ...)
{
va_list args;
int ret;
va_start(args, fmt);
ret = _eprintf(level, fmt, args);
va_end(args);
return ret;
}
/*
* Overloading libtraceevent standard info print
* function, display with -v in perf.
*/
void pr_stat(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
_eprintf(1, fmt, args);
va_end(args);
eprintf(1, "\n");
}
int dump_printf(const char *fmt, ...)
{
va_list args;
......
......@@ -17,4 +17,6 @@ void trace_event(union perf_event *event);
int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
void pr_stat(const char *fmt, ...);
#endif /* __PERF_DEBUG_H */
......@@ -451,6 +451,7 @@ struct dso *dso__new(const char *name)
dso->sorted_by_name = 0;
dso->has_build_id = 0;
dso->has_srcline = 1;
dso->a2l_fails = 1;
dso->kernel = DSO_TYPE_USER;
dso->needs_swap = DSO_SWAP__UNSET;
INIT_LIST_HEAD(&dso->node);
......@@ -469,6 +470,8 @@ void dso__delete(struct dso *dso)
if (dso->lname_alloc)
free(dso->long_name);
dso_cache__free(&dso->cache);
dso__free_a2l(dso);
free(dso->symsrc_filename);
free(dso);
}
......
......@@ -77,6 +77,9 @@ struct dso {
struct rb_root symbols[MAP__NR_TYPES];
struct rb_root symbol_names[MAP__NR_TYPES];
struct rb_root cache;
void *a2l;
char *symsrc_filename;
unsigned int a2l_fails;
enum dso_kernel_type kernel;
enum dso_swap_type needs_swap;
enum dso_binary_type symtab_type;
......@@ -166,4 +169,6 @@ static inline bool dso__is_kcore(struct dso *dso)
dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE;
}
void dso__free_a2l(struct dso *dso);
#endif /* __PERF_DSO */
......@@ -819,13 +819,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
if (evlist->threads == NULL)
return -1;
if (target->default_per_cpu)
evlist->cpus = target->per_thread ?
cpu_map__dummy_new() :
cpu_map__new(target->cpu_list);
else if (target__has_task(target))
evlist->cpus = cpu_map__dummy_new();
else if (!target__has_cpu(target) && !target->uses_mmap)
if (target__uses_dummy_map(target))
evlist->cpus = cpu_map__dummy_new();
else
evlist->cpus = cpu_map__new(target->cpu_list);
......
......@@ -23,6 +23,7 @@
#include "target.h"
#include "perf_regs.h"
#include "debug.h"
#include "trace-event.h"
static struct {
bool sample_id_all;
......@@ -180,47 +181,6 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
return evsel;
}
struct event_format *event_format__new(const char *sys, const char *name)
{
int fd, n;
char *filename;
void *bf = NULL, *nbf;
size_t size = 0, alloc_size = 0;
struct event_format *format = NULL;
if (asprintf(&filename, "%s/%s/%s/format", tracing_events_path, sys, name) < 0)
goto out;
fd = open(filename, O_RDONLY);
if (fd < 0)
goto out_free_filename;
do {
if (size == alloc_size) {
alloc_size += BUFSIZ;
nbf = realloc(bf, alloc_size);
if (nbf == NULL)
goto out_free_bf;
bf = nbf;
}
n = read(fd, bf + size, alloc_size - size);
if (n < 0)
goto out_free_bf;
size += n;
} while (n > 0);
pevent_parse_format(&format, bf, size, sys);
out_free_bf:
free(bf);
close(fd);
out_free_filename:
free(filename);
out:
return format;
}
struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx)
{
struct perf_evsel *evsel = zalloc(sizeof(*evsel));
......@@ -235,7 +195,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int
if (asprintf(&evsel->name, "%s:%s", sys, name) < 0)
goto out_free;
evsel->tp_format = event_format__new(sys, name);
evsel->tp_format = trace_event__tp_format(sys, name);
if (evsel->tp_format == NULL)
goto out_free;
......
......@@ -2834,11 +2834,11 @@ int perf_session__read_header(struct perf_session *session)
symbol_conf.nr_events = nr_attrs;
perf_header__process_sections(header, fd, &session->pevent,
perf_header__process_sections(header, fd, &session->tevent,
perf_file_section__process);
if (perf_evlist__prepare_tracepoint_events(session->evlist,
session->pevent))
session->tevent.pevent))
goto out_delete_evlist;
return 0;
......@@ -3003,7 +3003,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
lseek(fd, offset + sizeof(struct tracing_data_event),
SEEK_SET);
size_read = trace_report(fd, &session->pevent,
size_read = trace_report(fd, &session->tevent,
session->repipe);
padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
......@@ -3025,7 +3025,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
}
perf_evlist__prepare_tracepoint_events(session->evlist,
session->pevent);
session->tevent.pevent);
return size_read + padding;
}
......
......@@ -502,15 +502,11 @@ static u64 machine__get_kernel_start_addr(struct machine *machine)
char path[PATH_MAX];
struct process_args args;
if (machine__is_host(machine)) {
filename = "/proc/kallsyms";
} else {
if (machine__is_default_guest(machine))
filename = (char *)symbol_conf.default_guest_kallsyms;
else {
sprintf(path, "%s/proc/kallsyms", machine->root_dir);
filename = path;
}
if (machine__is_default_guest(machine))
filename = (char *)symbol_conf.default_guest_kallsyms;
else {
sprintf(path, "%s/proc/kallsyms", machine->root_dir);
filename = path;
}
if (symbol__restricted_filename(filename, "/proc/kallsyms"))
......
......@@ -18,4 +18,5 @@ util/cgroup.c
util/rblist.c
util/strlist.c
util/fs.c
util/trace-event.c
../../lib/rbtree.c
......@@ -1487,11 +1487,10 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
return NULL;
}
void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
struct perf_sample *sample, struct machine *machine,
void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
struct machine *machine, struct addr_location *al,
unsigned int print_opts, unsigned int stack_depth)
{
struct addr_location al;
struct callchain_cursor_node *node;
int print_ip = print_opts & PRINT_IP_OPT_IP;
int print_sym = print_opts & PRINT_IP_OPT_SYM;
......@@ -1500,15 +1499,10 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
char s = print_oneline ? ' ' : '\t';
if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
error("problem processing %d event, skipping it.\n",
event->header.type);
return;
}
if (symbol_conf.use_callchain && sample->callchain) {
struct addr_location node_al;
if (machine__resolve_callchain(machine, evsel, al.thread,
if (machine__resolve_callchain(machine, evsel, al->thread,
sample, NULL, NULL,
PERF_MAX_STACK_DEPTH) != 0) {
if (verbose)
......@@ -1517,6 +1511,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
}
callchain_cursor_commit(&callchain_cursor);
if (print_symoffset)
node_al = *al;
while (stack_depth) {
node = callchain_cursor_current(&callchain_cursor);
if (!node)
......@@ -1531,9 +1528,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
if (print_sym) {
printf(" ");
if (print_symoffset) {
al.addr = node->ip;
al.map = node->map;
symbol__fprintf_symname_offs(node->sym, &al, stdout);
node_al.addr = node->ip;
node_al.map = node->map;
symbol__fprintf_symname_offs(node->sym, &node_al, stdout);
} else
symbol__fprintf_symname(node->sym, stdout);
}
......@@ -1553,7 +1550,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
}
} else {
if (al.sym && al.sym->ignore)
if (al->sym && al->sym->ignore)
return;
if (print_ip)
......@@ -1562,15 +1559,15 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
if (print_sym) {
printf(" ");
if (print_symoffset)
symbol__fprintf_symname_offs(al.sym, &al,
symbol__fprintf_symname_offs(al->sym, al,
stdout);
else
symbol__fprintf_symname(al.sym, stdout);
symbol__fprintf_symname(al->sym, stdout);
}
if (print_dso) {
printf(" (");
map__fprintf_dsoname(al.map, stdout);
map__fprintf_dsoname(al->map, stdout);
printf(")");
}
}
......
#ifndef __PERF_SESSION_H
#define __PERF_SESSION_H
#include "trace-event.h"
#include "hist.h"
#include "event.h"
#include "header.h"
......@@ -32,7 +33,7 @@ struct perf_session {
struct perf_header header;
struct machines machines;
struct perf_evlist *evlist;
struct pevent *pevent;
struct trace_event tevent;
struct events_stats stats;
bool repipe;
struct ordered_samples ordered_samples;
......@@ -105,8 +106,8 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
unsigned int type);
void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
struct perf_sample *sample, struct machine *machine,
void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
struct machine *machine, struct addr_location *al,
unsigned int print_opts, unsigned int stack_depth);
int perf_session__cpu_bitmap(struct perf_session *session,
......
......@@ -146,18 +146,24 @@ static void addr2line_cleanup(struct a2l_data *a2l)
}
static int addr2line(const char *dso_name, unsigned long addr,
char **file, unsigned int *line)
char **file, unsigned int *line, struct dso *dso)
{
int ret = 0;
struct a2l_data *a2l;
struct a2l_data *a2l = dso->a2l;
if (!a2l) {
dso->a2l = addr2line_init(dso_name);
a2l = dso->a2l;
}
a2l = addr2line_init(dso_name);
if (a2l == NULL) {
pr_warning("addr2line_init failed for %s\n", dso_name);
return 0;
}
a2l->addr = addr;
a2l->found = false;
bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
if (a2l->found && a2l->filename) {
......@@ -168,14 +174,26 @@ static int addr2line(const char *dso_name, unsigned long addr,
ret = 1;
}
addr2line_cleanup(a2l);
return ret;
}
void dso__free_a2l(struct dso *dso)
{
struct a2l_data *a2l = dso->a2l;
if (!a2l)
return;
addr2line_cleanup(a2l);
dso->a2l = NULL;
}
#else /* HAVE_LIBBFD_SUPPORT */
static int addr2line(const char *dso_name, unsigned long addr,
char **file, unsigned int *line_nr)
char **file, unsigned int *line_nr,
struct dso *dso __maybe_unused)
{
FILE *fp;
char cmd[PATH_MAX];
......@@ -219,42 +237,58 @@ static int addr2line(const char *dso_name, unsigned long addr,
pclose(fp);
return ret;
}
void dso__free_a2l(struct dso *dso __maybe_unused)
{
}
#endif /* HAVE_LIBBFD_SUPPORT */
/*
* Number of addr2line failures (without success) before disabling it for that
* dso.
*/
#define A2L_FAIL_LIMIT 123
char *get_srcline(struct dso *dso, unsigned long addr)
{
char *file = NULL;
unsigned line = 0;
char *srcline;
char *dso_name = dso->long_name;
size_t size;
char *dso_name;
if (!dso->has_srcline)
return SRCLINE_UNKNOWN;
if (dso->symsrc_filename)
dso_name = dso->symsrc_filename;
else
dso_name = dso->long_name;
if (dso_name[0] == '[')
goto out;
if (!strncmp(dso_name, "/tmp/perf-", 10))
goto out;
if (!addr2line(dso_name, addr, &file, &line))
if (!addr2line(dso_name, addr, &file, &line, dso))
goto out;
/* just calculate actual length */
size = snprintf(NULL, 0, "%s:%u", file, line) + 1;
if (asprintf(&srcline, "%s:%u", file, line) < 0) {
free(file);
goto out;
}
srcline = malloc(size);
if (srcline)
snprintf(srcline, size, "%s:%u", file, line);
else
srcline = SRCLINE_UNKNOWN;
dso->a2l_fails = 0;
free(file);
return srcline;
out:
dso->has_srcline = 0;
if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
dso->has_srcline = 0;
dso__free_a2l(dso);
}
return SRCLINE_UNKNOWN;
}
......
......@@ -253,6 +253,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
if (!ss->name)
goto out_close;
ss->fd = fd;
ss->type = type;
return 0;
......
......@@ -1336,6 +1336,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
if (!syms_ss && symsrc__has_symtab(ss)) {
syms_ss = ss;
next_slot = true;
if (!dso->symsrc_filename)
dso->symsrc_filename = strdup(name);
}
if (!runtime_ss && symsrc__possibly_runtime(ss)) {
......
......@@ -63,4 +63,17 @@ static inline bool target__none(struct target *target)
return !target__has_task(target) && !target__has_cpu(target);
}
static inline bool target__uses_dummy_map(struct target *target)
{
bool use_dummy = false;
if (target->default_per_cpu)
use_dummy = target->per_thread ? true : false;
else if (target__has_task(target) ||
(!target__has_cpu(target) && !target->uses_mmap))
use_dummy = true;
return use_dummy;
}
#endif /* _PERF_TARGET_H */
......@@ -28,19 +28,6 @@
#include "util.h"
#include "trace-event.h"
struct pevent *read_trace_init(int file_bigendian, int host_bigendian)
{
struct pevent *pevent = pevent_alloc();
if (pevent != NULL) {
pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
pevent_set_file_bigendian(pevent, file_bigendian);
pevent_set_host_bigendian(pevent, host_bigendian);
}
return pevent;
}
static int get_common_field(struct scripting_context *context,
int *offset, int *size, const char *type)
{
......
......@@ -343,7 +343,7 @@ static int read_event_files(struct pevent *pevent)
return 0;
}
ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
{
char buf[BUFSIZ];
char test[] = { 23, 8, 68 };
......@@ -356,11 +356,9 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
int host_bigendian;
int file_long_size;
int file_page_size;
struct pevent *pevent;
struct pevent *pevent = NULL;
int err;
*ppevent = NULL;
repipe = __repipe;
input_fd = fd;
......@@ -390,12 +388,17 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
file_bigendian = buf[0];
host_bigendian = bigendian();
pevent = read_trace_init(file_bigendian, host_bigendian);
if (pevent == NULL) {
pr_debug("read_trace_init failed");
if (trace_event__init(tevent)) {
pr_debug("trace_event__init failed");
goto out;
}
pevent = tevent->pevent;
pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
pevent_set_file_bigendian(pevent, file_bigendian);
pevent_set_host_bigendian(pevent, host_bigendian);
if (do_read(buf, 1) < 0)
goto out;
file_long_size = buf[0];
......@@ -432,11 +435,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
pevent_print_printk(pevent);
}
*ppevent = pevent;
pevent = NULL;
out:
if (pevent)
pevent_free(pevent);
trace_event__cleanup(tevent);
return size;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/kernel.h>
#include <traceevent/event-parse.h>
#include "trace-event.h"
#include "util.h"
/*
* global trace_event object used by trace_event__tp_format
*
* TODO There's no cleanup call for this. Add some sort of
* __exit function support and call trace_event__cleanup
* there.
*/
static struct trace_event tevent;
int trace_event__init(struct trace_event *t)
{
struct pevent *pevent = pevent_alloc();
if (pevent) {
t->plugin_list = traceevent_load_plugins(pevent);
t->pevent = pevent;
}
return pevent ? 0 : -1;
}
void trace_event__cleanup(struct trace_event *t)
{
pevent_free(t->pevent);
traceevent_unload_plugins(t->plugin_list);
}
static struct event_format*
tp_format(const char *sys, const char *name)
{
struct pevent *pevent = tevent.pevent;
struct event_format *event = NULL;
char path[PATH_MAX];
size_t size;
char *data;
scnprintf(path, PATH_MAX, "%s/%s/%s/format",
tracing_events_path, sys, name);
if (filename__read_str(path, &data, &size))
return NULL;
pevent_parse_format(pevent, &event, data, size, sys);
free(data);
return event;
}
struct event_format*
trace_event__tp_format(const char *sys, const char *name)
{
static bool initialized;
if (!initialized) {
int be = traceevent_host_bigendian();
struct pevent *pevent;
if (trace_event__init(&tevent))
return NULL;
pevent = tevent.pevent;
pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
pevent_set_file_bigendian(pevent, be);
pevent_set_host_bigendian(pevent, be);
initialized = true;
}
return tp_format(sys, name);
}
......@@ -3,17 +3,26 @@
#include <traceevent/event-parse.h>
#include "parse-events.h"
#include "session.h"
struct machine;
struct perf_sample;
union perf_event;
struct perf_tool;
struct thread;
struct plugin_list;
struct trace_event {
struct pevent *pevent;
struct plugin_list *plugin_list;
};
int trace_event__init(struct trace_event *t);
void trace_event__cleanup(struct trace_event *t);
struct event_format*
trace_event__tp_format(const char *sys, const char *name);
int bigendian(void);
struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
void event_format__print(struct event_format *event,
int cpu, void *data, int size);
......@@ -27,7 +36,7 @@ raw_field_value(struct event_format *event, const char *name, void *data);
void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
ssize_t trace_report(int fd, struct pevent **pevent, bool repipe);
ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe);
struct event_format *trace_find_next_event(struct pevent *pevent,
struct event_format *event);
......
......@@ -6,6 +6,8 @@
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <linux/kernel.h>
/*
......@@ -433,3 +435,50 @@ int filename__read_int(const char *filename, int *value)
close(fd);
return err;
}
int filename__read_str(const char *filename, char **buf, size_t *sizep)
{
size_t size = 0, alloc_size = 0;
void *bf = NULL, *nbf;
int fd, n, err = 0;
fd = open(filename, O_RDONLY);
if (fd < 0)
return -errno;
do {
if (size == alloc_size) {
alloc_size += BUFSIZ;
nbf = realloc(bf, alloc_size);
if (!nbf) {
err = -ENOMEM;
break;
}
bf = nbf;
}
n = read(fd, bf + size, alloc_size - size);
if (n < 0) {
if (size) {
pr_warning("read failed %d: %s\n",
errno, strerror(errno));
err = 0;
} else
err = -errno;
break;
}
size += n;
} while (n > 0);
if (!err) {
*sizep = size;
*buf = bf;
} else
free(bf);
close(fd);
return err;
}
......@@ -308,4 +308,5 @@ char *get_srcline(struct dso *dso, unsigned long addr);
void free_srcline(char *srcline);
int filename__read_int(const char *filename, int *value);
int filename__read_str(const char *filename, char **buf, size_t *sizep);
#endif /* GIT_COMPAT_UTIL_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment