mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 06:49:29 -04:00
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: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
@@ -43,6 +43,30 @@ man_dir_SQ = '$(subst ','\'',$(man_dir))'
|
||||
export man_dir man_dir_SQ INSTALL
|
||||
export DESTDIR DESTDIR_SQ
|
||||
|
||||
set_plugin_dir := 1
|
||||
|
||||
# Set plugin_dir to preffered global plugin location
|
||||
# If we install under $HOME directory we go under
|
||||
# $(HOME)/.traceevent/plugins
|
||||
#
|
||||
# We dont set PLUGIN_DIR in case we install under $HOME
|
||||
# directory, because by default the code looks under:
|
||||
# $(HOME)/.traceevent/plugins by default.
|
||||
#
|
||||
ifeq ($(plugin_dir),)
|
||||
ifeq ($(prefix),$(HOME))
|
||||
override plugin_dir = $(HOME)/.traceevent/plugins
|
||||
set_plugin_dir := 0
|
||||
else
|
||||
override plugin_dir = $(prefix)/lib/traceevent/plugins
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(set_plugin_dir),1)
|
||||
PLUGIN_DIR = -DPLUGIN_DIR="$(DESTDIR)/$(plugin_dir)"
|
||||
PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))'
|
||||
endif
|
||||
|
||||
# copy a bit from Linux kbuild
|
||||
|
||||
ifeq ("$(origin V)", "command line")
|
||||
@@ -96,6 +120,7 @@ export prefix bindir src obj
|
||||
# Shell quotes
|
||||
bindir_SQ = $(subst ','\'',$(bindir))
|
||||
bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
|
||||
plugin_dir_SQ = $(subst ','\'',$(plugin_dir))
|
||||
|
||||
LIB_FILE = libtraceevent.a libtraceevent.so
|
||||
|
||||
@@ -138,10 +163,10 @@ else
|
||||
print_app_build = echo ' BUILD '$(OBJ);
|
||||
print_fpic_compile = echo ' CC FPIC '$(OBJ);
|
||||
print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
|
||||
print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ);
|
||||
print_plugin_build = echo ' BUILD PLUGIN '$(OBJ);
|
||||
print_plugin_obj_compile = echo ' CC FPIC '$(OBJ);
|
||||
print_plugin_build = echo ' BUILD PLUGIN '$(OBJ);
|
||||
print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ);
|
||||
print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2';
|
||||
print_install = echo ' INSTALL '$1;
|
||||
endif
|
||||
|
||||
do_fpic_compile = \
|
||||
@@ -180,12 +205,29 @@ $(obj)/%.o: $(src)/%.c
|
||||
%.o: $(src)/%.c
|
||||
$(Q)$(call do_compile)
|
||||
|
||||
PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
|
||||
PEVENT_LIB_OBJS = event-parse.o
|
||||
PEVENT_LIB_OBJS += event-plugin.o
|
||||
PEVENT_LIB_OBJS += trace-seq.o
|
||||
PEVENT_LIB_OBJS += parse-filter.o
|
||||
PEVENT_LIB_OBJS += parse-utils.o
|
||||
PEVENT_LIB_OBJS += kbuffer-parse.o
|
||||
|
||||
ALL_OBJS = $(PEVENT_LIB_OBJS)
|
||||
PLUGIN_OBJS = plugin_jbd2.o
|
||||
PLUGIN_OBJS += plugin_hrtimer.o
|
||||
PLUGIN_OBJS += plugin_kmem.o
|
||||
PLUGIN_OBJS += plugin_kvm.o
|
||||
PLUGIN_OBJS += plugin_mac80211.o
|
||||
PLUGIN_OBJS += plugin_sched_switch.o
|
||||
PLUGIN_OBJS += plugin_function.o
|
||||
PLUGIN_OBJS += plugin_xen.o
|
||||
PLUGIN_OBJS += plugin_scsi.o
|
||||
PLUGIN_OBJS += plugin_cfg80211.o
|
||||
|
||||
CMD_TARGETS = $(LIB_FILE)
|
||||
PLUGINS := $(PLUGIN_OBJS:.o=.so)
|
||||
|
||||
ALL_OBJS = $(PEVENT_LIB_OBJS) $(PLUGIN_OBJS)
|
||||
|
||||
CMD_TARGETS = $(LIB_FILE) $(PLUGINS)
|
||||
|
||||
TARGETS = $(CMD_TARGETS)
|
||||
|
||||
@@ -200,9 +242,17 @@ libtraceevent.so: $(PEVENT_LIB_OBJS)
|
||||
libtraceevent.a: $(PEVENT_LIB_OBJS)
|
||||
$(Q)$(do_build_static_lib)
|
||||
|
||||
plugins: $(PLUGINS)
|
||||
|
||||
$(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS
|
||||
$(Q)$(do_fpic_compile)
|
||||
|
||||
$(PLUGIN_OBJS): %.o : $(src)/%.c
|
||||
$(Q)$(do_compile_plugin_obj)
|
||||
|
||||
$(PLUGINS): %.so: %.o
|
||||
$(Q)$(do_plugin_build)
|
||||
|
||||
define make_version.h
|
||||
(echo '/* This file is automatically generated. Do not modify. */'; \
|
||||
echo \#define VERSION_CODE $(shell \
|
||||
@@ -290,9 +340,16 @@ define do_install
|
||||
$(INSTALL) $1 '$(DESTDIR_SQ)$2'
|
||||
endef
|
||||
|
||||
install_lib: all_cmd
|
||||
install_lib: all_cmd install_plugins
|
||||
$(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
|
||||
|
||||
PLUGINS_INSTALL = $(subst .so,.install,$(PLUGINS))
|
||||
|
||||
$(PLUGINS_INSTALL): %.install : %.so force
|
||||
$(Q)$(call do_install,$<,$(plugin_dir_SQ))
|
||||
|
||||
install_plugins: $(PLUGINS_INSTALL)
|
||||
|
||||
install: install_lib
|
||||
|
||||
clean:
|
||||
|
||||
@@ -5121,8 +5121,38 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum pevent_errno
|
||||
__pevent_parse_event(struct pevent *pevent,
|
||||
struct event_format **eventp,
|
||||
const char *buf, unsigned long size,
|
||||
const char *sys)
|
||||
{
|
||||
int ret = __pevent_parse_format(eventp, pevent, buf, size, sys);
|
||||
struct event_format *event = *eventp;
|
||||
|
||||
if (event == NULL)
|
||||
return ret;
|
||||
|
||||
if (pevent && add_event(pevent, event)) {
|
||||
ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
goto event_add_failed;
|
||||
}
|
||||
|
||||
#define PRINT_ARGS 0
|
||||
if (PRINT_ARGS && event->print_fmt.args)
|
||||
print_args(event->print_fmt.args);
|
||||
|
||||
return 0;
|
||||
|
||||
event_add_failed:
|
||||
pevent_free_format(event);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* pevent_parse_format - parse the event format
|
||||
* @pevent: the handle to the pevent
|
||||
* @eventp: returned format
|
||||
* @buf: the buffer storing the event format string
|
||||
* @size: the size of @buf
|
||||
* @sys: the system the event belongs to
|
||||
@@ -5134,10 +5164,12 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp,
|
||||
*
|
||||
* /sys/kernel/debug/tracing/events/.../.../format
|
||||
*/
|
||||
enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf,
|
||||
enum pevent_errno pevent_parse_format(struct pevent *pevent,
|
||||
struct event_format **eventp,
|
||||
const char *buf,
|
||||
unsigned long size, const char *sys)
|
||||
{
|
||||
return __pevent_parse_format(eventp, NULL, buf, size, sys);
|
||||
return __pevent_parse_event(pevent, eventp, buf, size, sys);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5158,25 +5190,7 @@ enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
|
||||
unsigned long size, const char *sys)
|
||||
{
|
||||
struct event_format *event = NULL;
|
||||
int ret = __pevent_parse_format(&event, pevent, buf, size, sys);
|
||||
|
||||
if (event == NULL)
|
||||
return ret;
|
||||
|
||||
if (add_event(pevent, event)) {
|
||||
ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
||||
goto event_add_failed;
|
||||
}
|
||||
|
||||
#define PRINT_ARGS 0
|
||||
if (PRINT_ARGS && event->print_fmt.args)
|
||||
print_args(event->print_fmt.args);
|
||||
|
||||
return 0;
|
||||
|
||||
event_add_failed:
|
||||
pevent_free_format(event);
|
||||
return ret;
|
||||
return __pevent_parse_event(pevent, &event, buf, size, sys);
|
||||
}
|
||||
|
||||
#undef _PE
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <regex.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef __maybe_unused
|
||||
#define __maybe_unused __attribute__((unused))
|
||||
@@ -377,6 +378,11 @@ enum pevent_errno {
|
||||
};
|
||||
#undef _PE
|
||||
|
||||
struct plugin_list;
|
||||
|
||||
struct plugin_list *traceevent_load_plugins(struct pevent *pevent);
|
||||
void traceevent_unload_plugins(struct plugin_list *plugin_list);
|
||||
|
||||
struct cmdline;
|
||||
struct cmdline_list;
|
||||
struct func_map;
|
||||
@@ -522,6 +528,15 @@ __data2host8(struct pevent *pevent, unsigned long long data)
|
||||
__data2host8(pevent, __val); \
|
||||
})
|
||||
|
||||
static inline int traceevent_host_bigendian(void)
|
||||
{
|
||||
unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
|
||||
unsigned int val;
|
||||
|
||||
memcpy(&val, str, 4);
|
||||
return val == 0x01020304;
|
||||
}
|
||||
|
||||
/* taken from kernel/trace/trace.h */
|
||||
enum trace_flag_type {
|
||||
TRACE_FLAG_IRQS_OFF = 0x01,
|
||||
@@ -547,7 +562,9 @@ int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long siz
|
||||
|
||||
enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf,
|
||||
unsigned long size, const char *sys);
|
||||
enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf,
|
||||
enum pevent_errno pevent_parse_format(struct pevent *pevent,
|
||||
struct event_format **eventp,
|
||||
const char *buf,
|
||||
unsigned long size, const char *sys);
|
||||
void pevent_free_format(struct event_format *event);
|
||||
|
||||
|
||||
215
tools/lib/traceevent/event-plugin.c
Normal file
215
tools/lib/traceevent/event-plugin.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
24
tools/lib/traceevent/plugin_cfg80211.c
Normal file
24
tools/lib/traceevent/plugin_cfg80211.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#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;
|
||||
}
|
||||
160
tools/lib/traceevent/plugin_function.c
Normal file
160
tools/lib/traceevent/plugin_function.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
78
tools/lib/traceevent/plugin_hrtimer.c
Normal file
78
tools/lib/traceevent/plugin_hrtimer.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
68
tools/lib/traceevent/plugin_jbd2.c
Normal file
68
tools/lib/traceevent/plugin_jbd2.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
72
tools/lib/traceevent/plugin_kmem.c
Normal file
72
tools/lib/traceevent/plugin_kmem.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
436
tools/lib/traceevent/plugin_kvm.c
Normal file
436
tools/lib/traceevent/plugin_kvm.c
Normal file
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
95
tools/lib/traceevent/plugin_mac80211.c
Normal file
95
tools/lib/traceevent/plugin_mac80211.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
148
tools/lib/traceevent/plugin_sched_switch.c
Normal file
148
tools/lib/traceevent/plugin_sched_switch.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
423
tools/lib/traceevent/plugin_scsi.c
Normal file
423
tools/lib/traceevent/plugin_scsi.c
Normal file
@@ -0,0 +1,423 @@
|
||||
#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;
|
||||
}
|
||||
130
tools/lib/traceevent/plugin_xen.c
Normal file
130
tools/lib/traceevent/plugin_xen.c
Normal file
@@ -0,0 +1,130 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "event-parse.h"
|
||||
|
||||
#define __HYPERVISOR_set_trap_table 0
|
||||
#define __HYPERVISOR_mmu_update 1
|
||||
#define __HYPERVISOR_set_gdt 2
|
||||
#define __HYPERVISOR_stack_switch 3
|
||||
#define __HYPERVISOR_set_callbacks 4
|
||||
#define __HYPERVISOR_fpu_taskswitch 5
|
||||
#define __HYPERVISOR_sched_op_compat 6
|
||||
#define __HYPERVISOR_dom0_op 7
|
||||
#define __HYPERVISOR_set_debugreg 8
|
||||
#define __HYPERVISOR_get_debugreg 9
|
||||
#define __HYPERVISOR_update_descriptor 10
|
||||
#define __HYPERVISOR_memory_op 12
|
||||
#define __HYPERVISOR_multicall 13
|
||||
#define __HYPERVISOR_update_va_mapping 14
|
||||
#define __HYPERVISOR_set_timer_op 15
|
||||
#define __HYPERVISOR_event_channel_op_compat 16
|
||||
#define __HYPERVISOR_xen_version 17
|
||||
#define __HYPERVISOR_console_io 18
|
||||
#define __HYPERVISOR_physdev_op_compat 19
|
||||
#define __HYPERVISOR_grant_table_op 20
|
||||
#define __HYPERVISOR_vm_assist 21
|
||||
#define __HYPERVISOR_update_va_mapping_otherdomain 22
|
||||
#define __HYPERVISOR_iret 23 /* x86 only */
|
||||
#define __HYPERVISOR_vcpu_op 24
|
||||
#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
|
||||
#define __HYPERVISOR_mmuext_op 26
|
||||
#define __HYPERVISOR_acm_op 27
|
||||
#define __HYPERVISOR_nmi_op 28
|
||||
#define __HYPERVISOR_sched_op 29
|
||||
#define __HYPERVISOR_callback_op 30
|
||||
#define __HYPERVISOR_xenoprof_op 31
|
||||
#define __HYPERVISOR_event_channel_op 32
|
||||
#define __HYPERVISOR_physdev_op 33
|
||||
#define __HYPERVISOR_hvm_op 34
|
||||
#define __HYPERVISOR_tmem_op 38
|
||||
|
||||
/* Architecture-specific hypercall definitions. */
|
||||
#define __HYPERVISOR_arch_0 48
|
||||
#define __HYPERVISOR_arch_1 49
|
||||
#define __HYPERVISOR_arch_2 50
|
||||
#define __HYPERVISOR_arch_3 51
|
||||
#define __HYPERVISOR_arch_4 52
|
||||
#define __HYPERVISOR_arch_5 53
|
||||
#define __HYPERVISOR_arch_6 54
|
||||
#define __HYPERVISOR_arch_7 55
|
||||
|
||||
#define N(x) [__HYPERVISOR_##x] = "("#x")"
|
||||
static const char *xen_hypercall_names[] = {
|
||||
N(set_trap_table),
|
||||
N(mmu_update),
|
||||
N(set_gdt),
|
||||
N(stack_switch),
|
||||
N(set_callbacks),
|
||||
N(fpu_taskswitch),
|
||||
N(sched_op_compat),
|
||||
N(dom0_op),
|
||||
N(set_debugreg),
|
||||
N(get_debugreg),
|
||||
N(update_descriptor),
|
||||
N(memory_op),
|
||||
N(multicall),
|
||||
N(update_va_mapping),
|
||||
N(set_timer_op),
|
||||
N(event_channel_op_compat),
|
||||
N(xen_version),
|
||||
N(console_io),
|
||||
N(physdev_op_compat),
|
||||
N(grant_table_op),
|
||||
N(vm_assist),
|
||||
N(update_va_mapping_otherdomain),
|
||||
N(iret),
|
||||
N(vcpu_op),
|
||||
N(set_segment_base),
|
||||
N(mmuext_op),
|
||||
N(acm_op),
|
||||
N(nmi_op),
|
||||
N(sched_op),
|
||||
N(callback_op),
|
||||
N(xenoprof_op),
|
||||
N(event_channel_op),
|
||||
N(physdev_op),
|
||||
N(hvm_op),
|
||||
|
||||
/* Architecture-specific hypercall definitions. */
|
||||
N(arch_0),
|
||||
N(arch_1),
|
||||
N(arch_2),
|
||||
N(arch_3),
|
||||
N(arch_4),
|
||||
N(arch_5),
|
||||
N(arch_6),
|
||||
N(arch_7),
|
||||
};
|
||||
#undef N
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
static const char *xen_hypercall_name(unsigned op)
|
||||
{
|
||||
if (op < ARRAY_SIZE(xen_hypercall_names) &&
|
||||
xen_hypercall_names[op] != NULL)
|
||||
return xen_hypercall_names[op];
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
unsigned long long process_xen_hypercall_name(struct trace_seq *s,
|
||||
unsigned long long *args)
|
||||
{
|
||||
unsigned int op = args[0];
|
||||
|
||||
trace_seq_printf(s, "%s", xen_hypercall_name(op));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
|
||||
{
|
||||
pevent_register_print_function(pevent,
|
||||
process_xen_hypercall_name,
|
||||
PEVENT_FUNC_ARG_STRING,
|
||||
"xen_hypercall_name",
|
||||
PEVENT_FUNC_ARG_INT,
|
||||
PEVENT_FUNC_ARG_VOID);
|
||||
return 0;
|
||||
}
|
||||
@@ -24,10 +24,17 @@ There are a couple of variants of perf kvm:
|
||||
of an arbitrary workload.
|
||||
|
||||
'perf kvm record <command>' to record the performance counter profile
|
||||
of an arbitrary workload and save it into a perf data file. If both
|
||||
--host and --guest are input, the perf data file name is perf.data.kvm.
|
||||
If there is no --host but --guest, the file name is perf.data.guest.
|
||||
If there is no --guest but --host, the file name is perf.data.host.
|
||||
of an arbitrary workload and save it into a perf data file. We set the
|
||||
default behavior of perf kvm as --guest, so if neither --host nor --guest
|
||||
is input, the perf data file name is perf.data.guest. If --host is input,
|
||||
the perf data file name is perf.data.kvm. If you want to record data into
|
||||
perf.data.host, please input --host --no-guest. The behaviors are shown as
|
||||
following:
|
||||
Default('') -> perf.data.guest
|
||||
--host -> perf.data.kvm
|
||||
--guest -> perf.data.guest
|
||||
--host --guest -> perf.data.kvm
|
||||
--host --no-guest -> perf.data.host
|
||||
|
||||
'perf kvm report' to display the performance counter profile information
|
||||
recorded via perf kvm record.
|
||||
@@ -37,7 +44,9 @@ There are a couple of variants of perf kvm:
|
||||
|
||||
'perf kvm buildid-list' to display the buildids found in a perf data file,
|
||||
so that other tools can be used to fetch packages with matching symbol tables
|
||||
for use by perf report.
|
||||
for use by perf report. As buildid is read from /sys/kernel/notes in os, then
|
||||
if you want to list the buildid for guest, please make sure your perf data file
|
||||
was captured with --guestmount in perf kvm record.
|
||||
|
||||
'perf kvm stat <command>' to run a command and gather performance counter
|
||||
statistics.
|
||||
@@ -58,14 +67,14 @@ There are a couple of variants of perf kvm:
|
||||
OPTIONS
|
||||
-------
|
||||
-i::
|
||||
--input=::
|
||||
--input=<path>::
|
||||
Input file name.
|
||||
-o::
|
||||
--output::
|
||||
--output=<path>::
|
||||
Output file name.
|
||||
--host=::
|
||||
--host::
|
||||
Collect host side performance profile.
|
||||
--guest=::
|
||||
--guest::
|
||||
Collect guest side performance profile.
|
||||
--guestmount=<path>::
|
||||
Guest os root file system mount directory. Users mounts guest os
|
||||
|
||||
@@ -105,7 +105,7 @@ ifeq ($(config),1)
|
||||
include config/Makefile
|
||||
endif
|
||||
|
||||
export prefix bindir sharedir sysconfdir
|
||||
export prefix bindir sharedir sysconfdir DESTDIR
|
||||
|
||||
# sparse is architecture-neutral, which means that we need to tell it
|
||||
# explicitly what architecture to check for. Fix this up for yours..
|
||||
@@ -353,6 +353,7 @@ LIB_OBJS += $(OUTPUT)util/pmu-bison.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event-read.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event-info.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
|
||||
LIB_OBJS += $(OUTPUT)util/trace-event.o
|
||||
LIB_OBJS += $(OUTPUT)util/svghelper.o
|
||||
LIB_OBJS += $(OUTPUT)util/sort.o
|
||||
LIB_OBJS += $(OUTPUT)util/hist.o
|
||||
@@ -710,13 +711,20 @@ $(LIB_FILE): $(LIB_OBJS)
|
||||
# libtraceevent.a
|
||||
TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch])
|
||||
|
||||
$(LIBTRACEEVENT): $(TE_SOURCES)
|
||||
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a
|
||||
LIBTRACEEVENT_FLAGS = $(QUIET_SUBDIR1) O=$(OUTPUT)
|
||||
LIBTRACEEVENT_FLAGS += CFLAGS="-g -Wall $(EXTRA_CFLAGS)"
|
||||
LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ)
|
||||
|
||||
$(LIBTRACEEVENT): $(TE_SOURCES) $(OUTPUT)PERF-CFLAGS
|
||||
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) libtraceevent.a plugins
|
||||
|
||||
$(LIBTRACEEVENT)-clean:
|
||||
$(call QUIET_CLEAN, libtraceevent)
|
||||
@$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
|
||||
|
||||
install-traceevent-plugins:
|
||||
$(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins
|
||||
|
||||
LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch])
|
||||
|
||||
# if subdir is set, we've been called from above so target has been built
|
||||
@@ -785,7 +793,7 @@ cscope:
|
||||
|
||||
### Detect prefix changes
|
||||
TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
|
||||
$(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
|
||||
$(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):$(plugindir_SQ)
|
||||
|
||||
$(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS
|
||||
@FLAGS='$(TRACK_CFLAGS)'; \
|
||||
@@ -849,7 +857,7 @@ endif
|
||||
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
|
||||
$(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
|
||||
|
||||
install: install-bin try-install-man
|
||||
install: install-bin try-install-man install-traceevent-plugins
|
||||
|
||||
install-python_ext:
|
||||
$(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
|
||||
|
||||
@@ -414,7 +414,8 @@ static void print_sample_bts(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_evsel *evsel,
|
||||
struct machine *machine,
|
||||
struct thread *thread)
|
||||
struct thread *thread,
|
||||
struct addr_location *al)
|
||||
{
|
||||
struct perf_event_attr *attr = &evsel->attr;
|
||||
|
||||
@@ -424,7 +425,7 @@ static void print_sample_bts(union perf_event *event,
|
||||
printf(" ");
|
||||
else
|
||||
printf("\n");
|
||||
perf_evsel__print_ip(evsel, event, sample, machine,
|
||||
perf_evsel__print_ip(evsel, sample, machine, al,
|
||||
output[attr->type].print_ip_opts,
|
||||
PERF_MAX_STACK_DEPTH);
|
||||
}
|
||||
@@ -443,7 +444,7 @@ static void print_sample_bts(union perf_event *event,
|
||||
static void process_event(union perf_event *event, struct perf_sample *sample,
|
||||
struct perf_evsel *evsel, struct machine *machine,
|
||||
struct thread *thread,
|
||||
struct addr_location *al __maybe_unused)
|
||||
struct addr_location *al)
|
||||
{
|
||||
struct perf_event_attr *attr = &evsel->attr;
|
||||
|
||||
@@ -458,7 +459,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
|
||||
}
|
||||
|
||||
if (is_bts_event(attr)) {
|
||||
print_sample_bts(event, sample, evsel, machine, thread);
|
||||
print_sample_bts(event, sample, evsel, machine, thread, al);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -474,7 +475,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
|
||||
else
|
||||
printf("\n");
|
||||
|
||||
perf_evsel__print_ip(evsel, event, sample, machine,
|
||||
perf_evsel__print_ip(evsel, sample, machine, al,
|
||||
output[attr->type].print_ip_opts,
|
||||
PERF_MAX_STACK_DEPTH);
|
||||
}
|
||||
@@ -1785,7 +1786,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = scripting_ops->generate_script(session->pevent,
|
||||
err = scripting_ops->generate_script(session->tevent.pevent,
|
||||
"perf-script");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "util/intlist.h"
|
||||
#include "util/thread_map.h"
|
||||
#include "util/stat.h"
|
||||
#include "trace-event.h"
|
||||
|
||||
#include <libaudit.h>
|
||||
#include <stdlib.h>
|
||||
@@ -1430,11 +1431,11 @@ static int trace__read_syscall_info(struct trace *trace, int id)
|
||||
sc->fmt = syscall_fmt__find(sc->name);
|
||||
|
||||
snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
|
||||
sc->tp_format = event_format__new("syscalls", tp_name);
|
||||
sc->tp_format = trace_event__tp_format("syscalls", tp_name);
|
||||
|
||||
if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
|
||||
snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
|
||||
sc->tp_format = event_format__new("syscalls", tp_name);
|
||||
sc->tp_format = trace_event__tp_format("syscalls", tp_name);
|
||||
}
|
||||
|
||||
if (sc->tp_format == NULL)
|
||||
|
||||
@@ -141,7 +141,6 @@ CORE_FEATURE_TESTS = \
|
||||
libslang \
|
||||
libunwind \
|
||||
on-exit \
|
||||
stackprotector \
|
||||
stackprotector-all \
|
||||
timerfd
|
||||
|
||||
@@ -209,10 +208,6 @@ ifeq ($(feature-stackprotector-all), 1)
|
||||
CFLAGS += -fstack-protector-all
|
||||
endif
|
||||
|
||||
ifeq ($(feature-stackprotector), 1)
|
||||
CFLAGS += -Wstack-protector
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),0)
|
||||
ifeq ($(feature-fortify-source), 1)
|
||||
CFLAGS += -D_FORTIFY_SOURCE=2
|
||||
@@ -598,3 +593,11 @@ else
|
||||
perfexec_instdir = $(prefix)/$(perfexecdir)
|
||||
endif
|
||||
perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
|
||||
|
||||
# If we install to $(HOME) we keep the traceevent default:
|
||||
# $(HOME)/.traceevent/plugins
|
||||
# Otherwise we install plugins into the global $(libdir).
|
||||
ifdef DESTDIR
|
||||
plugindir=$(libdir)/traceevent/plugins
|
||||
plugindir_SQ= $(subst ','\'',$(prefix)/$(plugindir))
|
||||
endif
|
||||
|
||||
@@ -26,7 +26,6 @@ FILES= \
|
||||
test-libunwind-debug-frame \
|
||||
test-on-exit \
|
||||
test-stackprotector-all \
|
||||
test-stackprotector \
|
||||
test-timerfd
|
||||
|
||||
CC := $(CC) -MD
|
||||
@@ -38,7 +37,7 @@ BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c
|
||||
###############################
|
||||
|
||||
test-all:
|
||||
$(BUILD) -Werror -fstack-protector -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
|
||||
$(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
|
||||
|
||||
test-hello:
|
||||
$(BUILD)
|
||||
@@ -46,9 +45,6 @@ test-hello:
|
||||
test-stackprotector-all:
|
||||
$(BUILD) -Werror -fstack-protector-all
|
||||
|
||||
test-stackprotector:
|
||||
$(BUILD) -Werror -fstack-protector -Wstack-protector
|
||||
|
||||
test-fortify-source:
|
||||
$(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
return puts("hi");
|
||||
}
|
||||
@@ -16,13 +16,11 @@
|
||||
int verbose;
|
||||
bool dump_trace = false, quiet = false;
|
||||
|
||||
int eprintf(int level, const char *fmt, ...)
|
||||
static int _eprintf(int level, const char *fmt, va_list args)
|
||||
{
|
||||
va_list args;
|
||||
int ret = 0;
|
||||
|
||||
if (verbose >= level) {
|
||||
va_start(args, fmt);
|
||||
if (use_browser >= 1)
|
||||
ui_helpline__vshow(fmt, args);
|
||||
else
|
||||
@@ -33,6 +31,32 @@ int eprintf(int level, const char *fmt, ...)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int eprintf(int level, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = _eprintf(level, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Overloading libtraceevent standard info print
|
||||
* function, display with -v in perf.
|
||||
*/
|
||||
void pr_stat(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
_eprintf(1, fmt, args);
|
||||
va_end(args);
|
||||
eprintf(1, "\n");
|
||||
}
|
||||
|
||||
int dump_printf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
@@ -17,4 +17,6 @@ void trace_event(union perf_event *event);
|
||||
int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
|
||||
|
||||
void pr_stat(const char *fmt, ...);
|
||||
|
||||
#endif /* __PERF_DEBUG_H */
|
||||
|
||||
@@ -451,6 +451,7 @@ struct dso *dso__new(const char *name)
|
||||
dso->sorted_by_name = 0;
|
||||
dso->has_build_id = 0;
|
||||
dso->has_srcline = 1;
|
||||
dso->a2l_fails = 1;
|
||||
dso->kernel = DSO_TYPE_USER;
|
||||
dso->needs_swap = DSO_SWAP__UNSET;
|
||||
INIT_LIST_HEAD(&dso->node);
|
||||
@@ -469,6 +470,8 @@ void dso__delete(struct dso *dso)
|
||||
if (dso->lname_alloc)
|
||||
free(dso->long_name);
|
||||
dso_cache__free(&dso->cache);
|
||||
dso__free_a2l(dso);
|
||||
free(dso->symsrc_filename);
|
||||
free(dso);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,9 @@ struct dso {
|
||||
struct rb_root symbols[MAP__NR_TYPES];
|
||||
struct rb_root symbol_names[MAP__NR_TYPES];
|
||||
struct rb_root cache;
|
||||
void *a2l;
|
||||
char *symsrc_filename;
|
||||
unsigned int a2l_fails;
|
||||
enum dso_kernel_type kernel;
|
||||
enum dso_swap_type needs_swap;
|
||||
enum dso_binary_type symtab_type;
|
||||
@@ -166,4 +169,6 @@ static inline bool dso__is_kcore(struct dso *dso)
|
||||
dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE;
|
||||
}
|
||||
|
||||
void dso__free_a2l(struct dso *dso);
|
||||
|
||||
#endif /* __PERF_DSO */
|
||||
|
||||
@@ -819,13 +819,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
|
||||
if (evlist->threads == NULL)
|
||||
return -1;
|
||||
|
||||
if (target->default_per_cpu)
|
||||
evlist->cpus = target->per_thread ?
|
||||
cpu_map__dummy_new() :
|
||||
cpu_map__new(target->cpu_list);
|
||||
else if (target__has_task(target))
|
||||
evlist->cpus = cpu_map__dummy_new();
|
||||
else if (!target__has_cpu(target) && !target->uses_mmap)
|
||||
if (target__uses_dummy_map(target))
|
||||
evlist->cpus = cpu_map__dummy_new();
|
||||
else
|
||||
evlist->cpus = cpu_map__new(target->cpu_list);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "target.h"
|
||||
#include "perf_regs.h"
|
||||
#include "debug.h"
|
||||
#include "trace-event.h"
|
||||
|
||||
static struct {
|
||||
bool sample_id_all;
|
||||
@@ -180,47 +181,6 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
|
||||
return evsel;
|
||||
}
|
||||
|
||||
struct event_format *event_format__new(const char *sys, const char *name)
|
||||
{
|
||||
int fd, n;
|
||||
char *filename;
|
||||
void *bf = NULL, *nbf;
|
||||
size_t size = 0, alloc_size = 0;
|
||||
struct event_format *format = NULL;
|
||||
|
||||
if (asprintf(&filename, "%s/%s/%s/format", tracing_events_path, sys, name) < 0)
|
||||
goto out;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
goto out_free_filename;
|
||||
|
||||
do {
|
||||
if (size == alloc_size) {
|
||||
alloc_size += BUFSIZ;
|
||||
nbf = realloc(bf, alloc_size);
|
||||
if (nbf == NULL)
|
||||
goto out_free_bf;
|
||||
bf = nbf;
|
||||
}
|
||||
|
||||
n = read(fd, bf + size, alloc_size - size);
|
||||
if (n < 0)
|
||||
goto out_free_bf;
|
||||
size += n;
|
||||
} while (n > 0);
|
||||
|
||||
pevent_parse_format(&format, bf, size, sys);
|
||||
|
||||
out_free_bf:
|
||||
free(bf);
|
||||
close(fd);
|
||||
out_free_filename:
|
||||
free(filename);
|
||||
out:
|
||||
return format;
|
||||
}
|
||||
|
||||
struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx)
|
||||
{
|
||||
struct perf_evsel *evsel = zalloc(sizeof(*evsel));
|
||||
@@ -235,7 +195,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int
|
||||
if (asprintf(&evsel->name, "%s:%s", sys, name) < 0)
|
||||
goto out_free;
|
||||
|
||||
evsel->tp_format = event_format__new(sys, name);
|
||||
evsel->tp_format = trace_event__tp_format(sys, name);
|
||||
if (evsel->tp_format == NULL)
|
||||
goto out_free;
|
||||
|
||||
|
||||
@@ -2834,11 +2834,11 @@ int perf_session__read_header(struct perf_session *session)
|
||||
|
||||
symbol_conf.nr_events = nr_attrs;
|
||||
|
||||
perf_header__process_sections(header, fd, &session->pevent,
|
||||
perf_header__process_sections(header, fd, &session->tevent,
|
||||
perf_file_section__process);
|
||||
|
||||
if (perf_evlist__prepare_tracepoint_events(session->evlist,
|
||||
session->pevent))
|
||||
session->tevent.pevent))
|
||||
goto out_delete_evlist;
|
||||
|
||||
return 0;
|
||||
@@ -3003,7 +3003,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
|
||||
lseek(fd, offset + sizeof(struct tracing_data_event),
|
||||
SEEK_SET);
|
||||
|
||||
size_read = trace_report(fd, &session->pevent,
|
||||
size_read = trace_report(fd, &session->tevent,
|
||||
session->repipe);
|
||||
padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
|
||||
|
||||
@@ -3025,7 +3025,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
|
||||
}
|
||||
|
||||
perf_evlist__prepare_tracepoint_events(session->evlist,
|
||||
session->pevent);
|
||||
session->tevent.pevent);
|
||||
|
||||
return size_read + padding;
|
||||
}
|
||||
|
||||
@@ -502,15 +502,11 @@ static u64 machine__get_kernel_start_addr(struct machine *machine)
|
||||
char path[PATH_MAX];
|
||||
struct process_args args;
|
||||
|
||||
if (machine__is_host(machine)) {
|
||||
filename = "/proc/kallsyms";
|
||||
} else {
|
||||
if (machine__is_default_guest(machine))
|
||||
filename = (char *)symbol_conf.default_guest_kallsyms;
|
||||
else {
|
||||
sprintf(path, "%s/proc/kallsyms", machine->root_dir);
|
||||
filename = path;
|
||||
}
|
||||
if (machine__is_default_guest(machine))
|
||||
filename = (char *)symbol_conf.default_guest_kallsyms;
|
||||
else {
|
||||
sprintf(path, "%s/proc/kallsyms", machine->root_dir);
|
||||
filename = path;
|
||||
}
|
||||
|
||||
if (symbol__restricted_filename(filename, "/proc/kallsyms"))
|
||||
|
||||
@@ -18,4 +18,5 @@ util/cgroup.c
|
||||
util/rblist.c
|
||||
util/strlist.c
|
||||
util/fs.c
|
||||
util/trace-event.c
|
||||
../../lib/rbtree.c
|
||||
|
||||
@@ -1487,11 +1487,10 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
|
||||
struct perf_sample *sample, struct machine *machine,
|
||||
void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
struct machine *machine, struct addr_location *al,
|
||||
unsigned int print_opts, unsigned int stack_depth)
|
||||
{
|
||||
struct addr_location al;
|
||||
struct callchain_cursor_node *node;
|
||||
int print_ip = print_opts & PRINT_IP_OPT_IP;
|
||||
int print_sym = print_opts & PRINT_IP_OPT_SYM;
|
||||
@@ -1500,15 +1499,10 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
|
||||
int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
|
||||
char s = print_oneline ? ' ' : '\t';
|
||||
|
||||
if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
|
||||
error("problem processing %d event, skipping it.\n",
|
||||
event->header.type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (symbol_conf.use_callchain && sample->callchain) {
|
||||
struct addr_location node_al;
|
||||
|
||||
if (machine__resolve_callchain(machine, evsel, al.thread,
|
||||
if (machine__resolve_callchain(machine, evsel, al->thread,
|
||||
sample, NULL, NULL,
|
||||
PERF_MAX_STACK_DEPTH) != 0) {
|
||||
if (verbose)
|
||||
@@ -1517,6 +1511,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
|
||||
}
|
||||
callchain_cursor_commit(&callchain_cursor);
|
||||
|
||||
if (print_symoffset)
|
||||
node_al = *al;
|
||||
|
||||
while (stack_depth) {
|
||||
node = callchain_cursor_current(&callchain_cursor);
|
||||
if (!node)
|
||||
@@ -1531,9 +1528,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
|
||||
if (print_sym) {
|
||||
printf(" ");
|
||||
if (print_symoffset) {
|
||||
al.addr = node->ip;
|
||||
al.map = node->map;
|
||||
symbol__fprintf_symname_offs(node->sym, &al, stdout);
|
||||
node_al.addr = node->ip;
|
||||
node_al.map = node->map;
|
||||
symbol__fprintf_symname_offs(node->sym, &node_al, stdout);
|
||||
} else
|
||||
symbol__fprintf_symname(node->sym, stdout);
|
||||
}
|
||||
@@ -1553,7 +1550,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
|
||||
}
|
||||
|
||||
} else {
|
||||
if (al.sym && al.sym->ignore)
|
||||
if (al->sym && al->sym->ignore)
|
||||
return;
|
||||
|
||||
if (print_ip)
|
||||
@@ -1562,15 +1559,15 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
|
||||
if (print_sym) {
|
||||
printf(" ");
|
||||
if (print_symoffset)
|
||||
symbol__fprintf_symname_offs(al.sym, &al,
|
||||
symbol__fprintf_symname_offs(al->sym, al,
|
||||
stdout);
|
||||
else
|
||||
symbol__fprintf_symname(al.sym, stdout);
|
||||
symbol__fprintf_symname(al->sym, stdout);
|
||||
}
|
||||
|
||||
if (print_dso) {
|
||||
printf(" (");
|
||||
map__fprintf_dsoname(al.map, stdout);
|
||||
map__fprintf_dsoname(al->map, stdout);
|
||||
printf(")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef __PERF_SESSION_H
|
||||
#define __PERF_SESSION_H
|
||||
|
||||
#include "trace-event.h"
|
||||
#include "hist.h"
|
||||
#include "event.h"
|
||||
#include "header.h"
|
||||
@@ -32,7 +33,7 @@ struct perf_session {
|
||||
struct perf_header header;
|
||||
struct machines machines;
|
||||
struct perf_evlist *evlist;
|
||||
struct pevent *pevent;
|
||||
struct trace_event tevent;
|
||||
struct events_stats stats;
|
||||
bool repipe;
|
||||
struct ordered_samples ordered_samples;
|
||||
@@ -105,8 +106,8 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
|
||||
struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
|
||||
unsigned int type);
|
||||
|
||||
void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
|
||||
struct perf_sample *sample, struct machine *machine,
|
||||
void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
struct machine *machine, struct addr_location *al,
|
||||
unsigned int print_opts, unsigned int stack_depth);
|
||||
|
||||
int perf_session__cpu_bitmap(struct perf_session *session,
|
||||
|
||||
@@ -146,18 +146,24 @@ static void addr2line_cleanup(struct a2l_data *a2l)
|
||||
}
|
||||
|
||||
static int addr2line(const char *dso_name, unsigned long addr,
|
||||
char **file, unsigned int *line)
|
||||
char **file, unsigned int *line, struct dso *dso)
|
||||
{
|
||||
int ret = 0;
|
||||
struct a2l_data *a2l;
|
||||
struct a2l_data *a2l = dso->a2l;
|
||||
|
||||
if (!a2l) {
|
||||
dso->a2l = addr2line_init(dso_name);
|
||||
a2l = dso->a2l;
|
||||
}
|
||||
|
||||
a2l = addr2line_init(dso_name);
|
||||
if (a2l == NULL) {
|
||||
pr_warning("addr2line_init failed for %s\n", dso_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
a2l->addr = addr;
|
||||
a2l->found = false;
|
||||
|
||||
bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
|
||||
|
||||
if (a2l->found && a2l->filename) {
|
||||
@@ -168,14 +174,26 @@ static int addr2line(const char *dso_name, unsigned long addr,
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
addr2line_cleanup(a2l);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dso__free_a2l(struct dso *dso)
|
||||
{
|
||||
struct a2l_data *a2l = dso->a2l;
|
||||
|
||||
if (!a2l)
|
||||
return;
|
||||
|
||||
addr2line_cleanup(a2l);
|
||||
|
||||
dso->a2l = NULL;
|
||||
}
|
||||
|
||||
#else /* HAVE_LIBBFD_SUPPORT */
|
||||
|
||||
static int addr2line(const char *dso_name, unsigned long addr,
|
||||
char **file, unsigned int *line_nr)
|
||||
char **file, unsigned int *line_nr,
|
||||
struct dso *dso __maybe_unused)
|
||||
{
|
||||
FILE *fp;
|
||||
char cmd[PATH_MAX];
|
||||
@@ -219,42 +237,58 @@ static int addr2line(const char *dso_name, unsigned long addr,
|
||||
pclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dso__free_a2l(struct dso *dso __maybe_unused)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBBFD_SUPPORT */
|
||||
|
||||
/*
|
||||
* Number of addr2line failures (without success) before disabling it for that
|
||||
* dso.
|
||||
*/
|
||||
#define A2L_FAIL_LIMIT 123
|
||||
|
||||
char *get_srcline(struct dso *dso, unsigned long addr)
|
||||
{
|
||||
char *file = NULL;
|
||||
unsigned line = 0;
|
||||
char *srcline;
|
||||
char *dso_name = dso->long_name;
|
||||
size_t size;
|
||||
char *dso_name;
|
||||
|
||||
if (!dso->has_srcline)
|
||||
return SRCLINE_UNKNOWN;
|
||||
|
||||
if (dso->symsrc_filename)
|
||||
dso_name = dso->symsrc_filename;
|
||||
else
|
||||
dso_name = dso->long_name;
|
||||
|
||||
if (dso_name[0] == '[')
|
||||
goto out;
|
||||
|
||||
if (!strncmp(dso_name, "/tmp/perf-", 10))
|
||||
goto out;
|
||||
|
||||
if (!addr2line(dso_name, addr, &file, &line))
|
||||
if (!addr2line(dso_name, addr, &file, &line, dso))
|
||||
goto out;
|
||||
|
||||
/* just calculate actual length */
|
||||
size = snprintf(NULL, 0, "%s:%u", file, line) + 1;
|
||||
if (asprintf(&srcline, "%s:%u", file, line) < 0) {
|
||||
free(file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
srcline = malloc(size);
|
||||
if (srcline)
|
||||
snprintf(srcline, size, "%s:%u", file, line);
|
||||
else
|
||||
srcline = SRCLINE_UNKNOWN;
|
||||
dso->a2l_fails = 0;
|
||||
|
||||
free(file);
|
||||
return srcline;
|
||||
|
||||
out:
|
||||
dso->has_srcline = 0;
|
||||
if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) {
|
||||
dso->has_srcline = 0;
|
||||
dso__free_a2l(dso);
|
||||
}
|
||||
return SRCLINE_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
@@ -253,6 +253,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
|
||||
if (!ss->name)
|
||||
goto out_close;
|
||||
|
||||
ss->fd = fd;
|
||||
ss->type = type;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1336,6 +1336,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
|
||||
if (!syms_ss && symsrc__has_symtab(ss)) {
|
||||
syms_ss = ss;
|
||||
next_slot = true;
|
||||
if (!dso->symsrc_filename)
|
||||
dso->symsrc_filename = strdup(name);
|
||||
}
|
||||
|
||||
if (!runtime_ss && symsrc__possibly_runtime(ss)) {
|
||||
|
||||
@@ -63,4 +63,17 @@ static inline bool target__none(struct target *target)
|
||||
return !target__has_task(target) && !target__has_cpu(target);
|
||||
}
|
||||
|
||||
static inline bool target__uses_dummy_map(struct target *target)
|
||||
{
|
||||
bool use_dummy = false;
|
||||
|
||||
if (target->default_per_cpu)
|
||||
use_dummy = target->per_thread ? true : false;
|
||||
else if (target__has_task(target) ||
|
||||
(!target__has_cpu(target) && !target->uses_mmap))
|
||||
use_dummy = true;
|
||||
|
||||
return use_dummy;
|
||||
}
|
||||
|
||||
#endif /* _PERF_TARGET_H */
|
||||
|
||||
@@ -28,19 +28,6 @@
|
||||
#include "util.h"
|
||||
#include "trace-event.h"
|
||||
|
||||
struct pevent *read_trace_init(int file_bigendian, int host_bigendian)
|
||||
{
|
||||
struct pevent *pevent = pevent_alloc();
|
||||
|
||||
if (pevent != NULL) {
|
||||
pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
|
||||
pevent_set_file_bigendian(pevent, file_bigendian);
|
||||
pevent_set_host_bigendian(pevent, host_bigendian);
|
||||
}
|
||||
|
||||
return pevent;
|
||||
}
|
||||
|
||||
static int get_common_field(struct scripting_context *context,
|
||||
int *offset, int *size, const char *type)
|
||||
{
|
||||
|
||||
@@ -343,7 +343,7 @@ static int read_event_files(struct pevent *pevent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
|
||||
ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
|
||||
{
|
||||
char buf[BUFSIZ];
|
||||
char test[] = { 23, 8, 68 };
|
||||
@@ -356,11 +356,9 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
|
||||
int host_bigendian;
|
||||
int file_long_size;
|
||||
int file_page_size;
|
||||
struct pevent *pevent;
|
||||
struct pevent *pevent = NULL;
|
||||
int err;
|
||||
|
||||
*ppevent = NULL;
|
||||
|
||||
repipe = __repipe;
|
||||
input_fd = fd;
|
||||
|
||||
@@ -390,12 +388,17 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
|
||||
file_bigendian = buf[0];
|
||||
host_bigendian = bigendian();
|
||||
|
||||
pevent = read_trace_init(file_bigendian, host_bigendian);
|
||||
if (pevent == NULL) {
|
||||
pr_debug("read_trace_init failed");
|
||||
if (trace_event__init(tevent)) {
|
||||
pr_debug("trace_event__init failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
pevent = tevent->pevent;
|
||||
|
||||
pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
|
||||
pevent_set_file_bigendian(pevent, file_bigendian);
|
||||
pevent_set_host_bigendian(pevent, host_bigendian);
|
||||
|
||||
if (do_read(buf, 1) < 0)
|
||||
goto out;
|
||||
file_long_size = buf[0];
|
||||
@@ -432,11 +435,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
|
||||
pevent_print_printk(pevent);
|
||||
}
|
||||
|
||||
*ppevent = pevent;
|
||||
pevent = NULL;
|
||||
|
||||
out:
|
||||
if (pevent)
|
||||
pevent_free(pevent);
|
||||
trace_event__cleanup(tevent);
|
||||
return size;
|
||||
}
|
||||
|
||||
82
tools/perf/util/trace-event.c
Normal file
82
tools/perf/util/trace-event.c
Normal file
@@ -0,0 +1,82 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <traceevent/event-parse.h>
|
||||
#include "trace-event.h"
|
||||
#include "util.h"
|
||||
|
||||
/*
|
||||
* global trace_event object used by trace_event__tp_format
|
||||
*
|
||||
* TODO There's no cleanup call for this. Add some sort of
|
||||
* __exit function support and call trace_event__cleanup
|
||||
* there.
|
||||
*/
|
||||
static struct trace_event tevent;
|
||||
|
||||
int trace_event__init(struct trace_event *t)
|
||||
{
|
||||
struct pevent *pevent = pevent_alloc();
|
||||
|
||||
if (pevent) {
|
||||
t->plugin_list = traceevent_load_plugins(pevent);
|
||||
t->pevent = pevent;
|
||||
}
|
||||
|
||||
return pevent ? 0 : -1;
|
||||
}
|
||||
|
||||
void trace_event__cleanup(struct trace_event *t)
|
||||
{
|
||||
pevent_free(t->pevent);
|
||||
traceevent_unload_plugins(t->plugin_list);
|
||||
}
|
||||
|
||||
static struct event_format*
|
||||
tp_format(const char *sys, const char *name)
|
||||
{
|
||||
struct pevent *pevent = tevent.pevent;
|
||||
struct event_format *event = NULL;
|
||||
char path[PATH_MAX];
|
||||
size_t size;
|
||||
char *data;
|
||||
|
||||
scnprintf(path, PATH_MAX, "%s/%s/%s/format",
|
||||
tracing_events_path, sys, name);
|
||||
|
||||
if (filename__read_str(path, &data, &size))
|
||||
return NULL;
|
||||
|
||||
pevent_parse_format(pevent, &event, data, size, sys);
|
||||
|
||||
free(data);
|
||||
return event;
|
||||
}
|
||||
|
||||
struct event_format*
|
||||
trace_event__tp_format(const char *sys, const char *name)
|
||||
{
|
||||
static bool initialized;
|
||||
|
||||
if (!initialized) {
|
||||
int be = traceevent_host_bigendian();
|
||||
struct pevent *pevent;
|
||||
|
||||
if (trace_event__init(&tevent))
|
||||
return NULL;
|
||||
|
||||
pevent = tevent.pevent;
|
||||
pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
|
||||
pevent_set_file_bigendian(pevent, be);
|
||||
pevent_set_host_bigendian(pevent, be);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
return tp_format(sys, name);
|
||||
}
|
||||
@@ -3,17 +3,26 @@
|
||||
|
||||
#include <traceevent/event-parse.h>
|
||||
#include "parse-events.h"
|
||||
#include "session.h"
|
||||
|
||||
struct machine;
|
||||
struct perf_sample;
|
||||
union perf_event;
|
||||
struct perf_tool;
|
||||
struct thread;
|
||||
struct plugin_list;
|
||||
|
||||
struct trace_event {
|
||||
struct pevent *pevent;
|
||||
struct plugin_list *plugin_list;
|
||||
};
|
||||
|
||||
int trace_event__init(struct trace_event *t);
|
||||
void trace_event__cleanup(struct trace_event *t);
|
||||
struct event_format*
|
||||
trace_event__tp_format(const char *sys, const char *name);
|
||||
|
||||
int bigendian(void);
|
||||
|
||||
struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
|
||||
void event_format__print(struct event_format *event,
|
||||
int cpu, void *data, int size);
|
||||
|
||||
@@ -27,7 +36,7 @@ raw_field_value(struct event_format *event, const char *name, void *data);
|
||||
void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
|
||||
void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
|
||||
|
||||
ssize_t trace_report(int fd, struct pevent **pevent, bool repipe);
|
||||
ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe);
|
||||
|
||||
struct event_format *trace_find_next_event(struct pevent *pevent,
|
||||
struct event_format *event);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
/*
|
||||
@@ -433,3 +435,50 @@ int filename__read_int(const char *filename, int *value)
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
int filename__read_str(const char *filename, char **buf, size_t *sizep)
|
||||
{
|
||||
size_t size = 0, alloc_size = 0;
|
||||
void *bf = NULL, *nbf;
|
||||
int fd, n, err = 0;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
do {
|
||||
if (size == alloc_size) {
|
||||
alloc_size += BUFSIZ;
|
||||
nbf = realloc(bf, alloc_size);
|
||||
if (!nbf) {
|
||||
err = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
bf = nbf;
|
||||
}
|
||||
|
||||
n = read(fd, bf + size, alloc_size - size);
|
||||
if (n < 0) {
|
||||
if (size) {
|
||||
pr_warning("read failed %d: %s\n",
|
||||
errno, strerror(errno));
|
||||
err = 0;
|
||||
} else
|
||||
err = -errno;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
size += n;
|
||||
} while (n > 0);
|
||||
|
||||
if (!err) {
|
||||
*sizep = size;
|
||||
*buf = bf;
|
||||
} else
|
||||
free(bf);
|
||||
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -308,4 +308,5 @@ char *get_srcline(struct dso *dso, unsigned long addr);
|
||||
void free_srcline(char *srcline);
|
||||
|
||||
int filename__read_int(const char *filename, int *value);
|
||||
int filename__read_str(const char *filename, char **buf, size_t *sizep);
|
||||
#endif /* GIT_COMPAT_UTIL_H */
|
||||
|
||||
Reference in New Issue
Block a user