Commit becf6c97 authored by Ingo Molnar's avatar Ingo Molnar

Merge branch 'perf/core' of...

Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
parents 6113e45f bafb6747
......@@ -411,7 +411,7 @@ endif
no-dot-config-targets := clean mrproper distclean \
cscope TAGS tags help %docs check% \
include/linux/version.h headers_% \
kernelrelease kernelversion
kernelrelease kernelversion %src-pkg
config-targets := 0
mixed-targets := 0
......@@ -1215,6 +1215,8 @@ distclean: mrproper
# rpm target kept for backward compatibility
package-dir := $(srctree)/scripts/package
%src-pkg: FORCE
$(Q)$(MAKE) $(build)=$(package-dir) $@
%pkg: include/config/kernel.release FORCE
$(Q)$(MAKE) $(build)=$(package-dir) $@
rpm: include/config/kernel.release FORCE
......
......@@ -111,6 +111,28 @@ tar%pkg: FORCE
clean-dirs += $(objtree)/tar-install/
# perf-pkg - generate a source tarball with perf source
# ---------------------------------------------------------------------------
perf-tar=perf-$(KERNELVERSION)
quiet_cmd_perf_tar = TAR
cmd_perf_tar = \
git archive --prefix=$(perf-tar)/ HEAD^{tree} \
$$(cat $(srctree)/tools/perf/MANIFEST) -o $(perf-tar).tar; \
mkdir -p $(perf-tar); \
git rev-parse HEAD > $(perf-tar)/HEAD; \
tar rf $(perf-tar).tar $(perf-tar)/HEAD; \
rm -r $(perf-tar); \
$(if $(findstring tar-src,$@),, \
$(if $(findstring bz2,$@),bzip2, \
$(if $(findstring gz,$@),gzip, \
$(error unknown target $@))) \
-f -9 $(perf-tar).tar)
perf-%pkg: FORCE
$(call cmd,perf_tar)
# Help text displayed when executing 'make help'
# ---------------------------------------------------------------------------
help: FORCE
......@@ -120,4 +142,7 @@ help: FORCE
@echo ' tar-pkg - Build the kernel as an uncompressed tarball'
@echo ' targz-pkg - Build the kernel as a gzip compressed tarball'
@echo ' tarbz2-pkg - Build the kernel as a bzip2 compressed tarball'
@echo ' perf-tar-src-pkg - Build $(perf-tar).tar source tarball'
@echo ' perf-targz-src-pkg - Build $(perf-tar).tar.gz source tarball'
@echo ' perf-tarbz2-src-pkg - Build $(perf-tar).tar.bz2 source tarball'
......@@ -103,6 +103,13 @@ OPTIONS
--raw-samples::
Collect raw sample records from all opened counters (default for tracepoint counters).
-C::
--cpu::
Collect samples only on the list of cpus provided. Multiple CPUs can be provided as a
comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
In per-thread mode with inheritance mode on (default), samples are captured only when
the thread executes on the designated CPUs. Default is to monitor all CPUs.
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
......@@ -46,6 +46,13 @@ OPTIONS
-B::
print large numbers with thousands' separators according to locale
-C::
--cpu=::
Count only on the list of cpus provided. Multiple CPUs can be provided as a
comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
In per-thread mode, this option is ignored. The -a option is still necessary
to activate system-wide monitoring. Default is to count on all CPUs.
EXAMPLES
--------
......
......@@ -25,9 +25,11 @@ OPTIONS
--count=<count>::
Event period to sample.
-C <cpu>::
--CPU=<cpu>::
CPU to profile.
-C <cpu-list>::
--cpu=<cpu>::
Monitor only on the list of cpus provided. Multiple CPUs can be provided as a
comma-sperated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2.
Default is to monitor all CPUS.
-d <seconds>::
--delay=<seconds>::
......
tools/perf
include/linux/perf_event.h
include/linux/rbtree.h
include/linux/list.h
include/linux/hash.h
include/linux/stringify.h
lib/rbtree.c
include/linux/swab.h
arch/*/include/asm/unistd*.h
include/linux/poison.h
include/linux/magic.h
include/linux/hw_breakpoint.h
......@@ -61,11 +61,9 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
static int process_sample_event(event_t *event, struct perf_session *session)
{
struct addr_location al;
struct sample_data data;
dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
event->ip.pid, event->ip.ip);
if (event__preprocess_sample(event, session, &al, NULL) < 0) {
if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
pr_warning("problem processing %d event, skipping it.\n",
event->header.type);
return -1;
......
......@@ -78,8 +78,7 @@ static int __cmd_buildid_cache(void)
struct str_node *pos;
char debugdir[PATH_MAX];
snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
DEBUG_CACHE_DIR);
snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
if (add_name_list_str) {
list = strlist__new(true, add_name_list_str);
......
......@@ -35,10 +35,7 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
struct addr_location al;
struct sample_data data = { .period = 1, };
dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc,
event->ip.pid, event->ip.ip);
if (event__preprocess_sample(event, session, &al, NULL) < 0) {
if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
pr_warning("problem processing %d event, skipping it.\n",
event->header.type);
return -1;
......@@ -47,8 +44,6 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
if (al.filtered || al.sym == NULL)
return 0;
event__parse_sample(event, session->sample_type, &data);
if (hists__add_entry(&session->hists, &al, data.period)) {
pr_warning("problem incrementing symbol period, skipping event\n");
return -1;
......
......@@ -49,7 +49,6 @@ static int group = 0;
static int realtime_prio = 0;
static bool raw_samples = false;
static bool system_wide = false;
static int profile_cpu = -1;
static pid_t target_pid = -1;
static pid_t target_tid = -1;
static pid_t *all_tids = NULL;
......@@ -74,6 +73,7 @@ static int file_new = 1;
static off_t post_processing_offset;
static struct perf_session *session;
static const char *cpu_list;
struct mmap_data {
int counter;
......@@ -274,6 +274,9 @@ static void create_counter(int counter, int cpu)
if (call_graph)
attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
if (system_wide)
attr->sample_type |= PERF_SAMPLE_CPU;
if (raw_samples) {
attr->sample_type |= PERF_SAMPLE_TIME;
attr->sample_type |= PERF_SAMPLE_RAW;
......@@ -300,7 +303,7 @@ static void create_counter(int counter, int cpu)
die("Permission error - are you root?\n"
"\t Consider tweaking"
" /proc/sys/kernel/perf_event_paranoid.\n");
else if (err == ENODEV && profile_cpu != -1) {
else if (err == ENODEV && cpu_list) {
die("No such device - did you specify"
" an out-of-range profile CPU?\n");
}
......@@ -622,10 +625,15 @@ static int __cmd_record(int argc, const char **argv)
close(child_ready_pipe[0]);
}
if ((!system_wide && no_inherit) || profile_cpu != -1) {
open_counters(profile_cpu);
nr_cpus = read_cpu_map(cpu_list);
if (nr_cpus < 1) {
perror("failed to collect number of CPUs\n");
return -1;
}
if (!system_wide && no_inherit && !cpu_list) {
open_counters(-1);
} else {
nr_cpus = read_cpu_map();
for (i = 0; i < nr_cpus; i++)
open_counters(cpumap[i]);
}
......@@ -704,7 +712,7 @@ static int __cmd_record(int argc, const char **argv)
if (perf_guest)
perf_session__process_machines(session, event__synthesize_guest_os);
if (!system_wide && profile_cpu == -1)
if (!system_wide && cpu_list)
event__synthesize_thread(target_tid, process_synthesized_event,
session);
else
......@@ -794,8 +802,8 @@ static const struct option options[] = {
"system-wide collection from all CPUs"),
OPT_BOOLEAN('A', "append", &append_file,
"append to the output file to do incremental profiling"),
OPT_INTEGER('C', "profile_cpu", &profile_cpu,
"CPU to profile on"),
OPT_STRING('C', "cpu", &cpu_list, "cpu",
"list of cpus to monitor"),
OPT_BOOLEAN('f', "force", &force,
"overwrite existing data file (deprecated)"),
OPT_U64('c', "count", &user_interval, "event period to sample"),
......@@ -825,7 +833,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
argc = parse_options(argc, argv, options, record_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc && target_pid == -1 && target_tid == -1 &&
!system_wide && profile_cpu == -1)
!system_wide && !cpu_list)
usage_with_options(record_usage, options);
if (force && append_file) {
......
......@@ -155,30 +155,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
struct addr_location al;
struct perf_event_attr *attr;
event__parse_sample(event, session->sample_type, &data);
dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
data.pid, data.tid, data.ip, data.period);
if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
unsigned int i;
dump_printf("... chain: nr:%Lu\n", data.callchain->nr);
if (!ip_callchain__valid(data.callchain, event)) {
pr_debug("call-chain problem with event, "
"skipping it.\n");
return 0;
}
if (dump_trace) {
for (i = 0; i < data.callchain->nr; i++)
dump_printf("..... %2d: %016Lx\n",
i, data.callchain->ips[i]);
}
}
if (event__preprocess_sample(event, session, &al, NULL) < 0) {
if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
fprintf(stderr, "problem processing %d event, skipping it.\n",
event->header.type);
return -1;
......
......@@ -69,7 +69,7 @@ static struct perf_event_attr default_attrs[] = {
};
static bool system_wide = false;
static unsigned int nr_cpus = 0;
static int nr_cpus = 0;
static int run_idx = 0;
static int run_count = 1;
......@@ -82,6 +82,7 @@ static int thread_num = 0;
static pid_t child_pid = -1;
static bool null_run = false;
static bool big_num = false;
static const char *cpu_list;
static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
......@@ -158,7 +159,7 @@ static int create_perf_stat_counter(int counter)
PERF_FORMAT_TOTAL_TIME_RUNNING;
if (system_wide) {
unsigned int cpu;
int cpu;
for (cpu = 0; cpu < nr_cpus; cpu++) {
fd[cpu][counter][0] = sys_perf_event_open(attr,
......@@ -208,7 +209,7 @@ static inline int nsec_counter(int counter)
static void read_counter(int counter)
{
u64 count[3], single_count[3];
unsigned int cpu;
int cpu;
size_t res, nv;
int scaled;
int i, thread;
......@@ -542,6 +543,8 @@ static const struct option options[] = {
"null run - dont start any counters"),
OPT_BOOLEAN('B', "big-num", &big_num,
"print large numbers with thousands\' separators"),
OPT_STRING('C', "cpu", &cpu_list, "cpu",
"list of cpus to monitor in system-wide"),
OPT_END()
};
......@@ -566,10 +569,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
}
if (system_wide)
nr_cpus = read_cpu_map();
nr_cpus = read_cpu_map(cpu_list);
else
nr_cpus = 1;
if (nr_cpus < 1)
usage_with_options(stat_usage, options);
if (target_pid != -1) {
target_tid = target_pid;
thread_num = find_all_tid(target_pid, &all_tids);
......
......@@ -102,6 +102,7 @@ struct sym_entry *sym_filter_entry_sched = NULL;
static int sym_pcnt_filter = 5;
static int sym_counter = 0;
static int display_weighted = -1;
static const char *cpu_list;
/*
* Symbols
......@@ -982,6 +983,7 @@ static void event__process_sample(const event_t *self,
u64 ip = self->ip.ip;
struct sym_entry *syme;
struct addr_location al;
struct sample_data data;
struct machine *machine;
u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
......@@ -1024,7 +1026,8 @@ static void event__process_sample(const event_t *self,
if (self->header.misc & PERF_RECORD_MISC_EXACT_IP)
exact_samples++;
if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
if (event__preprocess_sample(self, session, &al, &data,
symbol_filter) < 0 ||
al.filtered)
return;
......@@ -1351,8 +1354,8 @@ static const struct option options[] = {
"profile events on existing thread id"),
OPT_BOOLEAN('a', "all-cpus", &system_wide,
"system-wide collection from all CPUs"),
OPT_INTEGER('C', "CPU", &profile_cpu,
"CPU to profile on"),
OPT_STRING('C', "cpu", &cpu_list, "cpu",
"list of cpus to monitor"),
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
"file", "vmlinux pathname"),
OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols,
......@@ -1428,10 +1431,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
return -ENOMEM;
/* CPU and PID are mutually exclusive */
if (target_tid > 0 && profile_cpu != -1) {
if (target_tid > 0 && cpu_list) {
printf("WARNING: PID switch overriding CPU\n");
sleep(1);
profile_cpu = -1;
cpu_list = NULL;
}
if (!nr_counters)
......@@ -1469,10 +1472,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
attrs[counter].sample_period = default_interval;
}
if (target_tid != -1 || profile_cpu != -1)
if (target_tid != -1)
nr_cpus = 1;
else
nr_cpus = read_cpu_map();
nr_cpus = read_cpu_map(cpu_list);
if (nr_cpus < 1)
usage_with_options(top_usage, options);
get_term_dimensions(&winsize);
if (print_entries == 0) {
......
......@@ -7,7 +7,17 @@ if [ $# -ne 0 ] ; then
PERF_DATA=$1
fi
DEBUGDIR=~/.debug/
#
# PERF_BUILDID_DIR environment variable set by perf
# path to buildid directory, default to $HOME/.debug
#
if [ -z $PERF_BUILDID_DIR ]; then
PERF_BUILDID_DIR=~/.debug/
else
# append / to make substitutions work
PERF_BUILDID_DIR=$PERF_BUILDID_DIR/
fi
BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX)
NOBUILDID=0000000000000000000000000000000000000000
......@@ -22,13 +32,13 @@ MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX)
cut -d ' ' -f 1 $BUILDIDS | \
while read build_id ; do
linkname=$DEBUGDIR.build-id/${build_id:0:2}/${build_id:2}
linkname=$PERF_BUILDID_DIR.build-id/${build_id:0:2}/${build_id:2}
filename=$(readlink -f $linkname)
echo ${linkname#$DEBUGDIR} >> $MANIFEST
echo ${filename#$DEBUGDIR} >> $MANIFEST
echo ${linkname#$PERF_BUILDID_DIR} >> $MANIFEST
echo ${filename#$PERF_BUILDID_DIR} >> $MANIFEST
done
tar cfj $PERF_DATA.tar.bz2 -C $DEBUGDIR -T $MANIFEST
tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
rm -f $MANIFEST $BUILDIDS
echo -e "Now please run:\n"
echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n"
......
......@@ -458,6 +458,8 @@ int main(int argc, const char **argv)
handle_options(&argv, &argc, NULL);
commit_pager_choice();
set_debugfs_path();
set_buildid_dir();
if (argc > 0) {
if (!prefixcmp(argv[0], "--"))
argv[0] += 2;
......
......@@ -43,19 +43,17 @@ struct perf_event_ops build_id__mark_dso_hit_ops = {
char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
{
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
const char *home;
if (!self->has_build_id)
return NULL;
build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex);
home = getenv("HOME");
if (bf == NULL) {
if (asprintf(&bf, "%s/%s/.build-id/%.2s/%s", home,
DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2) < 0)
if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir,
build_id_hex, build_id_hex + 2) < 0)
return NULL;
} else
snprintf(bf, size, "%s/%s/.build-id/%.2s/%s", home,
DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2);
snprintf(bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
build_id_hex, build_id_hex + 2);
return bf;
}
......@@ -23,6 +23,7 @@ extern int perf_config(config_fn_t fn, void *);
extern int perf_config_int(const char *, const char *);
extern int perf_config_bool(const char *, const char *);
extern int config_error_nonbool(const char *);
extern const char *perf_config_dirname(const char *, const char *);
/* pager.c */
extern void setup_pager(void);
......
......@@ -18,7 +18,7 @@
#include "util.h"
#include "callchain.h"
bool ip_callchain__valid(struct ip_callchain *chain, event_t *event)
bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
{
unsigned int chain_size = event->header.size;
chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
......
......@@ -60,5 +60,5 @@ int register_callchain_param(struct callchain_param *param);
int append_chain(struct callchain_node *root, struct ip_callchain *chain,
struct map_symbol *syms);
bool ip_callchain__valid(struct ip_callchain *chain, event_t *event);
bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
#endif /* __PERF_CALLCHAIN_H */
......@@ -11,6 +11,11 @@
#define MAXNAME (256)
#define DEBUG_CACHE_DIR ".debug"
char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
static FILE *config_file;
static const char *config_file_name;
static int config_linenr;
......@@ -127,7 +132,7 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
break;
if (!iskeychar(c))
break;
name[len++] = tolower(c);
name[len++] = c;
if (len >= MAXNAME)
return -1;
}
......@@ -327,6 +332,13 @@ int perf_config_bool(const char *name, const char *value)
return !!perf_config_bool_or_int(name, value, &discard);
}
const char *perf_config_dirname(const char *name, const char *value)
{
if (!name)
return NULL;
return value;
}
static int perf_default_core_config(const char *var __used, const char *value __used)
{
/* Add other config variables here and to Documentation/config.txt. */
......@@ -428,3 +440,53 @@ int config_error_nonbool(const char *var)
{
return error("Missing value for '%s'", var);
}
struct buildid_dir_config {
char *dir;
};
static int buildid_dir_command_config(const char *var, const char *value,
void *data)
{
struct buildid_dir_config *c = data;
const char *v;
/* same dir for all commands */
if (!prefixcmp(var, "buildid.") && !strcmp(var + 8, "dir")) {
v = perf_config_dirname(var, value);
if (!v)
return -1;
strncpy(c->dir, v, MAXPATHLEN-1);
c->dir[MAXPATHLEN-1] = '\0';
}
return 0;
}
static void check_buildid_dir_config(void)
{
struct buildid_dir_config c;
c.dir = buildid_dir;
perf_config(buildid_dir_command_config, &c);
}
void set_buildid_dir(void)
{
buildid_dir[0] = '\0';
/* try config file */
check_buildid_dir_config();
/* default to $HOME/.debug */
if (buildid_dir[0] == '\0') {
char *v = getenv("HOME");
if (v) {
snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s",
v, DEBUG_CACHE_DIR);
} else {
strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
}
buildid_dir[MAXPATHLEN-1] = '\0';
}
/* for communicating with external commands */
setenv("PERF_BUILDID_DIR", buildid_dir, 1);
}
......@@ -20,7 +20,7 @@ static int default_cpu_map(void)
return nr_cpus;
}
int read_cpu_map(void)
static int read_all_cpu_map(void)
{
FILE *onlnf;
int nr_cpus = 0;
......@@ -57,3 +57,58 @@ int read_cpu_map(void)
return default_cpu_map();
}
int read_cpu_map(const char *cpu_list)
{
unsigned long start_cpu, end_cpu = 0;
char *p = NULL;
int i, nr_cpus = 0;
if (!cpu_list)
return read_all_cpu_map();
if (!isdigit(*cpu_list))
goto invalid;
while (isdigit(*cpu_list)) {
p = NULL;
start_cpu = strtoul(cpu_list, &p, 0);
if (start_cpu >= INT_MAX
|| (*p != '\0' && *p != ',' && *p != '-'))
goto invalid;
if (*p == '-') {
cpu_list = ++p;
p = NULL;
end_cpu = strtoul(cpu_list, &p, 0);
if (end_cpu >= INT_MAX || (*p != '\0' && *p != ','))
goto invalid;
if (end_cpu < start_cpu)
goto invalid;
} else {
end_cpu = start_cpu;
}
for (; start_cpu <= end_cpu; start_cpu++) {
/* check for duplicates */
for (i = 0; i < nr_cpus; i++)
if (cpumap[i] == (int)start_cpu)
goto invalid;
assert(nr_cpus < MAX_NR_CPUS);
cpumap[nr_cpus++] = (int)start_cpu;
}
if (*p)
++p;
cpu_list = p;
}
if (nr_cpus > 0)
return nr_cpus;
return default_cpu_map();
invalid:
return -1;
}
#ifndef __PERF_CPUMAP_H
#define __PERF_CPUMAP_H
extern int read_cpu_map(void);
extern int read_cpu_map(const char *cpu_list);
extern int cpumap[];
#endif /* __PERF_CPUMAP_H */
......@@ -655,11 +655,36 @@ static void dso__calc_col_width(struct dso *self)
}
int event__preprocess_sample(const event_t *self, struct perf_session *session,
struct addr_location *al, symbol_filter_t filter)
struct addr_location *al, struct sample_data *data,
symbol_filter_t filter)
{
u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
struct thread *thread = perf_session__findnew(session, self->ip.pid);
struct thread *thread;
event__parse_sample(self, session->sample_type, data);
dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld cpu:%d\n",
self->header.misc, data->pid, data->tid, data->ip,
data->period, data->cpu);
if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
unsigned int i;
dump_printf("... chain: nr:%Lu\n", data->callchain->nr);
if (!ip_callchain__valid(data->callchain, self)) {
pr_debug("call-chain problem with event, "
"skipping it.\n");
goto out_filtered;
}
if (dump_trace) {
for (i = 0; i < data->callchain->nr; i++)
dump_printf("..... %2d: %016Lx\n",
i, data->callchain->ips[i]);
}
}
thread = perf_session__findnew(session, self->ip.pid);
if (thread == NULL)
return -1;
......@@ -685,6 +710,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
al->map ? al->map->dso->long_name :
al->level == 'H' ? "[hypervisor]" : "<not found>");
al->sym = NULL;
al->cpu = data->cpu;
if (al->map) {
if (symbol_conf.dso_list &&
......@@ -724,9 +750,9 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
return 0;
}
int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
int event__parse_sample(const event_t *event, u64 type, struct sample_data *data)
{
u64 *array = event->sample.array;
const u64 *array = event->sample.array;
if (type & PERF_SAMPLE_IP) {
data->ip = event->ip.ip;
......@@ -765,7 +791,8 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
u32 *p = (u32 *)array;
data->cpu = *p;
array++;
}
} else
data->cpu = -1;
if (type & PERF_SAMPLE_PERIOD) {
data->period = *array;
......
......@@ -157,8 +157,9 @@ int event__process_task(event_t *self, struct perf_session *session);
struct addr_location;
int event__preprocess_sample(const event_t *self, struct perf_session *session,
struct addr_location *al, symbol_filter_t filter);
int event__parse_sample(event_t *event, u64 type, struct sample_data *data);
struct addr_location *al, struct sample_data *data,
symbol_filter_t filter);
int event__parse_sample(const event_t *event, u64 type, struct sample_data *data);
extern const char *event__name[];
......
......@@ -385,8 +385,7 @@ static int perf_session__cache_build_ids(struct perf_session *self)
int ret;
char debugdir[PATH_MAX];
snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
DEBUG_CACHE_DIR);
snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
return -1;
......
......@@ -70,6 +70,7 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.map = al->map,
.sym = al->sym,
},
.cpu = al->cpu,
.ip = al->addr,
.level = al->level,
.period = period,
......@@ -1037,7 +1038,7 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
dso, dso->long_name, sym, sym->name);
snprintf(command, sizeof(command),
"objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s|grep -v %s|expand",
"objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
map__rip_2objdump(map, sym->start),
map__rip_2objdump(map, sym->end),
filename, filename);
......
......@@ -13,6 +13,7 @@ enum sort_type sort__first_dimension;
unsigned int dsos__col_width;
unsigned int comms__col_width;
unsigned int threads__col_width;
unsigned int cpus__col_width;
static unsigned int parent_symbol__col_width;
char * field_sep;
......@@ -28,6 +29,8 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width);
static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width);
static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width);
struct sort_entry sort_thread = {
.se_header = "Command: Pid",
......@@ -64,6 +67,13 @@ struct sort_entry sort_parent = {
.se_width = &parent_symbol__col_width,
};
struct sort_entry sort_cpu = {
.se_header = "CPU",
.se_cmp = sort__cpu_cmp,
.se_snprintf = hist_entry__cpu_snprintf,
.se_width = &cpus__col_width,
};
struct sort_dimension {
const char *name;
struct sort_entry *entry;
......@@ -76,6 +86,7 @@ static struct sort_dimension sort_dimensions[] = {
{ .name = "dso", .entry = &sort_dso, },
{ .name = "symbol", .entry = &sort_sym, },
{ .name = "parent", .entry = &sort_parent, },
{ .name = "cpu", .entry = &sort_cpu, },
};
int64_t cmp_null(void *l, void *r)
......@@ -242,6 +253,20 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
self->parent ? self->parent->name : "[other]");
}
/* --sort cpu */
int64_t
sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
{
return right->cpu - left->cpu;
}
static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
}
int sort_dimension__add(const char *tok)
{
unsigned int i;
......@@ -281,6 +306,8 @@ int sort_dimension__add(const char *tok)
sort__first_dimension = SORT_SYM;
else if (!strcmp(sd->name, "parent"))
sort__first_dimension = SORT_PARENT;
else if (!strcmp(sd->name, "cpu"))
sort__first_dimension = SORT_CPU;
}
list_add_tail(&sd->entry->list, &hist_entry__sort_list);
......
......@@ -39,6 +39,7 @@ extern struct sort_entry sort_parent;
extern unsigned int dsos__col_width;
extern unsigned int comms__col_width;
extern unsigned int threads__col_width;
extern unsigned int cpus__col_width;
extern enum sort_type sort__first_dimension;
struct hist_entry {
......@@ -51,6 +52,7 @@ struct hist_entry {
struct map_symbol ms;
struct thread *thread;
u64 ip;
s32 cpu;
u32 nr_events;
char level;
u8 filtered;
......@@ -68,7 +70,8 @@ enum sort_type {
SORT_COMM,
SORT_DSO,
SORT_SYM,
SORT_PARENT
SORT_PARENT,
SORT_CPU,
};
/*
......@@ -104,6 +107,7 @@ extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
int64_t sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right);
extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
extern int sort_dimension__add(const char *);
void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
......
......@@ -9,8 +9,6 @@
#include <linux/rbtree.h>
#include <stdio.h>
#define DEBUG_CACHE_DIR ".debug"
#ifdef HAVE_CPLUS_DEMANGLE
extern char *cplus_demangle(const char *, int);
......@@ -112,7 +110,8 @@ struct addr_location {
u64 addr;
char level;
bool filtered;
unsigned int cpumode;
u8 cpumode;
s32 cpu;
};
enum dso_kernel_type {
......
......@@ -89,6 +89,7 @@
extern const char *graph_line;
extern const char *graph_dotted_line;
extern char buildid_dir[];
/* On most systems <limits.h> would have given us this, but
* not on some systems (e.g. GNU/Hurd).
......@@ -152,6 +153,7 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)))
extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
extern int prefixcmp(const char *str, const char *prefix);
extern void set_buildid_dir(void);
static inline const char *skip_prefix(const char *str, const char *prefix)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment