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 ...@@ -411,7 +411,7 @@ endif
no-dot-config-targets := clean mrproper distclean \ no-dot-config-targets := clean mrproper distclean \
cscope TAGS tags help %docs check% \ cscope TAGS tags help %docs check% \
include/linux/version.h headers_% \ include/linux/version.h headers_% \
kernelrelease kernelversion kernelrelease kernelversion %src-pkg
config-targets := 0 config-targets := 0
mixed-targets := 0 mixed-targets := 0
...@@ -1215,6 +1215,8 @@ distclean: mrproper ...@@ -1215,6 +1215,8 @@ distclean: mrproper
# rpm target kept for backward compatibility # rpm target kept for backward compatibility
package-dir := $(srctree)/scripts/package package-dir := $(srctree)/scripts/package
%src-pkg: FORCE
$(Q)$(MAKE) $(build)=$(package-dir) $@
%pkg: include/config/kernel.release FORCE %pkg: include/config/kernel.release FORCE
$(Q)$(MAKE) $(build)=$(package-dir) $@ $(Q)$(MAKE) $(build)=$(package-dir) $@
rpm: include/config/kernel.release FORCE rpm: include/config/kernel.release FORCE
......
...@@ -111,13 +111,38 @@ tar%pkg: FORCE ...@@ -111,13 +111,38 @@ tar%pkg: FORCE
clean-dirs += $(objtree)/tar-install/ 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 text displayed when executing 'make help'
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
help: FORCE help: FORCE
@echo ' rpm-pkg - Build both source and binary RPM kernel packages' @echo ' rpm-pkg - Build both source and binary RPM kernel packages'
@echo ' binrpm-pkg - Build only the binary kernel package' @echo ' binrpm-pkg - Build only the binary kernel package'
@echo ' deb-pkg - Build the kernel as an deb package' @echo ' deb-pkg - Build the kernel as an deb package'
@echo ' tar-pkg - Build the kernel as an uncompressed tarball' @echo ' tar-pkg - Build the kernel as an uncompressed tarball'
@echo ' targz-pkg - Build the kernel as a gzip compressed tarball' @echo ' targz-pkg - Build the kernel as a gzip compressed tarball'
@echo ' tarbz2-pkg - Build the kernel as a bzip2 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 ...@@ -103,6 +103,13 @@ OPTIONS
--raw-samples:: --raw-samples::
Collect raw sample records from all opened counters (default for tracepoint counters). 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 SEE ALSO
-------- --------
linkperf:perf-stat[1], linkperf:perf-list[1] linkperf:perf-stat[1], linkperf:perf-list[1]
...@@ -46,6 +46,13 @@ OPTIONS ...@@ -46,6 +46,13 @@ OPTIONS
-B:: -B::
print large numbers with thousands' separators according to locale 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 EXAMPLES
-------- --------
......
...@@ -25,9 +25,11 @@ OPTIONS ...@@ -25,9 +25,11 @@ OPTIONS
--count=<count>:: --count=<count>::
Event period to sample. Event period to sample.
-C <cpu>:: -C <cpu-list>::
--CPU=<cpu>:: --cpu=<cpu>::
CPU to profile. 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>:: -d <seconds>::
--delay=<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) ...@@ -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) static int process_sample_event(event_t *event, struct perf_session *session)
{ {
struct addr_location al; struct addr_location al;
struct sample_data data;
dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc, if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
event->ip.pid, event->ip.ip);
if (event__preprocess_sample(event, session, &al, NULL) < 0) {
pr_warning("problem processing %d event, skipping it.\n", pr_warning("problem processing %d event, skipping it.\n",
event->header.type); event->header.type);
return -1; return -1;
......
...@@ -78,8 +78,7 @@ static int __cmd_buildid_cache(void) ...@@ -78,8 +78,7 @@ static int __cmd_buildid_cache(void)
struct str_node *pos; struct str_node *pos;
char debugdir[PATH_MAX]; char debugdir[PATH_MAX];
snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
DEBUG_CACHE_DIR);
if (add_name_list_str) { if (add_name_list_str) {
list = strlist__new(true, 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 ...@@ -35,10 +35,7 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
struct addr_location al; struct addr_location al;
struct sample_data data = { .period = 1, }; struct sample_data data = { .period = 1, };
dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc, if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
event->ip.pid, event->ip.ip);
if (event__preprocess_sample(event, session, &al, NULL) < 0) {
pr_warning("problem processing %d event, skipping it.\n", pr_warning("problem processing %d event, skipping it.\n",
event->header.type); event->header.type);
return -1; return -1;
...@@ -47,8 +44,6 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi ...@@ -47,8 +44,6 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
if (al.filtered || al.sym == NULL) if (al.filtered || al.sym == NULL)
return 0; return 0;
event__parse_sample(event, session->sample_type, &data);
if (hists__add_entry(&session->hists, &al, data.period)) { if (hists__add_entry(&session->hists, &al, data.period)) {
pr_warning("problem incrementing symbol period, skipping event\n"); pr_warning("problem incrementing symbol period, skipping event\n");
return -1; return -1;
......
...@@ -49,7 +49,6 @@ static int group = 0; ...@@ -49,7 +49,6 @@ static int group = 0;
static int realtime_prio = 0; static int realtime_prio = 0;
static bool raw_samples = false; static bool raw_samples = false;
static bool system_wide = false; static bool system_wide = false;
static int profile_cpu = -1;
static pid_t target_pid = -1; static pid_t target_pid = -1;
static pid_t target_tid = -1; static pid_t target_tid = -1;
static pid_t *all_tids = NULL; static pid_t *all_tids = NULL;
...@@ -74,6 +73,7 @@ static int file_new = 1; ...@@ -74,6 +73,7 @@ static int file_new = 1;
static off_t post_processing_offset; static off_t post_processing_offset;
static struct perf_session *session; static struct perf_session *session;
static const char *cpu_list;
struct mmap_data { struct mmap_data {
int counter; int counter;
...@@ -274,6 +274,9 @@ static void create_counter(int counter, int cpu) ...@@ -274,6 +274,9 @@ static void create_counter(int counter, int cpu)
if (call_graph) if (call_graph)
attr->sample_type |= PERF_SAMPLE_CALLCHAIN; attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
if (system_wide)
attr->sample_type |= PERF_SAMPLE_CPU;
if (raw_samples) { if (raw_samples) {
attr->sample_type |= PERF_SAMPLE_TIME; attr->sample_type |= PERF_SAMPLE_TIME;
attr->sample_type |= PERF_SAMPLE_RAW; attr->sample_type |= PERF_SAMPLE_RAW;
...@@ -300,7 +303,7 @@ static void create_counter(int counter, int cpu) ...@@ -300,7 +303,7 @@ static void create_counter(int counter, int cpu)
die("Permission error - are you root?\n" die("Permission error - are you root?\n"
"\t Consider tweaking" "\t Consider tweaking"
" /proc/sys/kernel/perf_event_paranoid.\n"); " /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" die("No such device - did you specify"
" an out-of-range profile CPU?\n"); " an out-of-range profile CPU?\n");
} }
...@@ -622,10 +625,15 @@ static int __cmd_record(int argc, const char **argv) ...@@ -622,10 +625,15 @@ static int __cmd_record(int argc, const char **argv)
close(child_ready_pipe[0]); close(child_ready_pipe[0]);
} }
if ((!system_wide && no_inherit) || profile_cpu != -1) { nr_cpus = read_cpu_map(cpu_list);
open_counters(profile_cpu); 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 { } else {
nr_cpus = read_cpu_map();
for (i = 0; i < nr_cpus; i++) for (i = 0; i < nr_cpus; i++)
open_counters(cpumap[i]); open_counters(cpumap[i]);
} }
...@@ -704,7 +712,7 @@ static int __cmd_record(int argc, const char **argv) ...@@ -704,7 +712,7 @@ static int __cmd_record(int argc, const char **argv)
if (perf_guest) if (perf_guest)
perf_session__process_machines(session, event__synthesize_guest_os); 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, event__synthesize_thread(target_tid, process_synthesized_event,
session); session);
else else
...@@ -794,8 +802,8 @@ static const struct option options[] = { ...@@ -794,8 +802,8 @@ static const struct option options[] = {
"system-wide collection from all CPUs"), "system-wide collection from all CPUs"),
OPT_BOOLEAN('A', "append", &append_file, OPT_BOOLEAN('A', "append", &append_file,
"append to the output file to do incremental profiling"), "append to the output file to do incremental profiling"),
OPT_INTEGER('C', "profile_cpu", &profile_cpu, OPT_STRING('C', "cpu", &cpu_list, "cpu",
"CPU to profile on"), "list of cpus to monitor"),
OPT_BOOLEAN('f', "force", &force, OPT_BOOLEAN('f', "force", &force,
"overwrite existing data file (deprecated)"), "overwrite existing data file (deprecated)"),
OPT_U64('c', "count", &user_interval, "event period to sample"), 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) ...@@ -825,7 +833,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
argc = parse_options(argc, argv, options, record_usage, argc = parse_options(argc, argv, options, record_usage,
PARSE_OPT_STOP_AT_NON_OPTION); PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc && target_pid == -1 && target_tid == -1 && if (!argc && target_pid == -1 && target_tid == -1 &&
!system_wide && profile_cpu == -1) !system_wide && !cpu_list)
usage_with_options(record_usage, options); usage_with_options(record_usage, options);
if (force && append_file) { if (force && append_file) {
......
...@@ -155,30 +155,7 @@ static int process_sample_event(event_t *event, struct perf_session *session) ...@@ -155,30 +155,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
struct addr_location al; struct addr_location al;
struct perf_event_attr *attr; struct perf_event_attr *attr;
event__parse_sample(event, session->sample_type, &data); if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
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) {
fprintf(stderr, "problem processing %d event, skipping it.\n", fprintf(stderr, "problem processing %d event, skipping it.\n",
event->header.type); event->header.type);
return -1; return -1;
......
...@@ -69,7 +69,7 @@ static struct perf_event_attr default_attrs[] = { ...@@ -69,7 +69,7 @@ static struct perf_event_attr default_attrs[] = {
}; };
static bool system_wide = false; static bool system_wide = false;
static unsigned int nr_cpus = 0; static int nr_cpus = 0;
static int run_idx = 0; static int run_idx = 0;
static int run_count = 1; static int run_count = 1;
...@@ -82,6 +82,7 @@ static int thread_num = 0; ...@@ -82,6 +82,7 @@ static int thread_num = 0;
static pid_t child_pid = -1; static pid_t child_pid = -1;
static bool null_run = false; static bool null_run = false;
static bool big_num = false; static bool big_num = false;
static const char *cpu_list;
static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
...@@ -158,7 +159,7 @@ static int create_perf_stat_counter(int counter) ...@@ -158,7 +159,7 @@ static int create_perf_stat_counter(int counter)
PERF_FORMAT_TOTAL_TIME_RUNNING; PERF_FORMAT_TOTAL_TIME_RUNNING;
if (system_wide) { if (system_wide) {
unsigned int cpu; int cpu;
for (cpu = 0; cpu < nr_cpus; cpu++) { for (cpu = 0; cpu < nr_cpus; cpu++) {
fd[cpu][counter][0] = sys_perf_event_open(attr, fd[cpu][counter][0] = sys_perf_event_open(attr,
...@@ -208,7 +209,7 @@ static inline int nsec_counter(int counter) ...@@ -208,7 +209,7 @@ static inline int nsec_counter(int counter)
static void read_counter(int counter) static void read_counter(int counter)
{ {
u64 count[3], single_count[3]; u64 count[3], single_count[3];
unsigned int cpu; int cpu;
size_t res, nv; size_t res, nv;
int scaled; int scaled;
int i, thread; int i, thread;
...@@ -542,6 +543,8 @@ static const struct option options[] = { ...@@ -542,6 +543,8 @@ static const struct option options[] = {
"null run - dont start any counters"), "null run - dont start any counters"),
OPT_BOOLEAN('B', "big-num", &big_num, OPT_BOOLEAN('B', "big-num", &big_num,
"print large numbers with thousands\' separators"), "print large numbers with thousands\' separators"),
OPT_STRING('C', "cpu", &cpu_list, "cpu",
"list of cpus to monitor in system-wide"),
OPT_END() OPT_END()
}; };
...@@ -566,10 +569,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) ...@@ -566,10 +569,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
} }
if (system_wide) if (system_wide)
nr_cpus = read_cpu_map(); nr_cpus = read_cpu_map(cpu_list);
else else
nr_cpus = 1; nr_cpus = 1;
if (nr_cpus < 1)
usage_with_options(stat_usage, options);
if (target_pid != -1) { if (target_pid != -1) {
target_tid = target_pid; target_tid = target_pid;
thread_num = find_all_tid(target_pid, &all_tids); thread_num = find_all_tid(target_pid, &all_tids);
......
...@@ -102,6 +102,7 @@ struct sym_entry *sym_filter_entry_sched = NULL; ...@@ -102,6 +102,7 @@ struct sym_entry *sym_filter_entry_sched = NULL;
static int sym_pcnt_filter = 5; static int sym_pcnt_filter = 5;
static int sym_counter = 0; static int sym_counter = 0;
static int display_weighted = -1; static int display_weighted = -1;
static const char *cpu_list;
/* /*
* Symbols * Symbols
...@@ -982,6 +983,7 @@ static void event__process_sample(const event_t *self, ...@@ -982,6 +983,7 @@ static void event__process_sample(const event_t *self,
u64 ip = self->ip.ip; u64 ip = self->ip.ip;
struct sym_entry *syme; struct sym_entry *syme;
struct addr_location al; struct addr_location al;
struct sample_data data;
struct machine *machine; struct machine *machine;
u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
...@@ -1024,7 +1026,8 @@ static void event__process_sample(const event_t *self, ...@@ -1024,7 +1026,8 @@ static void event__process_sample(const event_t *self,
if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) if (self->header.misc & PERF_RECORD_MISC_EXACT_IP)
exact_samples++; 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) al.filtered)
return; return;
...@@ -1351,8 +1354,8 @@ static const struct option options[] = { ...@@ -1351,8 +1354,8 @@ static const struct option options[] = {
"profile events on existing thread id"), "profile events on existing thread id"),
OPT_BOOLEAN('a', "all-cpus", &system_wide, OPT_BOOLEAN('a', "all-cpus", &system_wide,
"system-wide collection from all CPUs"), "system-wide collection from all CPUs"),
OPT_INTEGER('C', "CPU", &profile_cpu, OPT_STRING('C', "cpu", &cpu_list, "cpu",
"CPU to profile on"), "list of cpus to monitor"),
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
"file", "vmlinux pathname"), "file", "vmlinux pathname"),
OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, 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) ...@@ -1428,10 +1431,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
return -ENOMEM; return -ENOMEM;
/* CPU and PID are mutually exclusive */ /* 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"); printf("WARNING: PID switch overriding CPU\n");
sleep(1); sleep(1);
profile_cpu = -1; cpu_list = NULL;
} }
if (!nr_counters) if (!nr_counters)
...@@ -1469,10 +1472,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) ...@@ -1469,10 +1472,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
attrs[counter].sample_period = default_interval; attrs[counter].sample_period = default_interval;
} }
if (target_tid != -1 || profile_cpu != -1) if (target_tid != -1)
nr_cpus = 1; nr_cpus = 1;
else 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); get_term_dimensions(&winsize);
if (print_entries == 0) { if (print_entries == 0) {
......
...@@ -7,7 +7,17 @@ if [ $# -ne 0 ] ; then ...@@ -7,7 +7,17 @@ if [ $# -ne 0 ] ; then
PERF_DATA=$1 PERF_DATA=$1
fi 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) BUILDIDS=$(mktemp /tmp/perf-archive-buildids.XXXXXX)
NOBUILDID=0000000000000000000000000000000000000000 NOBUILDID=0000000000000000000000000000000000000000
...@@ -22,13 +32,13 @@ MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX) ...@@ -22,13 +32,13 @@ MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX)
cut -d ' ' -f 1 $BUILDIDS | \ cut -d ' ' -f 1 $BUILDIDS | \
while read build_id ; do 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) filename=$(readlink -f $linkname)
echo ${linkname#$DEBUGDIR} >> $MANIFEST echo ${linkname#$PERF_BUILDID_DIR} >> $MANIFEST
echo ${filename#$DEBUGDIR} >> $MANIFEST echo ${filename#$PERF_BUILDID_DIR} >> $MANIFEST
done 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 rm -f $MANIFEST $BUILDIDS
echo -e "Now please run:\n" echo -e "Now please run:\n"
echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n" echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n"
......
...@@ -458,6 +458,8 @@ int main(int argc, const char **argv) ...@@ -458,6 +458,8 @@ int main(int argc, const char **argv)
handle_options(&argv, &argc, NULL); handle_options(&argv, &argc, NULL);
commit_pager_choice(); commit_pager_choice();
set_debugfs_path(); set_debugfs_path();
set_buildid_dir();
if (argc > 0) { if (argc > 0) {
if (!prefixcmp(argv[0], "--")) if (!prefixcmp(argv[0], "--"))
argv[0] += 2; argv[0] += 2;
......
...@@ -43,19 +43,17 @@ struct perf_event_ops build_id__mark_dso_hit_ops = { ...@@ -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 *dso__build_id_filename(struct dso *self, char *bf, size_t size)
{ {
char build_id_hex[BUILD_ID_SIZE * 2 + 1]; char build_id_hex[BUILD_ID_SIZE * 2 + 1];
const char *home;
if (!self->has_build_id) if (!self->has_build_id)
return NULL; return NULL;
build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex); build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex);
home = getenv("HOME");
if (bf == NULL) { if (bf == NULL) {
if (asprintf(&bf, "%s/%s/.build-id/%.2s/%s", home, if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir,
DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2) < 0) build_id_hex, build_id_hex + 2) < 0)
return NULL; return NULL;
} else } else
snprintf(bf, size, "%s/%s/.build-id/%.2s/%s", home, snprintf(bf, size, "%s/.build-id/%.2s/%s", buildid_dir,
DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2); build_id_hex, build_id_hex + 2);
return bf; return bf;
} }
...@@ -23,6 +23,7 @@ extern int perf_config(config_fn_t fn, void *); ...@@ -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_int(const char *, const char *);
extern int perf_config_bool(const char *, const char *); extern int perf_config_bool(const char *, const char *);
extern int config_error_nonbool(const char *); extern int config_error_nonbool(const char *);
extern const char *perf_config_dirname(const char *, const char *);
/* pager.c */ /* pager.c */
extern void setup_pager(void); extern void setup_pager(void);
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include "util.h" #include "util.h"
#include "callchain.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; unsigned int chain_size = event->header.size;
chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
......
...@@ -60,5 +60,5 @@ int register_callchain_param(struct callchain_param *param); ...@@ -60,5 +60,5 @@ int register_callchain_param(struct callchain_param *param);
int append_chain(struct callchain_node *root, struct ip_callchain *chain, int append_chain(struct callchain_node *root, struct ip_callchain *chain,
struct map_symbol *syms); 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 */ #endif /* __PERF_CALLCHAIN_H */
...@@ -11,6 +11,11 @@ ...@@ -11,6 +11,11 @@
#define MAXNAME (256) #define MAXNAME (256)
#define DEBUG_CACHE_DIR ".debug"
char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
static FILE *config_file; static FILE *config_file;
static const char *config_file_name; static const char *config_file_name;
static int config_linenr; static int config_linenr;
...@@ -127,7 +132,7 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) ...@@ -127,7 +132,7 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
break; break;
if (!iskeychar(c)) if (!iskeychar(c))
break; break;
name[len++] = tolower(c); name[len++] = c;
if (len >= MAXNAME) if (len >= MAXNAME)
return -1; return -1;
} }
...@@ -327,6 +332,13 @@ int perf_config_bool(const char *name, const char *value) ...@@ -327,6 +332,13 @@ int perf_config_bool(const char *name, const char *value)
return !!perf_config_bool_or_int(name, value, &discard); 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) static int perf_default_core_config(const char *var __used, const char *value __used)
{ {
/* Add other config variables here and to Documentation/config.txt. */ /* Add other config variables here and to Documentation/config.txt. */
...@@ -428,3 +440,53 @@ int config_error_nonbool(const char *var) ...@@ -428,3 +440,53 @@ int config_error_nonbool(const char *var)
{ {
return error("Missing value for '%s'", 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) ...@@ -20,7 +20,7 @@ static int default_cpu_map(void)
return nr_cpus; return nr_cpus;
} }
int read_cpu_map(void) static int read_all_cpu_map(void)
{ {
FILE *onlnf; FILE *onlnf;
int nr_cpus = 0; int nr_cpus = 0;
...@@ -57,3 +57,58 @@ int read_cpu_map(void) ...@@ -57,3 +57,58 @@ int read_cpu_map(void)
return default_cpu_map(); 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 #ifndef __PERF_CPUMAP_H
#define __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[]; extern int cpumap[];
#endif /* __PERF_CPUMAP_H */ #endif /* __PERF_CPUMAP_H */
...@@ -655,11 +655,36 @@ static void dso__calc_col_width(struct dso *self) ...@@ -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, 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; 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) if (thread == NULL)
return -1; return -1;
...@@ -685,6 +710,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session, ...@@ -685,6 +710,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
al->map ? al->map->dso->long_name : al->map ? al->map->dso->long_name :
al->level == 'H' ? "[hypervisor]" : "<not found>"); al->level == 'H' ? "[hypervisor]" : "<not found>");
al->sym = NULL; al->sym = NULL;
al->cpu = data->cpu;
if (al->map) { if (al->map) {
if (symbol_conf.dso_list && if (symbol_conf.dso_list &&
...@@ -724,9 +750,9 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session, ...@@ -724,9 +750,9 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
return 0; 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) { if (type & PERF_SAMPLE_IP) {
data->ip = event->ip.ip; data->ip = event->ip.ip;
...@@ -765,7 +791,8 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data) ...@@ -765,7 +791,8 @@ int event__parse_sample(event_t *event, u64 type, struct sample_data *data)
u32 *p = (u32 *)array; u32 *p = (u32 *)array;
data->cpu = *p; data->cpu = *p;
array++; array++;
} } else
data->cpu = -1;
if (type & PERF_SAMPLE_PERIOD) { if (type & PERF_SAMPLE_PERIOD) {
data->period = *array; data->period = *array;
......
...@@ -157,8 +157,9 @@ int event__process_task(event_t *self, struct perf_session *session); ...@@ -157,8 +157,9 @@ int event__process_task(event_t *self, struct perf_session *session);
struct addr_location; struct addr_location;
int event__preprocess_sample(const event_t *self, struct perf_session *session, 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,
int event__parse_sample(event_t *event, u64 type, 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[]; extern const char *event__name[];
......
...@@ -385,8 +385,7 @@ static int perf_session__cache_build_ids(struct perf_session *self) ...@@ -385,8 +385,7 @@ static int perf_session__cache_build_ids(struct perf_session *self)
int ret; int ret;
char debugdir[PATH_MAX]; char debugdir[PATH_MAX];
snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
DEBUG_CACHE_DIR);
if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
return -1; return -1;
......
...@@ -70,6 +70,7 @@ struct hist_entry *__hists__add_entry(struct hists *self, ...@@ -70,6 +70,7 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.map = al->map, .map = al->map,
.sym = al->sym, .sym = al->sym,
}, },
.cpu = al->cpu,
.ip = al->addr, .ip = al->addr,
.level = al->level, .level = al->level,
.period = period, .period = period,
...@@ -1037,7 +1038,7 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) ...@@ -1037,7 +1038,7 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
dso, dso->long_name, sym, sym->name); dso, dso->long_name, sym, sym->name);
snprintf(command, sizeof(command), 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->start),
map__rip_2objdump(map, sym->end), map__rip_2objdump(map, sym->end),
filename, filename); filename, filename);
......
...@@ -13,6 +13,7 @@ enum sort_type sort__first_dimension; ...@@ -13,6 +13,7 @@ enum sort_type sort__first_dimension;
unsigned int dsos__col_width; unsigned int dsos__col_width;
unsigned int comms__col_width; unsigned int comms__col_width;
unsigned int threads__col_width; unsigned int threads__col_width;
unsigned int cpus__col_width;
static unsigned int parent_symbol__col_width; static unsigned int parent_symbol__col_width;
char * field_sep; char * field_sep;
...@@ -28,6 +29,8 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, ...@@ -28,6 +29,8 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width); size_t size, unsigned int width);
static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width); 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 = { struct sort_entry sort_thread = {
.se_header = "Command: Pid", .se_header = "Command: Pid",
...@@ -63,6 +66,13 @@ struct sort_entry sort_parent = { ...@@ -63,6 +66,13 @@ struct sort_entry sort_parent = {
.se_snprintf = hist_entry__parent_snprintf, .se_snprintf = hist_entry__parent_snprintf,
.se_width = &parent_symbol__col_width, .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 { struct sort_dimension {
const char *name; const char *name;
...@@ -76,6 +86,7 @@ static struct sort_dimension sort_dimensions[] = { ...@@ -76,6 +86,7 @@ static struct sort_dimension sort_dimensions[] = {
{ .name = "dso", .entry = &sort_dso, }, { .name = "dso", .entry = &sort_dso, },
{ .name = "symbol", .entry = &sort_sym, }, { .name = "symbol", .entry = &sort_sym, },
{ .name = "parent", .entry = &sort_parent, }, { .name = "parent", .entry = &sort_parent, },
{ .name = "cpu", .entry = &sort_cpu, },
}; };
int64_t cmp_null(void *l, void *r) int64_t cmp_null(void *l, void *r)
...@@ -242,6 +253,20 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, ...@@ -242,6 +253,20 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
self->parent ? self->parent->name : "[other]"); 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) int sort_dimension__add(const char *tok)
{ {
unsigned int i; unsigned int i;
...@@ -281,6 +306,8 @@ int sort_dimension__add(const char *tok) ...@@ -281,6 +306,8 @@ int sort_dimension__add(const char *tok)
sort__first_dimension = SORT_SYM; sort__first_dimension = SORT_SYM;
else if (!strcmp(sd->name, "parent")) else if (!strcmp(sd->name, "parent"))
sort__first_dimension = SORT_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); list_add_tail(&sd->entry->list, &hist_entry__sort_list);
......
...@@ -39,6 +39,7 @@ extern struct sort_entry sort_parent; ...@@ -39,6 +39,7 @@ extern struct sort_entry sort_parent;
extern unsigned int dsos__col_width; extern unsigned int dsos__col_width;
extern unsigned int comms__col_width; extern unsigned int comms__col_width;
extern unsigned int threads__col_width; extern unsigned int threads__col_width;
extern unsigned int cpus__col_width;
extern enum sort_type sort__first_dimension; extern enum sort_type sort__first_dimension;
struct hist_entry { struct hist_entry {
...@@ -51,6 +52,7 @@ struct hist_entry { ...@@ -51,6 +52,7 @@ struct hist_entry {
struct map_symbol ms; struct map_symbol ms;
struct thread *thread; struct thread *thread;
u64 ip; u64 ip;
s32 cpu;
u32 nr_events; u32 nr_events;
char level; char level;
u8 filtered; u8 filtered;
...@@ -68,7 +70,8 @@ enum sort_type { ...@@ -68,7 +70,8 @@ enum sort_type {
SORT_COMM, SORT_COMM,
SORT_DSO, SORT_DSO,
SORT_SYM, SORT_SYM,
SORT_PARENT SORT_PARENT,
SORT_CPU,
}; };
/* /*
...@@ -104,6 +107,7 @@ extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *); ...@@ -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__dso_cmp(struct hist_entry *, struct hist_entry *);
extern int64_t sort__sym_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 *); 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 size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
extern int sort_dimension__add(const char *); extern int sort_dimension__add(const char *);
void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
......
...@@ -9,8 +9,6 @@ ...@@ -9,8 +9,6 @@
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include <stdio.h> #include <stdio.h>
#define DEBUG_CACHE_DIR ".debug"
#ifdef HAVE_CPLUS_DEMANGLE #ifdef HAVE_CPLUS_DEMANGLE
extern char *cplus_demangle(const char *, int); extern char *cplus_demangle(const char *, int);
...@@ -112,7 +110,8 @@ struct addr_location { ...@@ -112,7 +110,8 @@ struct addr_location {
u64 addr; u64 addr;
char level; char level;
bool filtered; bool filtered;
unsigned int cpumode; u8 cpumode;
s32 cpu;
}; };
enum dso_kernel_type { enum dso_kernel_type {
......
...@@ -89,6 +89,7 @@ ...@@ -89,6 +89,7 @@
extern const char *graph_line; extern const char *graph_line;
extern const char *graph_dotted_line; extern const char *graph_dotted_line;
extern char buildid_dir[];
/* On most systems <limits.h> would have given us this, but /* On most systems <limits.h> would have given us this, but
* not on some systems (e.g. GNU/Hurd). * not on some systems (e.g. GNU/Hurd).
...@@ -152,6 +153,7 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))) ...@@ -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 void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
extern int prefixcmp(const char *str, const char *prefix); 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) 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