Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
This commit is contained in:
commit
becf6c97a3
4
Makefile
4
Makefile
@ -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,13 +111,38 @@ 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
|
||||
@echo ' rpm-pkg - Build both source and binary RPM kernel packages'
|
||||
@echo ' binrpm-pkg - Build only the binary kernel package'
|
||||
@echo ' deb-pkg - Build the kernel as an deb package'
|
||||
@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 ' rpm-pkg - Build both source and binary RPM kernel packages'
|
||||
@echo ' binrpm-pkg - Build only the binary kernel package'
|
||||
@echo ' deb-pkg - Build the kernel as an deb package'
|
||||
@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>::
|
||||
|
12
tools/perf/MANIFEST
Normal file
12
tools/perf/MANIFEST
Normal file
@ -0,0 +1,12 @@
|
||||
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 @@ try_again:
|
||||
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;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#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 @@ out_filtered:
|
||||
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 @@ fallback:
|
||||
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",
|
||||
@ -63,6 +66,13 @@ struct sort_entry sort_parent = {
|
||||
.se_snprintf = hist_entry__parent_snprintf,
|
||||
.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;
|
||||
@ -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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user