2010-06-02 20:41:42

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [GIT PULL 0/4] Perf improvements for .36 (perf/core)

From: Arnaldo Carvalho de Melo <[email protected]>

Hi Ingo,

Please pull from:

git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 perf/core

I'll keep perf/urgent for .35 stuff, perf/core now has only things
for .36 and I'm merging perf/urgent into perf/core when you pull from it.

Regards,

- Arnaldo

Arnaldo Carvalho de Melo (1):
perf tools: Make target to generate self contained source tarball

Stephane Eranian (3):
perf report: Make -D print sampled CPU
perf tools: Add the ability to specify list of cpus to monitor
perf buildid: add perfconfig option to specify buildid cache dir


2010-06-02 20:40:36

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 4/4] perf buildid: add perfconfig option to specify buildid cache dir

From: Stephane Eranian <[email protected]>

This patch adds the ability to specify an alternate directory to store the
buildid cache (buildids, copy of binaries). By default, it is hardcoded to
$HOME/.debug. This directory contains immutable data. The layout of the
directory is such that no conflicts in filenames are possible. A modification
in a file, yields a different buildid and thus a different location in the
subdir hierarchy.

You may want to put the buildid cache elsewhere because of disk space
limitation or simply to share the cache between users. It is also useful for
remote collect vs. local analysis of profiles.

This patch adds a new config option to the perfconfig file. Under the tag
'buildid', there is a dir option. For instance, if you have:

$ cat /etc/perfconfig
[buildid]
dir = /var/cache/perf-buildid

All buildids and binaries are be saved in the directory specified. The perf
record, buildid-list, buildid-cache, report, annotate, and archive commands
will it to pull information out.

The option can be set in the system-wide perfconfig file or in the
$HOME/.perfconfig file.

Cc: David S. Miller <[email protected]>
Cc: Frédéric Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Tom Zanussi <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Stephane Eranian <[email protected]>

--
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-buildid-cache.c | 3 +-
tools/perf/perf-archive.sh | 20 ++++++++---
tools/perf/perf.c | 2 +
tools/perf/util/build-id.c | 10 ++---
tools/perf/util/cache.h | 1 +
tools/perf/util/config.c | 64 +++++++++++++++++++++++++++++++++++-
tools/perf/util/header.c | 3 +-
tools/perf/util/symbol.h | 2 -
tools/perf/util/util.h | 2 +
9 files changed, 89 insertions(+), 18 deletions(-)

diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index f8e3d18..29ad20e 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -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);
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh
index 2e7a4f4..677e59d 100644
--- a/tools/perf/perf-archive.sh
+++ b/tools/perf/perf-archive.sh
@@ -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"
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 6e48711..cdd6c03 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -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;
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 70c5cf8..5c26e2d 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -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;
}
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 65fe664..27e9ebe 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -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);
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index dabe892..e02d78c 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -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);
+}
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 1f62435..4a6a4b3 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -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;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 5e02d2c..34760a2 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -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);

diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 4e8b6b0..de61441 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -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)
{
--
1.6.2.5

2010-06-02 20:40:45

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 3/4] perf tools: Make target to generate self contained source tarball

From: Arnaldo Carvalho de Melo <[email protected]>

Useful for when people want to try some version of the perf tools and don't
wants to download the kernel tarball.

Here is a session using this new target:

[root@emilia linux-2.6-tip]# make help | grep -i perf
perf-tar-src-pkg - Build perf-2.6.35-rc1.tar source tarball
perf-targz-src-pkg - Build perf-2.6.35-rc1.tar.gz source tarball
perf-tarbz2-src-pkg - Build perf-2.6.35-rc1.tar.bz2 source tarball
[root@emilia linux-2.6-tip]# make perf-tarbz2-src-pkg
TAR
[root@emilia linux-2.6-tip]# ls -la perf-2.6.35-rc1.tar.bz2
-rw-r--r-- 1 root root 295731 May 31 11:18 perf-2.6.35-rc1.tar.bz2
[root@emilia linux-2.6-tip]# tar xf perf-2.6.35-rc1.tar.bz2
[root@emilia linux-2.6-tip]# cd perf-2.6.35-rc1
[root@emilia perf-2.6.35-rc1]# ls
arch HEAD include lib tools
[root@emilia perf-2.6.35-rc1]# cd tools/perf
[root@emilia perf]# make -j9 2>&1 | tail
CC arch/x86/util/dwarf-regs.o
CC util/probe-finder.o
CC util/newt.o
CC util/scripting-engines/trace-event-perl.o
CC scripts/perl/Perf-Trace-Util/Context.o
CC perf.o
CC builtin-help.o
AR libperf.a
LINK perf
rm .perf.dev.null
[root@emilia perf]# ./perf record -a sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.262 MB perf.data (~11457 samples) ]
[root@emilia perf]# ./perf report | head -12
# Events: 6K cycles
#
# Overhead Command Shared Object Symbol
# ........ ............... .................. ......
#
4.73% perf [kernel.kallsyms] [k] format_decode
4.49% perf libc-2.12.so [.] _IO_file_underflow_internal
4.38% init [kernel.kallsyms] [k] mwait_idle
3.29% perf [kernel.kallsyms] [k] vsnprintf
2.38% init [kernel.kallsyms] [k] sched_clock_local
2.35% init [kernel.kallsyms] [k] apic_timer_interrupt
1.86% sirq-timer/5 [kernel.kallsyms] [k] find_busiest_group
[root@emilia perf]#

Acked-by: Michal Marek <[email protected]>
Acked-by: Sam Ravnborg <[email protected]>
Cc: David S. Miller <[email protected]>
Cc: Frédéric Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Michal Marek <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Sam Ravnborg <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Tom Zanussi <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
Makefile | 2 +-
scripts/package/Makefile | 37 +++++++++++++++++++++++++++++++------
tools/perf/MANIFEST | 12 ++++++++++++
3 files changed, 44 insertions(+), 7 deletions(-)
create mode 100644 tools/perf/MANIFEST

diff --git a/Makefile b/Makefile
index 6e39ec7..0ab0c6f 100644
--- a/Makefile
+++ b/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
diff --git a/scripts/package/Makefile b/scripts/package/Makefile
index 62fcc3a..18513b0 100644
--- a/scripts/package/Makefile
+++ b/scripts/package/Makefile
@@ -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'

diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
new file mode 100644
index 0000000..8c7fc0c
--- /dev/null
+++ b/tools/perf/MANIFEST
@@ -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
--
1.6.2.5

2010-06-02 20:40:48

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 2/4] perf tools: Add the ability to specify list of cpus to monitor

From: Stephane Eranian <[email protected]>

This patch adds a -C option to stat, record, top to designate a list of CPUs to
monitor. CPUs can be specified as a comma-separated list or ranges, no space
allowed.

Examples:
$ perf record -a -C0-1,4-7 sleep 1
$ perf top -C0-4
$ perf stat -a -C1,2,3,4 sleep 1

With perf record in per-thread mode with inherit mode on, samples are collected
only when the thread runs on the designated CPUs.

The -C option does not turn on system-wide mode automatically.

Cc: David S. Miller <[email protected]>
Cc: Frédéric Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Tom Zanussi <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Stephane Eranian <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/Documentation/perf-record.txt | 7 ++++
tools/perf/Documentation/perf-stat.txt | 7 ++++
tools/perf/Documentation/perf-top.txt | 8 +++--
tools/perf/builtin-record.c | 23 +++++++-----
tools/perf/builtin-stat.c | 14 +++++--
tools/perf/builtin-top.c | 16 +++++---
tools/perf/util/cpumap.c | 57 +++++++++++++++++++++++++++++-
tools/perf/util/cpumap.h | 2 +-
8 files changed, 110 insertions(+), 24 deletions(-)

diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 34e255f..25576b4 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -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]
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 909fa76..4b3a2d4 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -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
--------

diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 785b9fc..1f96876 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -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>::
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 9bc8905..e52023b 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -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;
@@ -300,7 +300,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");
}
@@ -623,10 +623,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]);
}
@@ -705,7 +710,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
@@ -795,8 +800,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"),
@@ -826,7 +831,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) {
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 9a39ca3..a6b4d44 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -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);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index a66f427..45014ef 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -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
@@ -1351,8 +1352,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 +1429,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 +1470,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) {
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 4e01490..0f9b8d7 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -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;
+}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 86c78bb..3e60f56 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -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 */
--
1.6.2.5

2010-06-02 20:41:12

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 1/4] perf report: Make -D print sampled CPU

From: Stephane Eranian <[email protected]>

It is useful to know on which CPU a sample was captured on.
The information is captured with perf record -R but it was
not printed out by perf report -D. This patch adds this.

When -R is not used, cpu is set to -1to indicate that
the CPU is unknown (it is not captured).

Cc: David S. Miller <[email protected]>
Cc: Frédéric Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Tom Zanussi <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Stephane Eranian <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-report.c | 5 +++--
tools/perf/util/event.c | 3 ++-
2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 3592057..207da18 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -157,8 +157,9 @@ static int process_sample_event(event_t *event, struct perf_session *session)

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);
+ dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld cpu:%d\n",
+ event->header.misc, data.pid, data.tid, data.ip,
+ data.period, data.cpu);

if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
unsigned int i;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 50771b5..58cb96b 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -770,7 +770,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;
--
1.6.2.5

2010-06-03 09:02:33

by Andi Kleen

[permalink] [raw]
Subject: Re: [PATCH 3/4] perf tools: Make target to generate self contained source tarball

Arnaldo Carvalho de Melo <[email protected]> writes:

> From: Arnaldo Carvalho de Melo <[email protected]>
>
> Useful for when people want to try some version of the perf tools and don't
> wants to download the kernel tarball.

Does this also finally allow to build perf in a separate objdir like
the rest of the kernel?

Thanks,
-Andi

--
[email protected] -- Speaking for myself only.

2010-06-03 12:51:00

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: Re: [PATCH 3/4] perf tools: Make target to generate self contained source tarball

Em Thu, Jun 03, 2010 at 11:02:29AM +0200, Andi Kleen escreveu:
> > Arnaldo Carvalho de Melo <[email protected]> writes:
> > Useful for when people want to try some version of the perf tools and don't
> > wants to download the kernel tarball.
>
> Does this also finally allow to build perf in a separate objdir like
> the rest of the kernel?

This is how I build it:

make O=~/git/build/perf -j9 -C tools/perf install

was done a few months ago, in:

commit c29ede615fd35a640e771fbbb1778e915fac43a7
Author: Arnaldo Carvalho de Melo <[email protected]>
Date: Sat Mar 27 14:30:45 2010 -0300

perf tools: Allow specifying O= to build files in a separate directory

Avoiding polluting the source tree with build files.

Reported-by: Steven Rostedt <[email protected]>
Cc: Steven Rostedt <[email protected]>
Cc: Fr?d?ric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>

- Arnaldo

2010-06-03 17:26:51

by Andi Kleen

[permalink] [raw]
Subject: Re: [PATCH 3/4] perf tools: Make target to generate self contained source tarball

Thanks. That indeed solves it.
-Andi
--
[email protected] -- Speaking for myself only.

2010-06-08 17:44:58

by Ingo Molnar

[permalink] [raw]
Subject: Re: [GIT PULL 0/4] Perf improvements for .36 (perf/core)


* Arnaldo Carvalho de Melo <[email protected]> wrote:

> From: Arnaldo Carvalho de Melo <[email protected]>
>
> Hi Ingo,
>
> Please pull from:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 perf/core
>
> I'll keep perf/urgent for .35 stuff, perf/core now has only things
> for .36 and I'm merging perf/urgent into perf/core when you pull from it.

Yeah, that sounds good! Fixes then propagate into perf/core in due course via
an -rcx back-merge (or earlier, if they cause conflicts and need to be merged).

> Regards,
>
> - Arnaldo
>
> Arnaldo Carvalho de Melo (1):
> perf tools: Make target to generate self contained source tarball
>
> Stephane Eranian (3):
> perf report: Make -D print sampled CPU
> perf tools: Add the ability to specify list of cpus to monitor
> perf buildid: add perfconfig option to specify buildid cache dir

Pulled, thanks Arnaldo!

Ingo