2009-06-25 23:05:54 +08:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2009-11-11 11:51:03 +08:00
|
|
|
#include <linux/list.h>
|
2009-06-25 23:05:54 +08:00
|
|
|
|
|
|
|
#include "util.h"
|
|
|
|
#include "header.h"
|
2009-10-07 05:36:47 +08:00
|
|
|
#include "../perf.h"
|
|
|
|
#include "trace-event.h"
|
2009-11-11 11:51:03 +08:00
|
|
|
#include "symbol.h"
|
2009-06-25 23:05:54 +08:00
|
|
|
|
|
|
|
/*
|
2009-09-19 19:36:30 +08:00
|
|
|
* Create new perf.data header attribute:
|
2009-06-25 23:05:54 +08:00
|
|
|
*/
|
perf: Do the big rename: Performance Counters -> Performance Events
Bye-bye Performance Counters, welcome Performance Events!
In the past few months the perfcounters subsystem has grown out its
initial role of counting hardware events, and has become (and is
becoming) a much broader generic event enumeration, reporting, logging,
monitoring, analysis facility.
Naming its core object 'perf_counter' and naming the subsystem
'perfcounters' has become more and more of a misnomer. With pending
code like hw-breakpoints support the 'counter' name is less and
less appropriate.
All in one, we've decided to rename the subsystem to 'performance
events' and to propagate this rename through all fields, variables
and API names. (in an ABI compatible fashion)
The word 'event' is also a bit shorter than 'counter' - which makes
it slightly more convenient to write/handle as well.
Thanks goes to Stephane Eranian who first observed this misnomer and
suggested a rename.
User-space tooling and ABI compatibility is not affected - this patch
should be function-invariant. (Also, defconfigs were not touched to
keep the size down.)
This patch has been generated via the following script:
FILES=$(find * -type f | grep -vE 'oprofile|[^K]config')
sed -i \
-e 's/PERF_EVENT_/PERF_RECORD_/g' \
-e 's/PERF_COUNTER/PERF_EVENT/g' \
-e 's/perf_counter/perf_event/g' \
-e 's/nb_counters/nb_events/g' \
-e 's/swcounter/swevent/g' \
-e 's/tpcounter_event/tp_event/g' \
$FILES
for N in $(find . -name perf_counter.[ch]); do
M=$(echo $N | sed 's/perf_counter/perf_event/g')
mv $N $M
done
FILES=$(find . -name perf_event.*)
sed -i \
-e 's/COUNTER_MASK/REG_MASK/g' \
-e 's/COUNTER/EVENT/g' \
-e 's/\<event\>/event_id/g' \
-e 's/counter/event/g' \
-e 's/Counter/Event/g' \
$FILES
... to keep it as correct as possible. This script can also be
used by anyone who has pending perfcounters patches - it converts
a Linux kernel tree over to the new naming. We tried to time this
change to the point in time where the amount of pending patches
is the smallest: the end of the merge window.
Namespace clashes were fixed up in a preparatory patch - and some
stylistic fallout will be fixed up in a subsequent patch.
( NOTE: 'counters' are still the proper terminology when we deal
with hardware registers - and these sed scripts are a bit
over-eager in renaming them. I've undone some of that, but
in case there's something left where 'counter' would be
better than 'event' we can undo that on an individual basis
instead of touching an otherwise nicely automated patch. )
Suggested-by: Stephane Eranian <eranian@google.com>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Paul Mackerras <paulus@samba.org>
Reviewed-by: Arjan van de Ven <arjan@linux.intel.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Kyle McMartin <kyle@mcmartin.ca>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: <linux-arch@vger.kernel.org>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-09-21 18:02:48 +08:00
|
|
|
struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
|
2009-06-25 23:05:54 +08:00
|
|
|
{
|
|
|
|
struct perf_header_attr *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (!self)
|
|
|
|
die("nomem");
|
|
|
|
|
|
|
|
self->attr = *attr;
|
|
|
|
self->ids = 0;
|
|
|
|
self->size = 1;
|
|
|
|
self->id = malloc(sizeof(u64));
|
|
|
|
|
|
|
|
if (!self->id)
|
|
|
|
die("nomem");
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
|
|
|
|
{
|
|
|
|
int pos = self->ids;
|
|
|
|
|
|
|
|
self->ids++;
|
|
|
|
if (self->ids > self->size) {
|
|
|
|
self->size *= 2;
|
|
|
|
self->id = realloc(self->id, self->size * sizeof(u64));
|
|
|
|
if (!self->id)
|
|
|
|
die("nomem");
|
|
|
|
}
|
|
|
|
self->id[pos] = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2009-09-19 19:36:30 +08:00
|
|
|
* Create new perf.data header:
|
2009-06-25 23:05:54 +08:00
|
|
|
*/
|
|
|
|
struct perf_header *perf_header__new(void)
|
|
|
|
{
|
2009-10-17 23:12:34 +08:00
|
|
|
struct perf_header *self = calloc(sizeof(*self), 1);
|
2009-06-25 23:05:54 +08:00
|
|
|
|
|
|
|
if (!self)
|
|
|
|
die("nomem");
|
|
|
|
|
|
|
|
self->size = 1;
|
|
|
|
self->attr = malloc(sizeof(void *));
|
|
|
|
|
|
|
|
if (!self->attr)
|
|
|
|
die("nomem");
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
void perf_header__add_attr(struct perf_header *self,
|
|
|
|
struct perf_header_attr *attr)
|
|
|
|
{
|
|
|
|
int pos = self->attrs;
|
|
|
|
|
|
|
|
if (self->frozen)
|
|
|
|
die("frozen");
|
|
|
|
|
|
|
|
self->attrs++;
|
|
|
|
if (self->attrs > self->size) {
|
|
|
|
self->size *= 2;
|
|
|
|
self->attr = realloc(self->attr, self->size * sizeof(void *));
|
|
|
|
if (!self->attr)
|
|
|
|
die("nomem");
|
|
|
|
}
|
|
|
|
self->attr[pos] = attr;
|
|
|
|
}
|
|
|
|
|
2009-09-19 19:36:30 +08:00
|
|
|
#define MAX_EVENT_NAME 64
|
|
|
|
|
2009-09-12 13:52:51 +08:00
|
|
|
struct perf_trace_event_type {
|
|
|
|
u64 event_id;
|
2009-09-19 19:36:30 +08:00
|
|
|
char name[MAX_EVENT_NAME];
|
2009-09-12 13:52:51 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int event_count;
|
|
|
|
static struct perf_trace_event_type *events;
|
|
|
|
|
|
|
|
void perf_header__push_event(u64 id, const char *name)
|
|
|
|
{
|
2009-09-19 19:36:30 +08:00
|
|
|
if (strlen(name) > MAX_EVENT_NAME)
|
2009-10-22 03:34:06 +08:00
|
|
|
pr_warning("Event %s will be truncated\n", name);
|
2009-09-12 13:52:51 +08:00
|
|
|
|
|
|
|
if (!events) {
|
|
|
|
events = malloc(sizeof(struct perf_trace_event_type));
|
|
|
|
if (!events)
|
|
|
|
die("nomem");
|
|
|
|
} else {
|
|
|
|
events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type));
|
|
|
|
if (!events)
|
|
|
|
die("nomem");
|
|
|
|
}
|
|
|
|
memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
|
|
|
|
events[event_count].event_id = id;
|
2009-09-19 19:36:30 +08:00
|
|
|
strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
|
2009-09-12 13:52:51 +08:00
|
|
|
event_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *perf_header__find_event(u64 id)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0 ; i < event_count; i++) {
|
|
|
|
if (events[i].event_id == id)
|
|
|
|
return events[i].name;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-06-25 23:05:54 +08:00
|
|
|
static const char *__perf_magic = "PERFFILE";
|
|
|
|
|
|
|
|
#define PERF_MAGIC (*(u64 *)__perf_magic)
|
|
|
|
|
|
|
|
struct perf_file_section {
|
|
|
|
u64 offset;
|
|
|
|
u64 size;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct perf_file_attr {
|
perf: Do the big rename: Performance Counters -> Performance Events
Bye-bye Performance Counters, welcome Performance Events!
In the past few months the perfcounters subsystem has grown out its
initial role of counting hardware events, and has become (and is
becoming) a much broader generic event enumeration, reporting, logging,
monitoring, analysis facility.
Naming its core object 'perf_counter' and naming the subsystem
'perfcounters' has become more and more of a misnomer. With pending
code like hw-breakpoints support the 'counter' name is less and
less appropriate.
All in one, we've decided to rename the subsystem to 'performance
events' and to propagate this rename through all fields, variables
and API names. (in an ABI compatible fashion)
The word 'event' is also a bit shorter than 'counter' - which makes
it slightly more convenient to write/handle as well.
Thanks goes to Stephane Eranian who first observed this misnomer and
suggested a rename.
User-space tooling and ABI compatibility is not affected - this patch
should be function-invariant. (Also, defconfigs were not touched to
keep the size down.)
This patch has been generated via the following script:
FILES=$(find * -type f | grep -vE 'oprofile|[^K]config')
sed -i \
-e 's/PERF_EVENT_/PERF_RECORD_/g' \
-e 's/PERF_COUNTER/PERF_EVENT/g' \
-e 's/perf_counter/perf_event/g' \
-e 's/nb_counters/nb_events/g' \
-e 's/swcounter/swevent/g' \
-e 's/tpcounter_event/tp_event/g' \
$FILES
for N in $(find . -name perf_counter.[ch]); do
M=$(echo $N | sed 's/perf_counter/perf_event/g')
mv $N $M
done
FILES=$(find . -name perf_event.*)
sed -i \
-e 's/COUNTER_MASK/REG_MASK/g' \
-e 's/COUNTER/EVENT/g' \
-e 's/\<event\>/event_id/g' \
-e 's/counter/event/g' \
-e 's/Counter/Event/g' \
$FILES
... to keep it as correct as possible. This script can also be
used by anyone who has pending perfcounters patches - it converts
a Linux kernel tree over to the new naming. We tried to time this
change to the point in time where the amount of pending patches
is the smallest: the end of the merge window.
Namespace clashes were fixed up in a preparatory patch - and some
stylistic fallout will be fixed up in a subsequent patch.
( NOTE: 'counters' are still the proper terminology when we deal
with hardware registers - and these sed scripts are a bit
over-eager in renaming them. I've undone some of that, but
in case there's something left where 'counter' would be
better than 'event' we can undo that on an individual basis
instead of touching an otherwise nicely automated patch. )
Suggested-by: Stephane Eranian <eranian@google.com>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Paul Mackerras <paulus@samba.org>
Reviewed-by: Arjan van de Ven <arjan@linux.intel.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Kyle McMartin <kyle@mcmartin.ca>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: <linux-arch@vger.kernel.org>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-09-21 18:02:48 +08:00
|
|
|
struct perf_event_attr attr;
|
2009-06-25 23:05:54 +08:00
|
|
|
struct perf_file_section ids;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct perf_file_header {
|
|
|
|
u64 magic;
|
|
|
|
u64 size;
|
|
|
|
u64 attr_size;
|
|
|
|
struct perf_file_section attrs;
|
|
|
|
struct perf_file_section data;
|
2009-09-12 13:52:51 +08:00
|
|
|
struct perf_file_section event_types;
|
2009-10-17 23:57:18 +08:00
|
|
|
DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
|
2009-06-25 23:05:54 +08:00
|
|
|
};
|
|
|
|
|
2009-10-17 23:12:34 +08:00
|
|
|
void perf_header__feat_trace_info(struct perf_header *header)
|
2009-10-07 05:36:47 +08:00
|
|
|
{
|
2009-10-17 23:57:18 +08:00
|
|
|
set_bit(HEADER_TRACE_INFO, header->adds_features);
|
2009-10-07 05:36:47 +08:00
|
|
|
}
|
|
|
|
|
perf symbols: Use the buildids if present
With this change 'perf record' will intercept PERF_RECORD_MMAP
calls, creating a linked list of DSOs, then when the session
finishes, it will traverse this list and read the buildids,
stashing them at the end of the file and will set up a new
feature bit in the header bitmask.
'perf report' will then notice this feature and populate the
'dsos' list and set the build ids.
When reading the symtabs it will refuse to load from a file that
doesn't have the same build id. This improves the
reliability of the profiler output, as symbols and profiling
data is more guaranteed to match.
Example:
[root@doppio ~]# perf report | head
/home/acme/bin/perf with build id b1ea544ac3746e7538972548a09aadecc5753868 not found, continuing without symbols
# Samples: 2621434559
#
# Overhead Command Shared Object Symbol
# ........ ............... ............................. ......
#
7.91% init [kernel] [k] read_hpet
7.64% init [kernel] [k] mwait_idle_with_hints
7.60% swapper [kernel] [k] read_hpet
7.60% swapper [kernel] [k] mwait_idle_with_hints
3.65% init [kernel] [k] 0xffffffffa02339d9
[root@doppio ~]#
In this case the 'perf' binary was an older one, vanished,
so its symbols probably wouldn't match or would cause subtly
different (and misleading) output.
Next patches will support the kernel as well, reading the build
id notes for it and the modules from /sys.
Another patch should also introduce a new plumbing command:
'perf list-buildids'
that will then be used in porcelain that is distro specific to
fetch -debuginfo packages where such buildids are present. This
will in turn allow for one to run 'perf record' in one machine
and 'perf report' in another.
Future work on having the buildid sent directly from the kernel
in the PERF_RECORD_MMAP event is needed to close races, as the
DSO can be changed during a 'perf record' session, but this
patch at least helps with non-corner cases and current/older
kernels.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Frank Ch. Eigler <fche@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jason Baron <jbaron@redhat.com>
Cc: Jim Keniston <jkenisto@us.ibm.com>
Cc: K. Prasad <prasad@linux.vnet.ibm.com>
Cc: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Roland McGrath <roland@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <1257367843-26224-1-git-send-email-acme@infradead.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-11-05 04:50:43 +08:00
|
|
|
void perf_header__set_feat(struct perf_header *self, int feat)
|
|
|
|
{
|
|
|
|
set_bit(feat, self->adds_features);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool perf_header__has_feat(const struct perf_header *self, int feat)
|
|
|
|
{
|
|
|
|
return test_bit(feat, self->adds_features);
|
|
|
|
}
|
|
|
|
|
2009-06-25 23:05:54 +08:00
|
|
|
static void do_write(int fd, void *buf, size_t size)
|
|
|
|
{
|
|
|
|
while (size) {
|
|
|
|
int ret = write(fd, buf, size);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
die("failed to write");
|
|
|
|
|
|
|
|
size -= ret;
|
|
|
|
buf += ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-11 11:51:03 +08:00
|
|
|
static bool write_buildid_table(int fd)
|
|
|
|
{
|
|
|
|
struct dso *pos;
|
|
|
|
bool have_buildid = false;
|
|
|
|
|
|
|
|
list_for_each_entry(pos, &dsos, node) {
|
|
|
|
struct build_id_event b;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (filename__read_build_id(pos->long_name,
|
|
|
|
&b.build_id,
|
|
|
|
sizeof(b.build_id)) < 0)
|
|
|
|
continue;
|
|
|
|
have_buildid = true;
|
|
|
|
memset(&b.header, 0, sizeof(b.header));
|
|
|
|
len = strlen(pos->long_name) + 1;
|
|
|
|
len = ALIGN(len, 64);
|
|
|
|
b.header.size = sizeof(b) + len;
|
|
|
|
do_write(fd, &b, sizeof(b));
|
|
|
|
do_write(fd, pos->long_name, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
return have_buildid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
perf_header__adds_write(struct perf_header *self, int fd, bool at_exit)
|
2009-10-17 23:12:34 +08:00
|
|
|
{
|
|
|
|
struct perf_file_section trace_sec;
|
|
|
|
u64 cur_offset = lseek(fd, 0, SEEK_CUR);
|
2009-10-17 23:57:18 +08:00
|
|
|
unsigned long *feat_mask = self->adds_features;
|
2009-10-17 23:12:34 +08:00
|
|
|
|
|
|
|
if (test_bit(HEADER_TRACE_INFO, feat_mask)) {
|
|
|
|
/* Write trace info */
|
|
|
|
trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR);
|
|
|
|
read_tracing_data(fd, attrs, nr_counters);
|
|
|
|
trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset;
|
|
|
|
|
|
|
|
/* Write trace info headers */
|
|
|
|
lseek(fd, cur_offset, SEEK_SET);
|
|
|
|
do_write(fd, &trace_sec, sizeof(trace_sec));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update cur_offset. So that other (future)
|
|
|
|
* features can set their own infos in this place. But if we are
|
|
|
|
* the only feature, at least that seeks to the place the data
|
|
|
|
* should begin.
|
|
|
|
*/
|
|
|
|
cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET);
|
|
|
|
}
|
2009-11-11 11:51:03 +08:00
|
|
|
|
|
|
|
if (at_exit) {
|
|
|
|
lseek(fd, self->data_offset + self->data_size, SEEK_SET);
|
|
|
|
if (write_buildid_table(fd))
|
|
|
|
perf_header__set_feat(self, HEADER_BUILD_ID);
|
|
|
|
lseek(fd, cur_offset, SEEK_SET);
|
|
|
|
}
|
2009-10-17 23:12:34 +08:00
|
|
|
};
|
|
|
|
|
2009-11-11 11:51:03 +08:00
|
|
|
void perf_header__write(struct perf_header *self, int fd, bool at_exit)
|
2009-06-25 23:05:54 +08:00
|
|
|
{
|
|
|
|
struct perf_file_header f_header;
|
|
|
|
struct perf_file_attr f_attr;
|
|
|
|
struct perf_header_attr *attr;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
lseek(fd, sizeof(f_header), SEEK_SET);
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < self->attrs; i++) {
|
|
|
|
attr = self->attr[i];
|
|
|
|
|
|
|
|
attr->id_offset = lseek(fd, 0, SEEK_CUR);
|
|
|
|
do_write(fd, attr->id, attr->ids * sizeof(u64));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self->attr_offset = lseek(fd, 0, SEEK_CUR);
|
|
|
|
|
|
|
|
for (i = 0; i < self->attrs; i++) {
|
|
|
|
attr = self->attr[i];
|
|
|
|
|
|
|
|
f_attr = (struct perf_file_attr){
|
|
|
|
.attr = attr->attr,
|
|
|
|
.ids = {
|
|
|
|
.offset = attr->id_offset,
|
|
|
|
.size = attr->ids * sizeof(u64),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
do_write(fd, &f_attr, sizeof(f_attr));
|
|
|
|
}
|
|
|
|
|
2009-09-12 13:52:51 +08:00
|
|
|
self->event_offset = lseek(fd, 0, SEEK_CUR);
|
|
|
|
self->event_size = event_count * sizeof(struct perf_trace_event_type);
|
|
|
|
if (events)
|
|
|
|
do_write(fd, events, self->event_size);
|
|
|
|
|
2009-11-11 11:51:03 +08:00
|
|
|
perf_header__adds_write(self, fd, at_exit);
|
2009-06-25 23:05:54 +08:00
|
|
|
|
|
|
|
self->data_offset = lseek(fd, 0, SEEK_CUR);
|
|
|
|
|
|
|
|
f_header = (struct perf_file_header){
|
|
|
|
.magic = PERF_MAGIC,
|
|
|
|
.size = sizeof(f_header),
|
|
|
|
.attr_size = sizeof(f_attr),
|
|
|
|
.attrs = {
|
|
|
|
.offset = self->attr_offset,
|
|
|
|
.size = self->attrs * sizeof(f_attr),
|
|
|
|
},
|
|
|
|
.data = {
|
|
|
|
.offset = self->data_offset,
|
|
|
|
.size = self->data_size,
|
|
|
|
},
|
2009-09-12 13:52:51 +08:00
|
|
|
.event_types = {
|
|
|
|
.offset = self->event_offset,
|
|
|
|
.size = self->event_size,
|
|
|
|
},
|
2009-06-25 23:05:54 +08:00
|
|
|
};
|
|
|
|
|
2009-10-17 23:57:18 +08:00
|
|
|
memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
|
2009-10-17 23:12:34 +08:00
|
|
|
|
2009-06-25 23:05:54 +08:00
|
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
do_write(fd, &f_header, sizeof(f_header));
|
|
|
|
lseek(fd, self->data_offset + self->data_size, SEEK_SET);
|
|
|
|
|
|
|
|
self->frozen = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void do_read(int fd, void *buf, size_t size)
|
|
|
|
{
|
|
|
|
while (size) {
|
|
|
|
int ret = read(fd, buf, size);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
die("failed to read");
|
2009-08-07 20:16:00 +08:00
|
|
|
if (ret == 0)
|
|
|
|
die("failed to read: missing data");
|
2009-06-25 23:05:54 +08:00
|
|
|
|
|
|
|
size -= ret;
|
|
|
|
buf += ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-17 23:12:34 +08:00
|
|
|
static void perf_header__adds_read(struct perf_header *self, int fd)
|
|
|
|
{
|
2009-10-17 23:57:18 +08:00
|
|
|
const unsigned long *feat_mask = self->adds_features;
|
2009-10-17 23:12:34 +08:00
|
|
|
|
|
|
|
if (test_bit(HEADER_TRACE_INFO, feat_mask)) {
|
|
|
|
struct perf_file_section trace_sec;
|
|
|
|
|
|
|
|
do_read(fd, &trace_sec, sizeof(trace_sec));
|
|
|
|
lseek(fd, trace_sec.offset, SEEK_SET);
|
|
|
|
trace_report(fd);
|
|
|
|
lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-06-25 23:05:54 +08:00
|
|
|
struct perf_header *perf_header__read(int fd)
|
|
|
|
{
|
|
|
|
struct perf_header *self = perf_header__new();
|
|
|
|
struct perf_file_header f_header;
|
|
|
|
struct perf_file_attr f_attr;
|
|
|
|
u64 f_id;
|
|
|
|
|
|
|
|
int nr_attrs, nr_ids, i, j;
|
|
|
|
|
|
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
do_read(fd, &f_header, sizeof(f_header));
|
|
|
|
|
|
|
|
if (f_header.magic != PERF_MAGIC ||
|
|
|
|
f_header.attr_size != sizeof(f_attr))
|
|
|
|
die("incompatible file format");
|
|
|
|
|
2009-10-09 04:07:29 +08:00
|
|
|
if (f_header.size != sizeof(f_header)) {
|
|
|
|
/* Support the previous format */
|
2009-10-17 23:57:18 +08:00
|
|
|
if (f_header.size == offsetof(typeof(f_header), adds_features))
|
|
|
|
bitmap_zero(f_header.adds_features, HEADER_FEAT_BITS);
|
|
|
|
else
|
2009-10-09 04:07:29 +08:00
|
|
|
die("incompatible file format");
|
|
|
|
}
|
2009-06-25 23:05:54 +08:00
|
|
|
nr_attrs = f_header.attrs.size / sizeof(f_attr);
|
|
|
|
lseek(fd, f_header.attrs.offset, SEEK_SET);
|
|
|
|
|
|
|
|
for (i = 0; i < nr_attrs; i++) {
|
|
|
|
struct perf_header_attr *attr;
|
2009-08-07 02:57:41 +08:00
|
|
|
off_t tmp;
|
2009-06-25 23:05:54 +08:00
|
|
|
|
|
|
|
do_read(fd, &f_attr, sizeof(f_attr));
|
2009-08-07 02:57:41 +08:00
|
|
|
tmp = lseek(fd, 0, SEEK_CUR);
|
2009-06-25 23:05:54 +08:00
|
|
|
|
|
|
|
attr = perf_header_attr__new(&f_attr.attr);
|
|
|
|
|
|
|
|
nr_ids = f_attr.ids.size / sizeof(u64);
|
|
|
|
lseek(fd, f_attr.ids.offset, SEEK_SET);
|
|
|
|
|
|
|
|
for (j = 0; j < nr_ids; j++) {
|
|
|
|
do_read(fd, &f_id, sizeof(f_id));
|
|
|
|
|
|
|
|
perf_header_attr__add_id(attr, f_id);
|
|
|
|
}
|
|
|
|
perf_header__add_attr(self, attr);
|
|
|
|
lseek(fd, tmp, SEEK_SET);
|
|
|
|
}
|
|
|
|
|
2009-09-12 13:52:51 +08:00
|
|
|
if (f_header.event_types.size) {
|
|
|
|
lseek(fd, f_header.event_types.offset, SEEK_SET);
|
|
|
|
events = malloc(f_header.event_types.size);
|
|
|
|
if (!events)
|
|
|
|
die("nomem");
|
|
|
|
do_read(fd, events, f_header.event_types.size);
|
|
|
|
event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
|
|
|
|
}
|
2009-10-07 05:36:47 +08:00
|
|
|
|
2009-10-17 23:57:18 +08:00
|
|
|
memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features));
|
2009-10-07 05:36:47 +08:00
|
|
|
|
2009-10-17 23:12:34 +08:00
|
|
|
perf_header__adds_read(self, fd);
|
2009-10-07 05:36:47 +08:00
|
|
|
|
2009-09-12 13:52:51 +08:00
|
|
|
self->event_offset = f_header.event_types.offset;
|
|
|
|
self->event_size = f_header.event_types.size;
|
|
|
|
|
2009-06-25 23:05:54 +08:00
|
|
|
self->data_offset = f_header.data.offset;
|
|
|
|
self->data_size = f_header.data.size;
|
|
|
|
|
2009-09-03 22:21:11 +08:00
|
|
|
lseek(fd, self->data_offset, SEEK_SET);
|
2009-06-25 23:05:54 +08:00
|
|
|
|
|
|
|
self->frozen = 1;
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
2009-08-17 02:56:37 +08:00
|
|
|
|
|
|
|
u64 perf_header__sample_type(struct perf_header *header)
|
|
|
|
{
|
|
|
|
u64 type = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < header->attrs; i++) {
|
|
|
|
struct perf_header_attr *attr = header->attr[i];
|
|
|
|
|
|
|
|
if (!type)
|
|
|
|
type = attr->attr.sample_type;
|
|
|
|
else if (type != attr->attr.sample_type)
|
|
|
|
die("non matching sample_type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
perf: Do the big rename: Performance Counters -> Performance Events
Bye-bye Performance Counters, welcome Performance Events!
In the past few months the perfcounters subsystem has grown out its
initial role of counting hardware events, and has become (and is
becoming) a much broader generic event enumeration, reporting, logging,
monitoring, analysis facility.
Naming its core object 'perf_counter' and naming the subsystem
'perfcounters' has become more and more of a misnomer. With pending
code like hw-breakpoints support the 'counter' name is less and
less appropriate.
All in one, we've decided to rename the subsystem to 'performance
events' and to propagate this rename through all fields, variables
and API names. (in an ABI compatible fashion)
The word 'event' is also a bit shorter than 'counter' - which makes
it slightly more convenient to write/handle as well.
Thanks goes to Stephane Eranian who first observed this misnomer and
suggested a rename.
User-space tooling and ABI compatibility is not affected - this patch
should be function-invariant. (Also, defconfigs were not touched to
keep the size down.)
This patch has been generated via the following script:
FILES=$(find * -type f | grep -vE 'oprofile|[^K]config')
sed -i \
-e 's/PERF_EVENT_/PERF_RECORD_/g' \
-e 's/PERF_COUNTER/PERF_EVENT/g' \
-e 's/perf_counter/perf_event/g' \
-e 's/nb_counters/nb_events/g' \
-e 's/swcounter/swevent/g' \
-e 's/tpcounter_event/tp_event/g' \
$FILES
for N in $(find . -name perf_counter.[ch]); do
M=$(echo $N | sed 's/perf_counter/perf_event/g')
mv $N $M
done
FILES=$(find . -name perf_event.*)
sed -i \
-e 's/COUNTER_MASK/REG_MASK/g' \
-e 's/COUNTER/EVENT/g' \
-e 's/\<event\>/event_id/g' \
-e 's/counter/event/g' \
-e 's/Counter/Event/g' \
$FILES
... to keep it as correct as possible. This script can also be
used by anyone who has pending perfcounters patches - it converts
a Linux kernel tree over to the new naming. We tried to time this
change to the point in time where the amount of pending patches
is the smallest: the end of the merge window.
Namespace clashes were fixed up in a preparatory patch - and some
stylistic fallout will be fixed up in a subsequent patch.
( NOTE: 'counters' are still the proper terminology when we deal
with hardware registers - and these sed scripts are a bit
over-eager in renaming them. I've undone some of that, but
in case there's something left where 'counter' would be
better than 'event' we can undo that on an individual basis
instead of touching an otherwise nicely automated patch. )
Suggested-by: Stephane Eranian <eranian@google.com>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Paul Mackerras <paulus@samba.org>
Reviewed-by: Arjan van de Ven <arjan@linux.intel.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Kyle McMartin <kyle@mcmartin.ca>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: <linux-arch@vger.kernel.org>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-09-21 18:02:48 +08:00
|
|
|
struct perf_event_attr *
|
2009-08-17 02:56:37 +08:00
|
|
|
perf_header__find_attr(u64 id, struct perf_header *header)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < header->attrs; i++) {
|
|
|
|
struct perf_header_attr *attr = header->attr[i];
|
|
|
|
int j;
|
|
|
|
|
|
|
|
for (j = 0; j < attr->ids; j++) {
|
|
|
|
if (attr->id[j] == id)
|
|
|
|
return &attr->attr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|