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))' ...@@ -43,6 +43,30 @@ man_dir_SQ = '$(subst ','\'',$(man_dir))'
export man_dir man_dir_SQ INSTALL export man_dir man_dir_SQ INSTALL
export DESTDIR DESTDIR_SQ 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 # copy a bit from Linux kbuild
ifeq ("$(origin V)", "command line") ifeq ("$(origin V)", "command line")
...@@ -96,6 +120,7 @@ export prefix bindir src obj ...@@ -96,6 +120,7 @@ export prefix bindir src obj
# Shell quotes # Shell quotes
bindir_SQ = $(subst ','\'',$(bindir)) bindir_SQ = $(subst ','\'',$(bindir))
bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
plugin_dir_SQ = $(subst ','\'',$(plugin_dir))
LIB_FILE = libtraceevent.a libtraceevent.so LIB_FILE = libtraceevent.a libtraceevent.so
...@@ -138,10 +163,10 @@ else ...@@ -138,10 +163,10 @@ else
print_app_build = echo ' BUILD '$(OBJ); print_app_build = echo ' BUILD '$(OBJ);
print_fpic_compile = echo ' CC FPIC '$(OBJ); print_fpic_compile = echo ' CC FPIC '$(OBJ);
print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ); print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ); print_plugin_obj_compile = echo ' CC FPIC '$(OBJ);
print_plugin_build = echo ' BUILD PLUGIN '$(OBJ); print_plugin_build = echo ' BUILD PLUGIN '$(OBJ);
print_static_lib_build = echo ' BUILD STATIC LIB '$(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 endif
do_fpic_compile = \ do_fpic_compile = \
...@@ -180,12 +205,29 @@ $(obj)/%.o: $(src)/%.c ...@@ -180,12 +205,29 @@ $(obj)/%.o: $(src)/%.c
%.o: $(src)/%.c %.o: $(src)/%.c
$(Q)$(call do_compile) $(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 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) TARGETS = $(CMD_TARGETS)
...@@ -200,9 +242,17 @@ libtraceevent.so: $(PEVENT_LIB_OBJS) ...@@ -200,9 +242,17 @@ libtraceevent.so: $(PEVENT_LIB_OBJS)
libtraceevent.a: $(PEVENT_LIB_OBJS) libtraceevent.a: $(PEVENT_LIB_OBJS)
$(Q)$(do_build_static_lib) $(Q)$(do_build_static_lib)
plugins: $(PLUGINS)
$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS $(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS
$(Q)$(do_fpic_compile) $(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 define make_version.h
(echo '/* This file is automatically generated. Do not modify. */'; \ (echo '/* This file is automatically generated. Do not modify. */'; \
echo \#define VERSION_CODE $(shell \ echo \#define VERSION_CODE $(shell \
...@@ -290,9 +340,16 @@ define do_install ...@@ -290,9 +340,16 @@ define do_install
$(INSTALL) $1 '$(DESTDIR_SQ)$2' $(INSTALL) $1 '$(DESTDIR_SQ)$2'
endef endef
install_lib: all_cmd install_lib: all_cmd install_plugins
$(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) $(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 install: install_lib
clean: clean:
......
...@@ -5121,8 +5121,38 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, ...@@ -5121,8 +5121,38 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp,
return ret; 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_parse_format - parse the event format
* @pevent: the handle to the pevent
* @eventp: returned format
* @buf: the buffer storing the event format string * @buf: the buffer storing the event format string
* @size: the size of @buf * @size: the size of @buf
* @sys: the system the event belongs to * @sys: the system the event belongs to
...@@ -5134,10 +5164,12 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, ...@@ -5134,10 +5164,12 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp,
* *
* /sys/kernel/debug/tracing/events/.../.../format * /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) 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, ...@@ -5158,25 +5190,7 @@ enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
unsigned long size, const char *sys) unsigned long size, const char *sys)
{ {
struct event_format *event = NULL; struct event_format *event = NULL;
int ret = __pevent_parse_format(&event, pevent, buf, size, sys); return __pevent_parse_event(pevent, &event, 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;
} }
#undef _PE #undef _PE
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdarg.h> #include <stdarg.h>
#include <regex.h> #include <regex.h>
#include <string.h>
#ifndef __maybe_unused #ifndef __maybe_unused
#define __maybe_unused __attribute__((unused)) #define __maybe_unused __attribute__((unused))
...@@ -377,6 +378,11 @@ enum pevent_errno { ...@@ -377,6 +378,11 @@ enum pevent_errno {
}; };
#undef _PE #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;
struct cmdline_list; struct cmdline_list;
struct func_map; struct func_map;
...@@ -522,6 +528,15 @@ __data2host8(struct pevent *pevent, unsigned long long data) ...@@ -522,6 +528,15 @@ __data2host8(struct pevent *pevent, unsigned long long data)
__data2host8(pevent, __val); \ __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 */ /* taken from kernel/trace/trace.h */
enum trace_flag_type { enum trace_flag_type {
TRACE_FLAG_IRQS_OFF = 0x01, TRACE_FLAG_IRQS_OFF = 0x01,
...@@ -547,7 +562,9 @@ int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long siz ...@@ -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, enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
unsigned long size, const char *sys); 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); unsigned long size, const char *sys);
void pevent_free_format(struct event_format *event); 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;
}
/*
* 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 <stdint.h>
#include "event-parse.h"
#ifdef HAVE_UDIS86
#include <udis86.h>
static ud_t ud;
static void init_disassembler(void)
{
ud_init(&ud);
ud_set_syntax(&ud, UD_SYN_ATT);
}
static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
int cr0_pe, int eflags_vm,
int cs_d, int cs_l)
{
int mode;
if (!cr0_pe)
mode = 16;
else if (eflags_vm)
mode = 16;
else if (cs_l)
mode = 64;
else if (cs_d)
mode = 32;
else
mode = 16;
ud_set_pc(&ud, rip);
ud_set_mode(&ud, mode);
ud_set_input_buffer(&ud, insn, len);
ud_disassemble(&ud);
return ud_insn_asm(&ud);
}
#else
static void init_disassembler(void)
{
}
static const char *disassemble(unsigned char *insn, int len, uint64_t rip,
int cr0_pe, int eflags_vm,
int cs_d, int cs_l)
{
static char out[15*3+1];
int i;
for (i = 0; i < len; ++i)
sprintf(out + i * 3, "%02x ", insn[i]);
out[len*3-1] = '\0';
return out;
}
#endif
#define VMX_EXIT_REASONS \
_ER(EXCEPTION_NMI, 0) \
_ER(EXTERNAL_INTERRUPT, 1) \
_ER(TRIPLE_FAULT, 2) \
_ER(PENDING_INTERRUPT, 7) \
_ER(NMI_WINDOW, 8) \
_ER(TASK_SWITCH, 9) \
_ER(CPUID, 10) \
_ER(HLT, 12) \
_ER(INVD, 13) \
_ER(INVLPG, 14) \
_ER(RDPMC, 15) \
_ER(RDTSC, 16) \
_ER(VMCALL, 18) \
_ER(VMCLEAR, 19) \
_ER(VMLAUNCH, 20) \
_ER(VMPTRLD, 21) \
_ER(VMPTRST, 22) \
_ER(VMREAD, 23) \
_ER(VMRESUME, 24) \
_ER(VMWRITE, 25) \
_ER(VMOFF, 26) \
_ER(VMON, 27) \
_ER(CR_ACCESS, 28) \
_ER(DR_ACCESS, 29) \
_ER(IO_INSTRUCTION, 30) \
_ER(MSR_READ, 31) \
_ER(MSR_WRITE, 32) \
_ER(MWAIT_INSTRUCTION, 36) \
_ER(MONITOR_INSTRUCTION, 39) \
_ER(PAUSE_INSTRUCTION, 40) \
_ER(MCE_DURING_VMENTRY, 41) \
_ER(TPR_BELOW_THRESHOLD, 43) \
_ER(APIC_ACCESS, 44) \
_ER(EOI_INDUCED, 45) \
_ER(EPT_VIOLATION, 48) \
_ER(EPT_MISCONFIG, 49) \
_ER(INVEPT, 50) \
_ER(PREEMPTION_TIMER, 52) \
_ER(WBINVD, 54) \
_ER(XSETBV, 55) \
_ER(APIC_WRITE, 56) \
_ER(INVPCID, 58)
#define SVM_EXIT_REASONS \
_ER(EXIT_READ_CR0, 0x000) \
_ER(EXIT_READ_CR3, 0x003) \
_ER(EXIT_READ_CR4, 0x004) \
_ER(EXIT_READ_CR8, 0x008) \
_ER(EXIT_WRITE_CR0, 0x010) \
_ER(EXIT_WRITE_CR3, 0x013) \
_ER(EXIT_WRITE_CR4, 0x014) \
_ER(EXIT_WRITE_CR8, 0x018) \
_ER(EXIT_READ_DR0, 0x020) \
_ER(EXIT_READ_DR1, 0x021) \
_ER(EXIT_READ_DR2, 0x022) \
_ER(EXIT_READ_DR3, 0x023) \
_ER(EXIT_READ_DR4, 0x024) \
_ER(EXIT_READ_DR5, 0x025) \
_ER(EXIT_READ_DR6, 0x026) \
_ER(EXIT_READ_DR7, 0x027) \
_ER(EXIT_WRITE_DR0, 0x030) \
_ER(EXIT_WRITE_DR1, 0x031) \
_ER(EXIT_WRITE_DR2, 0x032) \
_ER(EXIT_WRITE_DR3, 0x033) \
_ER(EXIT_WRITE_DR4, 0x034) \
_ER(EXIT_WRITE_DR5, 0x035) \
_ER(EXIT_WRITE_DR6, 0x036) \
_ER(EXIT_WRITE_DR7, 0x037) \
_ER(EXIT_EXCP_BASE, 0x040) \
_ER(EXIT_INTR, 0x060) \
_ER(EXIT_NMI, 0x061) \
_ER(EXIT_SMI, 0x062) \
_ER(EXIT_INIT, 0x063) \
_ER(EXIT_VINTR, 0x064) \
_ER(EXIT_CR0_SEL_WRITE, 0x065) \
_ER(EXIT_IDTR_READ, 0x066) \
_ER(EXIT_GDTR_READ, 0x067) \
_ER(EXIT_LDTR_READ, 0x068) \
_ER(EXIT_TR_READ, 0x069) \
_ER(EXIT_IDTR_WRITE, 0x06a) \
_ER(EXIT_GDTR_WRITE, 0x06b) \
_ER(EXIT_LDTR_WRITE, 0x06c) \
_ER(EXIT_TR_WRITE, 0x06d) \
_ER(EXIT_RDTSC, 0x06e) \
_ER(EXIT_RDPMC, 0x06f) \
_ER(EXIT_PUSHF, 0x070) \
_ER(EXIT_POPF, 0x071) \
_ER(EXIT_CPUID, 0x072) \
_ER(EXIT_RSM, 0x073) \
_ER(EXIT_IRET, 0x074) \
_ER(EXIT_SWINT, 0x075) \
_ER(EXIT_INVD, 0x076) \
_ER(EXIT_PAUSE, 0x077) \
_ER(EXIT_HLT, 0x078) \
_ER(EXIT_INVLPG, 0x079) \
_ER(EXIT_INVLPGA, 0x07a) \
_ER(EXIT_IOIO, 0x07b) \
_ER(EXIT_MSR, 0x07c) \
_ER(EXIT_TASK_SWITCH, 0x07d) \
_ER(EXIT_FERR_FREEZE, 0x07e) \
_ER(EXIT_SHUTDOWN, 0x07f) \
_ER(EXIT_VMRUN, 0x080) \
_ER(EXIT_VMMCALL, 0x081) \
_ER(EXIT_VMLOAD, 0x082) \
_ER(EXIT_VMSAVE, 0x083) \
_ER(EXIT_STGI, 0x084) \
_ER(EXIT_CLGI, 0x085) \
_ER(EXIT_SKINIT, 0x086) \
_ER(EXIT_RDTSCP, 0x087) \
_ER(EXIT_ICEBP, 0x088) \
_ER(EXIT_WBINVD, 0x089) \
_ER(EXIT_MONITOR, 0x08a) \
_ER(EXIT_MWAIT, 0x08b) \
_ER(EXIT_MWAIT_COND, 0x08c) \
_ER(EXIT_NPF, 0x400) \
_ER(EXIT_ERR, -1)
#define _ER(reason, val) { #reason, val },
struct str_values {
const char *str;
int val;
};
static struct str_values vmx_exit_reasons[] = {
VMX_EXIT_REASONS
{ NULL, -1}
};
static struct str_values svm_exit_reasons[] = {
SVM_EXIT_REASONS
{ NULL, -1}
};
static struct isa_exit_reasons {
unsigned isa;
struct str_values *strings;
} isa_exit_reasons[] = {
{ .isa = 1, .strings = vmx_exit_reasons },
{ .isa = 2, .strings = svm_exit_reasons },
{ }
};
static const char *find_exit_reason(unsigned isa, int val)
{
struct str_values *strings = NULL;
int i;
for (i = 0; isa_exit_reasons[i].strings; ++i)
if (isa_exit_reasons[i].isa == isa) {
strings = isa_exit_reasons[i].strings;
break;
}
if (!strings)
return "UNKNOWN-ISA";
for (i = 0; strings[i].val >= 0; i++)
if (strings[i].val == val)
break;
if (strings[i].str)
return strings[i].str;
return "UNKNOWN";
}
static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record,
struct event_format *event, void *context)
{
unsigned long long isa;
unsigned long long val;
unsigned long long info1 = 0, info2 = 0;
if (pevent_get_field_val(s, event, "exit_reason", record, &val, 1) < 0)
return -1;
if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0)
isa = 1;
trace_seq_printf(s, "reason %s", find_exit_reason(isa, val));
pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1);
if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0
&& pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0)
trace_seq_printf(s, " info %llx %llx", info1, info2);
return 0;
}
#define KVM_EMUL_INSN_F_CR0_PE (1 << 0)
#define KVM_EMUL_INSN_F_EFL_VM (1 << 1)
#define KVM_EMUL_INSN_F_CS_D (1 << 2)
#define KVM_EMUL_INSN_F_CS_L (1 << 3)
static int kvm_emulate_insn_handler(struct trace_seq *s,
struct pevent_record *record,
struct event_format *event, void *context)
{
unsigned long long rip, csbase, len, flags, failed;
int llen;
uint8_t *insn;
const char *disasm;
if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0)
return -1;
if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0)
return -1;
if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0)
return -1;
if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0)
return -1;
if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0)
return -1;
insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1);
if (!insn)
return -1;
disasm = disassemble(insn, len, rip,
flags & KVM_EMUL_INSN_F_CR0_PE,
flags & KVM_EMUL_INSN_F_EFL_VM,
flags & KVM_EMUL_INSN_F_CS_D,
flags & KVM_EMUL_INSN_F_CS_L);
trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm,
failed ? " FAIL" : "");
return 0;
}
union kvm_mmu_page_role {
unsigned word;
struct {
unsigned glevels:4;
unsigned level:4;
unsigned quadrant:2;
unsigned pad_for_nice_hex_output:6;
unsigned direct:1;
unsigned access:3;
unsigned invalid:1;
unsigned cr4_pge:1;
unsigned nxe:1;
};
};
static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record,
struct event_format *event, void *context)
{
unsigned long long val;
static const char *access_str[] = {
"---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux"
};
union kvm_mmu_page_role role;
if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0)
return -1;
role.word = (int)val;
/*
* We can only use the structure if file is of the same
* endianess.
*/
if (pevent_is_file_bigendian(event->pevent) ==
pevent_is_host_bigendian(event->pevent)) {
trace_seq_printf(s, "%u/%u q%u%s %s%s %spge %snxe",
role.level,
role.glevels,
role.quadrant,
role.direct ? " direct" : "",
access_str[role.access],
role.invalid ? " invalid" : "",
role.cr4_pge ? "" : "!",
role.nxe ? "" : "!");
} else
trace_seq_printf(s, "WORD: %08x", role.word);
pevent_print_num_field(s, " root %u ", event,
"root_count", record, 1);
if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0)
return -1;
trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0);
return 0;
}
static int kvm_mmu_get_page_handler(struct trace_seq *s,
struct pevent_record *record,
struct event_format *event, void *context)
{
unsigned long long val;
if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0)
return -1;
trace_seq_printf(s, "%s ", val ? "new" : "existing");
if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0)
return -1;
trace_seq_printf(s, "sp gfn %llx ", val);
return kvm_mmu_print_role(s, record, event, context);
}
#define PT_WRITABLE_SHIFT 1
#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT)
static unsigned long long
process_is_writable_pte(struct trace_seq *s, unsigned long long *args)
{
unsigned long pte = args[0];
return pte & PT_WRITABLE_MASK;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
{
init_disassembler();
pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit",
kvm_exit_handler, NULL);
pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn",
kvm_emulate_insn_handler, NULL);
pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page",
kvm_mmu_get_page_handler, NULL);
pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page",
kvm_mmu_print_role, NULL);
pevent_register_event_handler(pevent, -1,
"kvmmmu", "kvm_mmu_unsync_page",
kvm_mmu_print_role, NULL);
pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page",
kvm_mmu_print_role, NULL);
pevent_register_event_handler(pevent, -1, "kvmmmu",
"kvm_mmu_prepare_zap_page", kvm_mmu_print_role,
NULL);
pevent_register_print_function(pevent,
process_is_writable_pte,
PEVENT_FUNC_ARG_INT,
"is_writable_pte",
PEVENT_FUNC_ARG_LONG,
PEVENT_FUNC_ARG_VOID);
return 0;
}
/*
* 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;
}
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "event-parse.h"
typedef unsigned long sector_t;
typedef uint64_t u64;
typedef unsigned int u32;
/*
* SCSI opcodes
*/
#define TEST_UNIT_READY 0x00
#define REZERO_UNIT 0x01
#define REQUEST_SENSE 0x03
#define FORMAT_UNIT 0x04
#define READ_BLOCK_LIMITS 0x05
#define REASSIGN_BLOCKS 0x07
#define INITIALIZE_ELEMENT_STATUS 0x07
#define READ_6 0x08
#define WRITE_6 0x0a
#define SEEK_6 0x0b
#define READ_REVERSE 0x0f
#define WRITE_FILEMARKS 0x10
#define SPACE 0x11
#define INQUIRY 0x12
#define RECOVER_BUFFERED_DATA 0x14
#define MODE_SELECT 0x15
#define RESERVE 0x16
#define RELEASE 0x17
#define COPY 0x18
#define ERASE 0x19
#define MODE_SENSE 0x1a
#define START_STOP 0x1b
#define RECEIVE_DIAGNOSTIC 0x1c
#define SEND_DIAGNOSTIC 0x1d
#define ALLOW_MEDIUM_REMOVAL 0x1e
#define READ_FORMAT_CAPACITIES 0x23
#define SET_WINDOW 0x24
#define READ_CAPACITY 0x25
#define READ_10 0x28
#define WRITE_10 0x2a
#define SEEK_10 0x2b
#define POSITION_TO_ELEMENT 0x2b
#define WRITE_VERIFY 0x2e
#define VERIFY 0x2f
#define SEARCH_HIGH 0x30
#define SEARCH_EQUAL 0x31
#define SEARCH_LOW 0x32
#define SET_LIMITS 0x33
#define PRE_FETCH 0x34
#define READ_POSITION 0x34
#define SYNCHRONIZE_CACHE 0x35
#define LOCK_UNLOCK_CACHE 0x36
#define READ_DEFECT_DATA 0x37
#define MEDIUM_SCAN 0x38
#define COMPARE 0x39
#define COPY_VERIFY 0x3a
#define WRITE_BUFFER 0x3b
#define READ_BUFFER 0x3c
#define UPDATE_BLOCK 0x3d
#define READ_LONG 0x3e
#define WRITE_LONG 0x3f
#define CHANGE_DEFINITION 0x40
#define WRITE_SAME 0x41
#define UNMAP 0x42
#define READ_TOC 0x43
#define READ_HEADER 0x44
#define GET_EVENT_STATUS_NOTIFICATION 0x4a
#define LOG_SELECT 0x4c
#define LOG_SENSE 0x4d
#define XDWRITEREAD_10 0x53
#define MODE_SELECT_10 0x55
#define RESERVE_10 0x56
#define RELEASE_10 0x57
#define MODE_SENSE_10 0x5a
#define PERSISTENT_RESERVE_IN 0x5e
#define PERSISTENT_RESERVE_OUT 0x5f
#define VARIABLE_LENGTH_CMD 0x7f
#define REPORT_LUNS 0xa0
#define SECURITY_PROTOCOL_IN 0xa2
#define MAINTENANCE_IN 0xa3
#define MAINTENANCE_OUT 0xa4
#define MOVE_MEDIUM 0xa5
#define EXCHANGE_MEDIUM 0xa6
#define READ_12 0xa8
#define WRITE_12 0xaa
#define READ_MEDIA_SERIAL_NUMBER 0xab
#define WRITE_VERIFY_12 0xae
#define VERIFY_12 0xaf
#define SEARCH_HIGH_12 0xb0
#define SEARCH_EQUAL_12 0xb1
#define SEARCH_LOW_12 0xb2
#define SECURITY_PROTOCOL_OUT 0xb5
#define READ_ELEMENT_STATUS 0xb8
#define SEND_VOLUME_TAG 0xb6
#define WRITE_LONG_2 0xea
#define EXTENDED_COPY 0x83
#define RECEIVE_COPY_RESULTS 0x84
#define ACCESS_CONTROL_IN 0x86
#define ACCESS_CONTROL_OUT 0x87
#define READ_16 0x88
#define WRITE_16 0x8a
#define READ_ATTRIBUTE 0x8c
#define WRITE_ATTRIBUTE 0x8d
#define VERIFY_16 0x8f
#define SYNCHRONIZE_CACHE_16 0x91
#define WRITE_SAME_16 0x93
#define SERVICE_ACTION_IN 0x9e
/* values for service action in */
#define SAI_READ_CAPACITY_16 0x10
#define SAI_GET_LBA_STATUS 0x12
/* values for VARIABLE_LENGTH_CMD service action codes
* see spc4r17 Section D.3.5, table D.7 and D.8 */
#define VLC_SA_RECEIVE_CREDENTIAL 0x1800
/* values for maintenance in */
#define MI_REPORT_IDENTIFYING_INFORMATION 0x05
#define MI_REPORT_TARGET_PGS 0x0a
#define MI_REPORT_ALIASES 0x0b
#define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c
#define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d
#define MI_REPORT_PRIORITY 0x0e
#define MI_REPORT_TIMESTAMP 0x0f
#define MI_MANAGEMENT_PROTOCOL_IN 0x10
/* value for MI_REPORT_TARGET_PGS ext header */
#define MI_EXT_HDR_PARAM_FMT 0x20
/* values for maintenance out */
#define MO_SET_IDENTIFYING_INFORMATION 0x06
#define MO_SET_TARGET_PGS 0x0a
#define MO_CHANGE_ALIASES 0x0b
#define MO_SET_PRIORITY 0x0e
#define MO_SET_TIMESTAMP 0x0f
#define MO_MANAGEMENT_PROTOCOL_OUT 0x10
/* values for variable length command */
#define XDREAD_32 0x03
#define XDWRITE_32 0x04
#define XPWRITE_32 0x06
#define XDWRITEREAD_32 0x07
#define READ_32 0x09
#define VERIFY_32 0x0a
#define WRITE_32 0x0b
#define WRITE_SAME_32 0x0d
#define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f)
#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9])
static const char *
scsi_trace_misc(struct trace_seq *, unsigned char *, int);
static const char *
scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len)
{
const char *ret = p->buffer + p->len;
sector_t lba = 0, txlen = 0;
lba |= ((cdb[1] & 0x1F) << 16);
lba |= (cdb[2] << 8);
lba |= cdb[3];
txlen = cdb[4];
trace_seq_printf(p, "lba=%llu txlen=%llu",
(unsigned long long)lba, (unsigned long long)txlen);
trace_seq_putc(p, 0);
return ret;
}
static const char *
scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len)
{
const char *ret = p->buffer + p->len;
sector_t lba = 0, txlen = 0;
lba |= (cdb[2] << 24);
lba |= (cdb[3] << 16);
lba |= (cdb[4] << 8);
lba |= cdb[5];
txlen |= (cdb[7] << 8);
txlen |= cdb[8];
trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
(unsigned long long)lba, (unsigned long long)txlen,
cdb[1] >> 5);
if (cdb[0] == WRITE_SAME)
trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
trace_seq_putc(p, 0);
return ret;
}
static const char *
scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len)
{
const char *ret = p->buffer + p->len;
sector_t lba = 0, txlen = 0;
lba |= (cdb[2] << 24);
lba |= (cdb[3] << 16);
lba |= (cdb[4] << 8);
lba |= cdb[5];
txlen |= (cdb[6] << 24);
txlen |= (cdb[7] << 16);
txlen |= (cdb[8] << 8);
txlen |= cdb[9];
trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
(unsigned long long)lba, (unsigned long long)txlen,
cdb[1] >> 5);
trace_seq_putc(p, 0);
return ret;
}
static const char *
scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len)
{
const char *ret = p->buffer + p->len;
sector_t lba = 0, txlen = 0;
lba |= ((u64)cdb[2] << 56);
lba |= ((u64)cdb[3] << 48);
lba |= ((u64)cdb[4] << 40);
lba |= ((u64)cdb[5] << 32);
lba |= (cdb[6] << 24);
lba |= (cdb[7] << 16);
lba |= (cdb[8] << 8);
lba |= cdb[9];
txlen |= (cdb[10] << 24);
txlen |= (cdb[11] << 16);
txlen |= (cdb[12] << 8);
txlen |= cdb[13];
trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u",
(unsigned long long)lba, (unsigned long long)txlen,
cdb[1] >> 5);
if (cdb[0] == WRITE_SAME_16)
trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1);
trace_seq_putc(p, 0);
return ret;
}
static const char *
scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
{
const char *ret = p->buffer + p->len, *cmd;
sector_t lba = 0, txlen = 0;
u32 ei_lbrt = 0;
switch (SERVICE_ACTION32(cdb)) {
case READ_32:
cmd = "READ";
break;
case VERIFY_32:
cmd = "VERIFY";
break;
case WRITE_32:
cmd = "WRITE";
break;
case WRITE_SAME_32:
cmd = "WRITE_SAME";
break;
default:
trace_seq_printf(p, "UNKNOWN");
goto out;
}
lba |= ((u64)cdb[12] << 56);
lba |= ((u64)cdb[13] << 48);
lba |= ((u64)cdb[14] << 40);
lba |= ((u64)cdb[15] << 32);
lba |= (cdb[16] << 24);
lba |= (cdb[17] << 16);
lba |= (cdb[18] << 8);
lba |= cdb[19];
ei_lbrt |= (cdb[20] << 24);
ei_lbrt |= (cdb[21] << 16);
ei_lbrt |= (cdb[22] << 8);
ei_lbrt |= cdb[23];
txlen |= (cdb[28] << 24);
txlen |= (cdb[29] << 16);
txlen |= (cdb[30] << 8);
txlen |= cdb[31];
trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u",
cmd, (unsigned long long)lba,
(unsigned long long)txlen, cdb[10] >> 5, ei_lbrt);
if (SERVICE_ACTION32(cdb) == WRITE_SAME_32)
trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1);
out:
trace_seq_putc(p, 0);
return ret;
}
static const char *
scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len)
{
const char *ret = p->buffer + p->len;
unsigned int regions = cdb[7] << 8 | cdb[8];
trace_seq_printf(p, "regions=%u", (regions - 8) / 16);
trace_seq_putc(p, 0);
return ret;
}
static const char *
scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
{
const char *ret = p->buffer + p->len, *cmd;
sector_t lba = 0;
u32 alloc_len = 0;
switch (SERVICE_ACTION16(cdb)) {
case SAI_READ_CAPACITY_16:
cmd = "READ_CAPACITY_16";
break;
case SAI_GET_LBA_STATUS:
cmd = "GET_LBA_STATUS";
break;
default:
trace_seq_printf(p, "UNKNOWN");
goto out;
}
lba |= ((u64)cdb[2] << 56);
lba |= ((u64)cdb[3] << 48);
lba |= ((u64)cdb[4] << 40);
lba |= ((u64)cdb[5] << 32);
lba |= (cdb[6] << 24);
lba |= (cdb[7] << 16);
lba |= (cdb[8] << 8);
lba |= cdb[9];
alloc_len |= (cdb[10] << 24);
alloc_len |= (cdb[11] << 16);
alloc_len |= (cdb[12] << 8);
alloc_len |= cdb[13];
trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd,
(unsigned long long)lba, alloc_len);
out:
trace_seq_putc(p, 0);
return ret;
}
static const char *
scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len)
{
switch (SERVICE_ACTION32(cdb)) {
case READ_32:
case VERIFY_32:
case WRITE_32:
case WRITE_SAME_32:
return scsi_trace_rw32(p, cdb, len);
default:
return scsi_trace_misc(p, cdb, len);
}
}
static const char *
scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len)
{
const char *ret = p->buffer + p->len;
trace_seq_printf(p, "-");
trace_seq_putc(p, 0);
return ret;
}
const char *
scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len)
{
switch (cdb[0]) {
case READ_6:
case WRITE_6:
return scsi_trace_rw6(p, cdb, len);
case READ_10:
case VERIFY:
case WRITE_10:
case WRITE_SAME:
return scsi_trace_rw10(p, cdb, len);
case READ_12:
case VERIFY_12:
case WRITE_12:
return scsi_trace_rw12(p, cdb, len);
case READ_16:
case VERIFY_16:
case WRITE_16:
case WRITE_SAME_16:
return scsi_trace_rw16(p, cdb, len);
case UNMAP:
return scsi_trace_unmap(p, cdb, len);
case SERVICE_ACTION_IN:
return scsi_trace_service_action_in(p, cdb, len);
case VARIABLE_LENGTH_CMD:
return scsi_trace_varlen(p, cdb, len);
default:
return scsi_trace_misc(p, cdb, len);
}
}
unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s,
unsigned long long *args)
{
scsi_trace_parse_cdb(s, (unsigned char *) args[1], args[2]);
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
{
pevent_register_print_function(pevent,
process_scsi_trace_parse_cdb,
PEVENT_FUNC_ARG_STRING,
"scsi_trace_parse_cdb",
PEVENT_FUNC_ARG_PTR,
PEVENT_FUNC_ARG_PTR,
PEVENT_FUNC_ARG_INT,
PEVENT_FUNC_ARG_VOID);
return 0;
}
#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: ...@@ -24,10 +24,17 @@ There are a couple of variants of perf kvm:
of an arbitrary workload. of an arbitrary workload.
'perf kvm record <command>' to record the performance counter profile 'perf kvm record <command>' to record the performance counter profile
of an arbitrary workload and save it into a perf data file. If both of an arbitrary workload and save it into a perf data file. We set the
--host and --guest are input, the perf data file name is perf.data.kvm. default behavior of perf kvm as --guest, so if neither --host nor --guest
If there is no --host but --guest, the file name is perf.data.guest. is input, the perf data file name is perf.data.guest. If --host is input,
If there is no --guest but --host, the file name is perf.data.host. 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 'perf kvm report' to display the performance counter profile information
recorded via perf kvm record. recorded via perf kvm record.
...@@ -37,7 +44,9 @@ There are a couple of variants of perf kvm: ...@@ -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, '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 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 'perf kvm stat <command>' to run a command and gather performance counter
statistics. statistics.
...@@ -58,14 +67,14 @@ There are a couple of variants of perf kvm: ...@@ -58,14 +67,14 @@ There are a couple of variants of perf kvm:
OPTIONS OPTIONS
------- -------
-i:: -i::
--input=:: --input=<path>::
Input file name. Input file name.
-o:: -o::
--output:: --output=<path>::
Output file name. Output file name.
--host=:: --host::
Collect host side performance profile. Collect host side performance profile.
--guest=:: --guest::
Collect guest side performance profile. Collect guest side performance profile.
--guestmount=<path>:: --guestmount=<path>::
Guest os root file system mount directory. Users mounts guest os Guest os root file system mount directory. Users mounts guest os
......
...@@ -105,7 +105,7 @@ ifeq ($(config),1) ...@@ -105,7 +105,7 @@ ifeq ($(config),1)
include config/Makefile include config/Makefile
endif endif
export prefix bindir sharedir sysconfdir export prefix bindir sharedir sysconfdir DESTDIR
# sparse is architecture-neutral, which means that we need to tell it # sparse is architecture-neutral, which means that we need to tell it
# explicitly what architecture to check for. Fix this up for yours.. # explicitly what architecture to check for. Fix this up for yours..
...@@ -353,6 +353,7 @@ LIB_OBJS += $(OUTPUT)util/pmu-bison.o ...@@ -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-read.o
LIB_OBJS += $(OUTPUT)util/trace-event-info.o LIB_OBJS += $(OUTPUT)util/trace-event-info.o
LIB_OBJS += $(OUTPUT)util/trace-event-scripting.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/svghelper.o
LIB_OBJS += $(OUTPUT)util/sort.o LIB_OBJS += $(OUTPUT)util/sort.o
LIB_OBJS += $(OUTPUT)util/hist.o LIB_OBJS += $(OUTPUT)util/hist.o
...@@ -710,13 +711,20 @@ $(LIB_FILE): $(LIB_OBJS) ...@@ -710,13 +711,20 @@ $(LIB_FILE): $(LIB_OBJS)
# libtraceevent.a # libtraceevent.a
TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch])
$(LIBTRACEEVENT): $(TE_SOURCES) LIBTRACEEVENT_FLAGS = $(QUIET_SUBDIR1) O=$(OUTPUT)
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a 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: $(LIBTRACEEVENT)-clean:
$(call QUIET_CLEAN, libtraceevent) $(call QUIET_CLEAN, libtraceevent)
@$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null @$(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]) LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch])
# if subdir is set, we've been called from above so target has been built # if subdir is set, we've been called from above so target has been built
...@@ -785,7 +793,7 @@ cscope: ...@@ -785,7 +793,7 @@ cscope:
### Detect prefix changes ### Detect prefix changes
TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ 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 $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
@FLAGS='$(TRACK_CFLAGS)'; \ @FLAGS='$(TRACK_CFLAGS)'; \
...@@ -849,7 +857,7 @@ endif ...@@ -849,7 +857,7 @@ endif
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
$(INSTALL) tests/attr/* '$(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: install-python_ext:
$(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
......
...@@ -414,7 +414,8 @@ static void print_sample_bts(union perf_event *event, ...@@ -414,7 +414,8 @@ static void print_sample_bts(union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct machine *machine, struct machine *machine,
struct thread *thread) struct thread *thread,
struct addr_location *al)
{ {
struct perf_event_attr *attr = &evsel->attr; struct perf_event_attr *attr = &evsel->attr;
...@@ -424,7 +425,7 @@ static void print_sample_bts(union perf_event *event, ...@@ -424,7 +425,7 @@ static void print_sample_bts(union perf_event *event,
printf(" "); printf(" ");
else else
printf("\n"); printf("\n");
perf_evsel__print_ip(evsel, event, sample, machine, perf_evsel__print_ip(evsel, sample, machine, al,
output[attr->type].print_ip_opts, output[attr->type].print_ip_opts,
PERF_MAX_STACK_DEPTH); PERF_MAX_STACK_DEPTH);
} }
...@@ -443,7 +444,7 @@ static void print_sample_bts(union perf_event *event, ...@@ -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, static void process_event(union perf_event *event, struct perf_sample *sample,
struct perf_evsel *evsel, struct machine *machine, struct perf_evsel *evsel, struct machine *machine,
struct thread *thread, struct thread *thread,
struct addr_location *al __maybe_unused) struct addr_location *al)
{ {
struct perf_event_attr *attr = &evsel->attr; struct perf_event_attr *attr = &evsel->attr;
...@@ -458,7 +459,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, ...@@ -458,7 +459,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
} }
if (is_bts_event(attr)) { if (is_bts_event(attr)) {
print_sample_bts(event, sample, evsel, machine, thread); print_sample_bts(event, sample, evsel, machine, thread, al);
return; return;
} }
...@@ -474,7 +475,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, ...@@ -474,7 +475,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
else else
printf("\n"); printf("\n");
perf_evsel__print_ip(evsel, event, sample, machine, perf_evsel__print_ip(evsel, sample, machine, al,
output[attr->type].print_ip_opts, output[attr->type].print_ip_opts,
PERF_MAX_STACK_DEPTH); PERF_MAX_STACK_DEPTH);
} }
...@@ -1785,7 +1786,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1785,7 +1786,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
return -1; return -1;
} }
err = scripting_ops->generate_script(session->pevent, err = scripting_ops->generate_script(session->tevent.pevent,
"perf-script"); "perf-script");
goto out; goto out;
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "util/intlist.h" #include "util/intlist.h"
#include "util/thread_map.h" #include "util/thread_map.h"
#include "util/stat.h" #include "util/stat.h"
#include "trace-event.h"
#include <libaudit.h> #include <libaudit.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -1430,11 +1431,11 @@ static int trace__read_syscall_info(struct trace *trace, int id) ...@@ -1430,11 +1431,11 @@ static int trace__read_syscall_info(struct trace *trace, int id)
sc->fmt = syscall_fmt__find(sc->name); sc->fmt = syscall_fmt__find(sc->name);
snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", 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) { if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", 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) if (sc->tp_format == NULL)
......
...@@ -141,7 +141,6 @@ CORE_FEATURE_TESTS = \ ...@@ -141,7 +141,6 @@ CORE_FEATURE_TESTS = \
libslang \ libslang \
libunwind \ libunwind \
on-exit \ on-exit \
stackprotector \
stackprotector-all \ stackprotector-all \
timerfd timerfd
...@@ -209,10 +208,6 @@ ifeq ($(feature-stackprotector-all), 1) ...@@ -209,10 +208,6 @@ ifeq ($(feature-stackprotector-all), 1)
CFLAGS += -fstack-protector-all CFLAGS += -fstack-protector-all
endif endif
ifeq ($(feature-stackprotector), 1)
CFLAGS += -Wstack-protector
endif
ifeq ($(DEBUG),0) ifeq ($(DEBUG),0)
ifeq ($(feature-fortify-source), 1) ifeq ($(feature-fortify-source), 1)
CFLAGS += -D_FORTIFY_SOURCE=2 CFLAGS += -D_FORTIFY_SOURCE=2
...@@ -598,3 +593,11 @@ else ...@@ -598,3 +593,11 @@ else
perfexec_instdir = $(prefix)/$(perfexecdir) perfexec_instdir = $(prefix)/$(perfexecdir)
endif endif
perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 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= \ ...@@ -26,7 +26,6 @@ FILES= \
test-libunwind-debug-frame \ test-libunwind-debug-frame \
test-on-exit \ test-on-exit \
test-stackprotector-all \ test-stackprotector-all \
test-stackprotector \
test-timerfd test-timerfd
CC := $(CC) -MD CC := $(CC) -MD
...@@ -38,7 +37,7 @@ BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c ...@@ -38,7 +37,7 @@ BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c
############################### ###############################
test-all: 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: test-hello:
$(BUILD) $(BUILD)
...@@ -46,9 +45,6 @@ test-hello: ...@@ -46,9 +45,6 @@ test-hello:
test-stackprotector-all: test-stackprotector-all:
$(BUILD) -Werror -fstack-protector-all $(BUILD) -Werror -fstack-protector-all
test-stackprotector:
$(BUILD) -Werror -fstack-protector -Wstack-protector
test-fortify-source: test-fortify-source:
$(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2
......
#include <stdio.h>
int main(void)
{
return puts("hi");
}
...@@ -16,13 +16,11 @@ ...@@ -16,13 +16,11 @@
int verbose; int verbose;
bool dump_trace = false, quiet = false; 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; int ret = 0;
if (verbose >= level) { if (verbose >= level) {
va_start(args, fmt);
if (use_browser >= 1) if (use_browser >= 1)
ui_helpline__vshow(fmt, args); ui_helpline__vshow(fmt, args);
else else
...@@ -33,6 +31,32 @@ int eprintf(int level, const char *fmt, ...) ...@@ -33,6 +31,32 @@ int eprintf(int level, const char *fmt, ...)
return ret; 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, ...) int dump_printf(const char *fmt, ...)
{ {
va_list args; va_list args;
......
...@@ -17,4 +17,6 @@ void trace_event(union perf_event *event); ...@@ -17,4 +17,6 @@ void trace_event(union perf_event *event);
int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
int ui__warning(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 */ #endif /* __PERF_DEBUG_H */
...@@ -451,6 +451,7 @@ struct dso *dso__new(const char *name) ...@@ -451,6 +451,7 @@ struct dso *dso__new(const char *name)
dso->sorted_by_name = 0; dso->sorted_by_name = 0;
dso->has_build_id = 0; dso->has_build_id = 0;
dso->has_srcline = 1; dso->has_srcline = 1;
dso->a2l_fails = 1;
dso->kernel = DSO_TYPE_USER; dso->kernel = DSO_TYPE_USER;
dso->needs_swap = DSO_SWAP__UNSET; dso->needs_swap = DSO_SWAP__UNSET;
INIT_LIST_HEAD(&dso->node); INIT_LIST_HEAD(&dso->node);
...@@ -469,6 +470,8 @@ void dso__delete(struct dso *dso) ...@@ -469,6 +470,8 @@ void dso__delete(struct dso *dso)
if (dso->lname_alloc) if (dso->lname_alloc)
free(dso->long_name); free(dso->long_name);
dso_cache__free(&dso->cache); dso_cache__free(&dso->cache);
dso__free_a2l(dso);
free(dso->symsrc_filename);
free(dso); free(dso);
} }
......
...@@ -77,6 +77,9 @@ struct dso { ...@@ -77,6 +77,9 @@ struct dso {
struct rb_root symbols[MAP__NR_TYPES]; struct rb_root symbols[MAP__NR_TYPES];
struct rb_root symbol_names[MAP__NR_TYPES]; struct rb_root symbol_names[MAP__NR_TYPES];
struct rb_root cache; struct rb_root cache;
void *a2l;
char *symsrc_filename;
unsigned int a2l_fails;
enum dso_kernel_type kernel; enum dso_kernel_type kernel;
enum dso_swap_type needs_swap; enum dso_swap_type needs_swap;
enum dso_binary_type symtab_type; enum dso_binary_type symtab_type;
...@@ -166,4 +169,6 @@ static inline bool dso__is_kcore(struct dso *dso) ...@@ -166,4 +169,6 @@ static inline bool dso__is_kcore(struct dso *dso)
dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE; dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE;
} }
void dso__free_a2l(struct dso *dso);
#endif /* __PERF_DSO */ #endif /* __PERF_DSO */
...@@ -819,13 +819,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) ...@@ -819,13 +819,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
if (evlist->threads == NULL) if (evlist->threads == NULL)
return -1; return -1;
if (target->default_per_cpu) if (target__uses_dummy_map(target))
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)
evlist->cpus = cpu_map__dummy_new(); evlist->cpus = cpu_map__dummy_new();
else else
evlist->cpus = cpu_map__new(target->cpu_list); evlist->cpus = cpu_map__new(target->cpu_list);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "target.h" #include "target.h"
#include "perf_regs.h" #include "perf_regs.h"
#include "debug.h" #include "debug.h"
#include "trace-event.h"
static struct { static struct {
bool sample_id_all; bool sample_id_all;
...@@ -180,47 +181,6 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) ...@@ -180,47 +181,6 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
return evsel; 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 *perf_evsel__newtp_idx(const char *sys, const char *name, int idx)
{ {
struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 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 ...@@ -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) if (asprintf(&evsel->name, "%s:%s", sys, name) < 0)
goto out_free; 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) if (evsel->tp_format == NULL)
goto out_free; goto out_free;
......
...@@ -2834,11 +2834,11 @@ int perf_session__read_header(struct perf_session *session) ...@@ -2834,11 +2834,11 @@ int perf_session__read_header(struct perf_session *session)
symbol_conf.nr_events = nr_attrs; 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); perf_file_section__process);
if (perf_evlist__prepare_tracepoint_events(session->evlist, if (perf_evlist__prepare_tracepoint_events(session->evlist,
session->pevent)) session->tevent.pevent))
goto out_delete_evlist; goto out_delete_evlist;
return 0; return 0;
...@@ -3003,7 +3003,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused, ...@@ -3003,7 +3003,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
lseek(fd, offset + sizeof(struct tracing_data_event), lseek(fd, offset + sizeof(struct tracing_data_event),
SEEK_SET); SEEK_SET);
size_read = trace_report(fd, &session->pevent, size_read = trace_report(fd, &session->tevent,
session->repipe); session->repipe);
padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 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, ...@@ -3025,7 +3025,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
} }
perf_evlist__prepare_tracepoint_events(session->evlist, perf_evlist__prepare_tracepoint_events(session->evlist,
session->pevent); session->tevent.pevent);
return size_read + padding; return size_read + padding;
} }
......
...@@ -502,15 +502,11 @@ static u64 machine__get_kernel_start_addr(struct machine *machine) ...@@ -502,15 +502,11 @@ static u64 machine__get_kernel_start_addr(struct machine *machine)
char path[PATH_MAX]; char path[PATH_MAX];
struct process_args args; struct process_args args;
if (machine__is_host(machine)) { if (machine__is_default_guest(machine))
filename = "/proc/kallsyms"; filename = (char *)symbol_conf.default_guest_kallsyms;
} else { else {
if (machine__is_default_guest(machine)) sprintf(path, "%s/proc/kallsyms", machine->root_dir);
filename = (char *)symbol_conf.default_guest_kallsyms; filename = path;
else {
sprintf(path, "%s/proc/kallsyms", machine->root_dir);
filename = path;
}
} }
if (symbol__restricted_filename(filename, "/proc/kallsyms")) if (symbol__restricted_filename(filename, "/proc/kallsyms"))
......
...@@ -18,4 +18,5 @@ util/cgroup.c ...@@ -18,4 +18,5 @@ util/cgroup.c
util/rblist.c util/rblist.c
util/strlist.c util/strlist.c
util/fs.c util/fs.c
util/trace-event.c
../../lib/rbtree.c ../../lib/rbtree.c
...@@ -1487,11 +1487,10 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, ...@@ -1487,11 +1487,10 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
return NULL; return NULL;
} }
void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
struct perf_sample *sample, struct machine *machine, struct machine *machine, struct addr_location *al,
unsigned int print_opts, unsigned int stack_depth) unsigned int print_opts, unsigned int stack_depth)
{ {
struct addr_location al;
struct callchain_cursor_node *node; struct callchain_cursor_node *node;
int print_ip = print_opts & PRINT_IP_OPT_IP; int print_ip = print_opts & PRINT_IP_OPT_IP;
int print_sym = print_opts & PRINT_IP_OPT_SYM; 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, ...@@ -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; int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
char s = print_oneline ? ' ' : '\t'; 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) { 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, sample, NULL, NULL,
PERF_MAX_STACK_DEPTH) != 0) { PERF_MAX_STACK_DEPTH) != 0) {
if (verbose) if (verbose)
...@@ -1517,6 +1511,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, ...@@ -1517,6 +1511,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
} }
callchain_cursor_commit(&callchain_cursor); callchain_cursor_commit(&callchain_cursor);
if (print_symoffset)
node_al = *al;
while (stack_depth) { while (stack_depth) {
node = callchain_cursor_current(&callchain_cursor); node = callchain_cursor_current(&callchain_cursor);
if (!node) if (!node)
...@@ -1531,9 +1528,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, ...@@ -1531,9 +1528,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
if (print_sym) { if (print_sym) {
printf(" "); printf(" ");
if (print_symoffset) { if (print_symoffset) {
al.addr = node->ip; node_al.addr = node->ip;
al.map = node->map; node_al.map = node->map;
symbol__fprintf_symname_offs(node->sym, &al, stdout); symbol__fprintf_symname_offs(node->sym, &node_al, stdout);
} else } else
symbol__fprintf_symname(node->sym, stdout); symbol__fprintf_symname(node->sym, stdout);
} }
...@@ -1553,7 +1550,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, ...@@ -1553,7 +1550,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
} }
} else { } else {
if (al.sym && al.sym->ignore) if (al->sym && al->sym->ignore)
return; return;
if (print_ip) if (print_ip)
...@@ -1562,15 +1559,15 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, ...@@ -1562,15 +1559,15 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
if (print_sym) { if (print_sym) {
printf(" "); printf(" ");
if (print_symoffset) if (print_symoffset)
symbol__fprintf_symname_offs(al.sym, &al, symbol__fprintf_symname_offs(al->sym, al,
stdout); stdout);
else else
symbol__fprintf_symname(al.sym, stdout); symbol__fprintf_symname(al->sym, stdout);
} }
if (print_dso) { if (print_dso) {
printf(" ("); printf(" (");
map__fprintf_dsoname(al.map, stdout); map__fprintf_dsoname(al->map, stdout);
printf(")"); printf(")");
} }
} }
......
#ifndef __PERF_SESSION_H #ifndef __PERF_SESSION_H
#define __PERF_SESSION_H #define __PERF_SESSION_H
#include "trace-event.h"
#include "hist.h" #include "hist.h"
#include "event.h" #include "event.h"
#include "header.h" #include "header.h"
...@@ -32,7 +33,7 @@ struct perf_session { ...@@ -32,7 +33,7 @@ struct perf_session {
struct perf_header header; struct perf_header header;
struct machines machines; struct machines machines;
struct perf_evlist *evlist; struct perf_evlist *evlist;
struct pevent *pevent; struct trace_event tevent;
struct events_stats stats; struct events_stats stats;
bool repipe; bool repipe;
struct ordered_samples ordered_samples; struct ordered_samples ordered_samples;
...@@ -105,8 +106,8 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); ...@@ -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, struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
unsigned int type); unsigned int type);
void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
struct perf_sample *sample, struct machine *machine, struct machine *machine, struct addr_location *al,
unsigned int print_opts, unsigned int stack_depth); unsigned int print_opts, unsigned int stack_depth);
int perf_session__cpu_bitmap(struct perf_session *session, int perf_session__cpu_bitmap(struct perf_session *session,
......
...@@ -146,18 +146,24 @@ static void addr2line_cleanup(struct a2l_data *a2l) ...@@ -146,18 +146,24 @@ static void addr2line_cleanup(struct a2l_data *a2l)
} }
static int addr2line(const char *dso_name, unsigned long addr, 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; 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) { if (a2l == NULL) {
pr_warning("addr2line_init failed for %s\n", dso_name); pr_warning("addr2line_init failed for %s\n", dso_name);
return 0; return 0;
} }
a2l->addr = addr; a2l->addr = addr;
a2l->found = false;
bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
if (a2l->found && a2l->filename) { if (a2l->found && a2l->filename) {
...@@ -168,14 +174,26 @@ static int addr2line(const char *dso_name, unsigned long addr, ...@@ -168,14 +174,26 @@ static int addr2line(const char *dso_name, unsigned long addr,
ret = 1; ret = 1;
} }
addr2line_cleanup(a2l);
return ret; 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 */ #else /* HAVE_LIBBFD_SUPPORT */
static int addr2line(const char *dso_name, unsigned long addr, 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; FILE *fp;
char cmd[PATH_MAX]; char cmd[PATH_MAX];
...@@ -219,42 +237,58 @@ static int addr2line(const char *dso_name, unsigned long addr, ...@@ -219,42 +237,58 @@ static int addr2line(const char *dso_name, unsigned long addr,
pclose(fp); pclose(fp);
return ret; return ret;
} }
void dso__free_a2l(struct dso *dso __maybe_unused)
{
}
#endif /* HAVE_LIBBFD_SUPPORT */ #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 *get_srcline(struct dso *dso, unsigned long addr)
{ {
char *file = NULL; char *file = NULL;
unsigned line = 0; unsigned line = 0;
char *srcline; char *srcline;
char *dso_name = dso->long_name; char *dso_name;
size_t size;
if (!dso->has_srcline) if (!dso->has_srcline)
return SRCLINE_UNKNOWN; return SRCLINE_UNKNOWN;
if (dso->symsrc_filename)
dso_name = dso->symsrc_filename;
else
dso_name = dso->long_name;
if (dso_name[0] == '[') if (dso_name[0] == '[')
goto out; goto out;
if (!strncmp(dso_name, "/tmp/perf-", 10)) if (!strncmp(dso_name, "/tmp/perf-", 10))
goto out; goto out;
if (!addr2line(dso_name, addr, &file, &line)) if (!addr2line(dso_name, addr, &file, &line, dso))
goto out; goto out;
/* just calculate actual length */ if (asprintf(&srcline, "%s:%u", file, line) < 0) {
size = snprintf(NULL, 0, "%s:%u", file, line) + 1; free(file);
goto out;
}
srcline = malloc(size); dso->a2l_fails = 0;
if (srcline)
snprintf(srcline, size, "%s:%u", file, line);
else
srcline = SRCLINE_UNKNOWN;
free(file); free(file);
return srcline; return srcline;
out: 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; return SRCLINE_UNKNOWN;
} }
......
...@@ -253,6 +253,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused, ...@@ -253,6 +253,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
if (!ss->name) if (!ss->name)
goto out_close; goto out_close;
ss->fd = fd;
ss->type = type; ss->type = type;
return 0; return 0;
......
...@@ -1336,6 +1336,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) ...@@ -1336,6 +1336,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
if (!syms_ss && symsrc__has_symtab(ss)) { if (!syms_ss && symsrc__has_symtab(ss)) {
syms_ss = ss; syms_ss = ss;
next_slot = true; next_slot = true;
if (!dso->symsrc_filename)
dso->symsrc_filename = strdup(name);
} }
if (!runtime_ss && symsrc__possibly_runtime(ss)) { if (!runtime_ss && symsrc__possibly_runtime(ss)) {
......
...@@ -63,4 +63,17 @@ static inline bool target__none(struct target *target) ...@@ -63,4 +63,17 @@ static inline bool target__none(struct target *target)
return !target__has_task(target) && !target__has_cpu(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 */ #endif /* _PERF_TARGET_H */
...@@ -28,19 +28,6 @@ ...@@ -28,19 +28,6 @@
#include "util.h" #include "util.h"
#include "trace-event.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, static int get_common_field(struct scripting_context *context,
int *offset, int *size, const char *type) int *offset, int *size, const char *type)
{ {
......
...@@ -343,7 +343,7 @@ static int read_event_files(struct pevent *pevent) ...@@ -343,7 +343,7 @@ static int read_event_files(struct pevent *pevent)
return 0; 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 buf[BUFSIZ];
char test[] = { 23, 8, 68 }; char test[] = { 23, 8, 68 };
...@@ -356,11 +356,9 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) ...@@ -356,11 +356,9 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
int host_bigendian; int host_bigendian;
int file_long_size; int file_long_size;
int file_page_size; int file_page_size;
struct pevent *pevent; struct pevent *pevent = NULL;
int err; int err;
*ppevent = NULL;
repipe = __repipe; repipe = __repipe;
input_fd = fd; input_fd = fd;
...@@ -390,12 +388,17 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) ...@@ -390,12 +388,17 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
file_bigendian = buf[0]; file_bigendian = buf[0];
host_bigendian = bigendian(); host_bigendian = bigendian();
pevent = read_trace_init(file_bigendian, host_bigendian); if (trace_event__init(tevent)) {
if (pevent == NULL) { pr_debug("trace_event__init failed");
pr_debug("read_trace_init failed");
goto out; 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) if (do_read(buf, 1) < 0)
goto out; goto out;
file_long_size = buf[0]; file_long_size = buf[0];
...@@ -432,11 +435,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) ...@@ -432,11 +435,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
pevent_print_printk(pevent); pevent_print_printk(pevent);
} }
*ppevent = pevent;
pevent = NULL; pevent = NULL;
out: out:
if (pevent) if (pevent)
pevent_free(pevent); trace_event__cleanup(tevent);
return size; 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 @@ ...@@ -3,17 +3,26 @@
#include <traceevent/event-parse.h> #include <traceevent/event-parse.h>
#include "parse-events.h" #include "parse-events.h"
#include "session.h"
struct machine; struct machine;
struct perf_sample; struct perf_sample;
union perf_event; union perf_event;
struct perf_tool; struct perf_tool;
struct thread; 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); int bigendian(void);
struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
void event_format__print(struct event_format *event, void event_format__print(struct event_format *event,
int cpu, void *data, int size); int cpu, void *data, int size);
...@@ -27,7 +36,7 @@ raw_field_value(struct event_format *event, const char *name, void *data); ...@@ -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_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
void parse_ftrace_printk(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 *trace_find_next_event(struct pevent *pevent,
struct event_format *event); struct event_format *event);
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
/* /*
...@@ -433,3 +435,50 @@ int filename__read_int(const char *filename, int *value) ...@@ -433,3 +435,50 @@ int filename__read_int(const char *filename, int *value)
close(fd); close(fd);
return err; 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); ...@@ -308,4 +308,5 @@ char *get_srcline(struct dso *dso, unsigned long addr);
void free_srcline(char *srcline); void free_srcline(char *srcline);
int filename__read_int(const char *filename, int *value); 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 */ #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