2010-12-06 20:33:52

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [GIT PULL 0/5] perf/core improvements and fixes

Hi Ingo,

Please pull from:

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

This is in addition to the previous pull request.

Regards,

- Arnaldo

Akihiro Nagai (1):
perf options: add OPT_CALLBACK_DEFAULT_NOOPT

Chris Samuel (1):
perf tools: Catch a few uncheck calloc/malloc's

Ian Munsie (1):
perf hist: Better displaying of unresolved DSOs and symbols

Stephane Eranian (1):
perf script: Fix compiler warning in builtin_script.c:is_top_script()

Thomas Gleixner (1):
perf session: Sort all events if ordered_samples=true

tools/perf/builtin-kmem.c | 3 +
tools/perf/builtin-lock.c | 3 +
tools/perf/builtin-sched.c | 3 +
tools/perf/builtin-script.c | 10 ++--
tools/perf/builtin-timechart.c | 3 +
tools/perf/util/header.c | 3 +
tools/perf/util/parse-options.h | 4 +
tools/perf/util/session.c | 125 ++++++++++++++++++++++----------------
tools/perf/util/sort.c | 6 +-
9 files changed, 99 insertions(+), 61 deletions(-)


2010-12-06 20:28:39

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 5/5] perf tools: Catch a few uncheck calloc/malloc's

From: Chris Samuel <[email protected]>

There were a few stray calloc()'s and malloc()'s which were not having
their return values checked for success.

As the calling code either already coped with failure or didn't actually
care we just return -ENOMEM at that point.

Cc: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Signed-off-by: Chris Samuel <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-kmem.c | 3 +++
tools/perf/builtin-lock.c | 3 +++
tools/perf/builtin-sched.c | 3 +++
tools/perf/builtin-timechart.c | 3 +++
tools/perf/util/header.c | 3 +++
5 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index d0a652e..c9620ff 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -736,6 +736,9 @@ static int __cmd_record(int argc, const char **argv)
rec_argc = ARRAY_SIZE(record_args) + argc - 1;
rec_argv = calloc(rec_argc + 1, sizeof(char *));

+ if (rec_argv == NULL)
+ return -ENOMEM;
+
for (i = 0; i < ARRAY_SIZE(record_args); i++)
rec_argv[i] = strdup(record_args[i]);

diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 92d3da5..b41b449 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -943,6 +943,9 @@ static int __cmd_record(int argc, const char **argv)
rec_argc = ARRAY_SIZE(record_args) + argc - 1;
rec_argv = calloc(rec_argc + 1, sizeof(char *));

+ if (rec_argv == NULL)
+ return -ENOMEM;
+
for (i = 0; i < ARRAY_SIZE(record_args); i++)
rec_argv[i] = strdup(record_args[i]);

diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 73d1e30..c775394 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1860,6 +1860,9 @@ static int __cmd_record(int argc, const char **argv)
rec_argc = ARRAY_SIZE(record_args) + argc - 1;
rec_argv = calloc(rec_argc + 1, sizeof(char *));

+ if (rec_argv)
+ return -ENOMEM;
+
for (i = 0; i < ARRAY_SIZE(record_args); i++)
rec_argv[i] = strdup(record_args[i]);

diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 1f158dc..d2fc461 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -989,6 +989,9 @@ static int __cmd_record(int argc, const char **argv)
rec_argc = ARRAY_SIZE(record_args) + argc - 1;
rec_argv = calloc(rec_argc + 1, sizeof(char *));

+ if (rec_argv == NULL)
+ return -ENOMEM;
+
for (i = 0; i < ARRAY_SIZE(record_args); i++)
rec_argv[i] = strdup(record_args[i]);

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 073f0e1..76e949a 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1005,6 +1005,9 @@ int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id,

ev = malloc(size);

+ if (ev == NULL)
+ return -ENOMEM;
+
ev->attr.attr = *attr;
memcpy(ev->attr.id, id, ids * sizeof(u64));

--
1.6.2.5

2010-12-06 20:28:33

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 4/5] perf script: Fix compiler warning in builtin_script.c:is_top_script()

From: Stephane Eranian <[email protected]>

Fix annoying compiler warning in the is_top_script() function.

The issue was that a const char * was cast into a char * to call
ends_with(). We fix the users of ends_with() instead. Some are passing a
char *, but it is okay to cast the return value of ends_with() to char *
(because we understand what ends_with() does).

Cc: David S. Miller <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Robert Richter <[email protected]>
Cc: Stephane Eranian <[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-script.c | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 683a305..54f1ea8 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -387,10 +387,10 @@ out_delete_desc:
return NULL;
}

-static char *ends_with(char *str, const char *suffix)
+static const char *ends_with(const char *str, const char *suffix)
{
size_t suffix_len = strlen(suffix);
- char *p = str;
+ const char *p = str;

if (strlen(str) > suffix_len) {
p = str + strlen(str) - suffix_len;
@@ -482,7 +482,7 @@ static int list_available_scripts(const struct option *opt __used,

for_each_script(lang_path, lang_dir, script_dirent, script_next) {
script_root = strdup(script_dirent.d_name);
- str = ends_with(script_root, REPORT_SUFFIX);
+ str = (char *)ends_with(script_root, REPORT_SUFFIX);
if (str) {
*str = '\0';
desc = script_desc__findnew(script_root);
@@ -530,7 +530,7 @@ static char *get_script_path(const char *script_root, const char *suffix)

for_each_script(lang_path, lang_dir, script_dirent, script_next) {
__script_root = strdup(script_dirent.d_name);
- str = ends_with(__script_root, suffix);
+ str = (char *)ends_with(__script_root, suffix);
if (str) {
*str = '\0';
if (strcmp(__script_root, script_root))
@@ -550,7 +550,7 @@ static char *get_script_path(const char *script_root, const char *suffix)

static bool is_top_script(const char *script_path)
{
- return ends_with((char *)script_path, "top") == NULL ? false : true;
+ return ends_with(script_path, "top") == NULL ? false : true;
}

static int has_required_arg(char *script_path)
--
1.6.2.5

2010-12-06 20:28:42

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 2/5] perf options: add OPT_CALLBACK_DEFAULT_NOOPT

From: Akihiro Nagai <[email protected]>

Add new macro OPT_CALLBACK_DEFAULT_NOOPT for parse_options.

It enables to pass the default value (opt->defval) to the callback function
processing options require no argument.

Reviewed-by: Masami Hiramatsu <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Masami Hiramatsu <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Akihiro Nagai <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/parse-options.h | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index c7d72dc..abc31a1 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -119,6 +119,10 @@ struct option {
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
+#define OPT_CALLBACK_DEFAULT_NOOPT(s, l, v, a, h, f, d) \
+ { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
+ .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
+ .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}

/* parse_options() will filter out the processed options and leave the
* non-option argments in argv[].
--
1.6.2.5

2010-12-06 20:29:06

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 3/5] perf session: Sort all events if ordered_samples=true

From: Thomas Gleixner <[email protected]>

Now that we have timestamps on FORK, EXIT, COMM, MMAP events we can
sort everything in time order. This fixes the following observed
problem:

mmap(file1) -> pagefault() -> munmap(file1)
mmap(file2) -> pagefault() -> munmap(file2)

Resulted in decoding both pagefaults in file2 because the file1 map
was already replaced by the file2 map when the map address was
identical.

With all events sorted we decode both pagefaults correctly.

Cc: Frederic Weisbecker <[email protected]>
Cc: Ian Munsie <[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]>
LKML-Reference: <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/session.c | 125 ++++++++++++++++++++++++++-------------------
1 files changed, 72 insertions(+), 53 deletions(-)

diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 5c75660..3074d38 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -461,6 +461,11 @@ static void perf_session_free_sample_buffers(struct perf_session *session)
}
}

+static int perf_session_deliver_event(struct perf_session *session,
+ event_t *event,
+ struct sample_data *sample,
+ struct perf_event_ops *ops);
+
static void flush_sample_queue(struct perf_session *s,
struct perf_event_ops *ops)
{
@@ -479,7 +484,7 @@ static void flush_sample_queue(struct perf_session *s,
break;

event__parse_sample(iter->event, s, &sample);
- ops->sample(iter->event, &sample, s);
+ perf_session_deliver_event(s, iter->event, &sample, ops);

os->last_flush = iter->timestamp;
list_del(&iter->list);
@@ -544,8 +549,7 @@ static int process_finished_round(event_t *event __used,
}

/* The queue is ordered by time */
-static void __queue_sample_event(struct sample_queue *new,
- struct perf_session *s)
+static void __queue_event(struct sample_queue *new, struct perf_session *s)
{
struct ordered_samples *os = &s->ordered_samples;
struct sample_queue *sample = os->last_sample;
@@ -591,14 +595,17 @@ static void __queue_sample_event(struct sample_queue *new,

#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue))

-static int queue_sample_event(event_t *event, struct sample_data *data,
- struct perf_session *s)
+static int perf_session_queue_event(struct perf_session *s, event_t *event,
+ struct sample_data *data)
{
struct ordered_samples *os = &s->ordered_samples;
struct list_head *sc = &os->sample_cache;
u64 timestamp = data->time;
struct sample_queue *new;

+ if (!timestamp)
+ return -ETIME;
+
if (timestamp < s->ordered_samples.last_flush) {
printf("Warning: Timestamp below last timeslice flush\n");
return -EINVAL;
@@ -623,20 +630,8 @@ static int queue_sample_event(event_t *event, struct sample_data *data,
new->timestamp = timestamp;
new->event = event;

- __queue_sample_event(new, s);
-
- return 0;
-}
-
-static int perf_session__process_sample(event_t *event,
- struct sample_data *sample,
- struct perf_session *s,
- struct perf_event_ops *ops)
-{
- if (!ops->ordered_samples)
- return ops->sample(event, sample, s);
+ __queue_event(new, s);

- queue_sample_event(event, sample, s);
return 0;
}

@@ -670,83 +665,107 @@ static void perf_session__print_tstamp(struct perf_session *session,
printf("%Lu ", sample->time);
}

-static int perf_session__process_event(struct perf_session *self,
+static int perf_session_deliver_event(struct perf_session *session,
+ event_t *event,
+ struct sample_data *sample,
+ struct perf_event_ops *ops)
+{
+ switch (event->header.type) {
+ case PERF_RECORD_SAMPLE:
+ return ops->sample(event, sample, session);
+ case PERF_RECORD_MMAP:
+ return ops->mmap(event, sample, session);
+ case PERF_RECORD_COMM:
+ return ops->comm(event, sample, session);
+ case PERF_RECORD_FORK:
+ return ops->fork(event, sample, session);
+ case PERF_RECORD_EXIT:
+ return ops->exit(event, sample, session);
+ case PERF_RECORD_LOST:
+ return ops->lost(event, sample, session);
+ case PERF_RECORD_READ:
+ return ops->read(event, sample, session);
+ case PERF_RECORD_THROTTLE:
+ return ops->throttle(event, sample, session);
+ case PERF_RECORD_UNTHROTTLE:
+ return ops->unthrottle(event, sample, session);
+ default:
+ ++session->hists.stats.nr_unknown_events;
+ return -1;
+ }
+}
+
+static int perf_session__process_event(struct perf_session *session,
event_t *event,
struct perf_event_ops *ops,
u64 file_offset)
{
struct sample_data sample;
+ int ret;

trace_event(event);

- if (self->header.needs_swap && event__swap_ops[event->header.type])
+ if (session->header.needs_swap && event__swap_ops[event->header.type])
event__swap_ops[event->header.type](event);

if (event->header.type >= PERF_RECORD_MMAP &&
event->header.type <= PERF_RECORD_SAMPLE) {
- event__parse_sample(event, self, &sample);
+ event__parse_sample(event, session, &sample);
if (dump_trace)
- perf_session__print_tstamp(self, event, &sample);
+ perf_session__print_tstamp(session, event, &sample);
}

if (event->header.type < PERF_RECORD_HEADER_MAX) {
dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
file_offset, event->header.size,
event__name[event->header.type]);
- hists__inc_nr_events(&self->hists, event->header.type);
+ hists__inc_nr_events(&session->hists, event->header.type);
}

+ /* These events are processed right away */
switch (event->header.type) {
case PERF_RECORD_SAMPLE:
- dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
+ dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n",
+ event->header.misc,
sample.pid, sample.tid, sample.ip, sample.period);

- if (self->sample_type & PERF_SAMPLE_CALLCHAIN) {
+ if (session->sample_type & PERF_SAMPLE_CALLCHAIN) {
if (!ip_callchain__valid(sample.callchain, event)) {
pr_debug("call-chain problem with event, "
"skipping it.\n");
- ++self->hists.stats.nr_invalid_chains;
- self->hists.stats.total_invalid_chains += sample.period;
+ ++session->hists.stats.nr_invalid_chains;
+ session->hists.stats.total_invalid_chains +=
+ sample.period;
return 0;
}

callchain__dump(&sample);
}
+ break;

- return perf_session__process_sample(event, &sample, self, ops);
-
- case PERF_RECORD_MMAP:
- return ops->mmap(event, &sample, self);
- case PERF_RECORD_COMM:
- return ops->comm(event, &sample, self);
- case PERF_RECORD_FORK:
- return ops->fork(event, &sample, self);
- case PERF_RECORD_EXIT:
- return ops->exit(event, &sample, self);
- case PERF_RECORD_LOST:
- return ops->lost(event, &sample, self);
- case PERF_RECORD_READ:
- return ops->read(event, &sample, self);
- case PERF_RECORD_THROTTLE:
- return ops->throttle(event, &sample, self);
- case PERF_RECORD_UNTHROTTLE:
- return ops->unthrottle(event, &sample, self);
case PERF_RECORD_HEADER_ATTR:
- return ops->attr(event, self);
+ return ops->attr(event, session);
case PERF_RECORD_HEADER_EVENT_TYPE:
- return ops->event_type(event, self);
+ return ops->event_type(event, session);
case PERF_RECORD_HEADER_TRACING_DATA:
/* setup for reading amidst mmap */
- lseek(self->fd, file_offset, SEEK_SET);
- return ops->tracing_data(event, self);
+ lseek(session->fd, file_offset, SEEK_SET);
+ return ops->tracing_data(event, session);
case PERF_RECORD_HEADER_BUILD_ID:
- return ops->build_id(event, self);
+ return ops->build_id(event, session);
case PERF_RECORD_FINISHED_ROUND:
- return ops->finished_round(event, self, ops);
+ return ops->finished_round(event, session, ops);
default:
- ++self->hists.stats.nr_unknown_events;
- return -1;
+ break;
}
+
+ if (ops->ordered_samples) {
+ ret = perf_session_queue_event(session, event, &sample);
+ if (ret != -ETIME)
+ return ret;
+ }
+
+ return perf_session_deliver_event(session, event, &sample, ops);
}

void perf_event_header__bswap(struct perf_event_header *self)
--
1.6.2.5

2010-12-06 20:33:59

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 1/5] perf hist: Better displaying of unresolved DSOs and symbols

From: Ian Munsie <[email protected]>

In the event that a DSO has not been identified, just print out [unknown]
instead of the instruction pointer as we previously were doing, which is pretty
meaningless for a shared object (at least to the users perspective).

The IP we print out is fairly meaningless in general anyway - it's just one
(the first) of the many addresses that were lumped together as unidentified,
and could span many shared objects and symbols. In reality if we see this
[unknown] output then the report -D output is going to be more useful anyway as
we can see all the different address that it represents.

If we are printing the symbols we are still going to see this IP in that column
anyway since they shouldn't resolve either.

This patch also changes the symbol address printouts so that they print out 0x
before the address, are left aligned, and changes the %L format string (which
relies on a glibc bug) to %ll.

Before:
74.11% :3259 4a6c [k] 4a6c
After:
74.11% :3259 [unknown] [k] 0x4a6c

Cc: Frederic Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Ian Munsie <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/sort.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index b62a553..f44fa54 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -170,7 +170,7 @@ static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
return repsep_snprintf(bf, size, "%-*s", width, dso_name);
}

- return repsep_snprintf(bf, size, "%*Lx", width, self->ip);
+ return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
}

/* --sort symbol */
@@ -196,7 +196,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,

if (verbose) {
char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
- ret += repsep_snprintf(bf, size, "%*Lx %c ",
+ ret += repsep_snprintf(bf, size, "%-#*llx %c ",
BITS_PER_LONG / 4, self->ip, o);
}

@@ -205,7 +205,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
ret += repsep_snprintf(bf + ret, size - ret, "%s",
self->ms.sym->name);
else
- ret += repsep_snprintf(bf + ret, size - ret, "%*Lx",
+ ret += repsep_snprintf(bf + ret, size - ret, "%-#*llx",
BITS_PER_LONG / 4, self->ip);

return ret;
--
1.6.2.5