perf tools: Factorize the map helpers
Factorize the dso mapping helpers into a single purpose common file "util/map.c" Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Brice Goglin <Brice.Goglin@inria.fr>
This commit is contained in:
@@ -340,6 +340,7 @@ LIB_OBJS += util/header.o
|
|||||||
LIB_OBJS += util/callchain.o
|
LIB_OBJS += util/callchain.o
|
||||||
LIB_OBJS += util/values.o
|
LIB_OBJS += util/values.o
|
||||||
LIB_OBJS += util/debug.o
|
LIB_OBJS += util/debug.o
|
||||||
|
LIB_OBJS += util/map.o
|
||||||
|
|
||||||
BUILTIN_OBJS += builtin-annotate.o
|
BUILTIN_OBJS += builtin-annotate.o
|
||||||
BUILTIN_OBJS += builtin-help.o
|
BUILTIN_OBJS += builtin-help.o
|
||||||
|
@@ -51,83 +51,6 @@ struct sym_ext {
|
|||||||
char *path;
|
char *path;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct map {
|
|
||||||
struct list_head node;
|
|
||||||
u64 start;
|
|
||||||
u64 end;
|
|
||||||
u64 pgoff;
|
|
||||||
u64 (*map_ip)(struct map *, u64);
|
|
||||||
struct dso *dso;
|
|
||||||
};
|
|
||||||
|
|
||||||
static u64 map__map_ip(struct map *map, u64 ip)
|
|
||||||
{
|
|
||||||
return ip - map->start + map->pgoff;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u64 vdso__map_ip(struct map *map __used, u64 ip)
|
|
||||||
{
|
|
||||||
return ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct map *map__new(struct mmap_event *event)
|
|
||||||
{
|
|
||||||
struct map *self = malloc(sizeof(*self));
|
|
||||||
|
|
||||||
if (self != NULL) {
|
|
||||||
const char *filename = event->filename;
|
|
||||||
|
|
||||||
self->start = event->start;
|
|
||||||
self->end = event->start + event->len;
|
|
||||||
self->pgoff = event->pgoff;
|
|
||||||
|
|
||||||
self->dso = dsos__findnew(filename);
|
|
||||||
if (self->dso == NULL)
|
|
||||||
goto out_delete;
|
|
||||||
|
|
||||||
if (self->dso == vdso)
|
|
||||||
self->map_ip = vdso__map_ip;
|
|
||||||
else
|
|
||||||
self->map_ip = map__map_ip;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
out_delete:
|
|
||||||
free(self);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct map *map__clone(struct map *self)
|
|
||||||
{
|
|
||||||
struct map *map = malloc(sizeof(*self));
|
|
||||||
|
|
||||||
if (!map)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memcpy(map, self, sizeof(*self));
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int map__overlap(struct map *l, struct map *r)
|
|
||||||
{
|
|
||||||
if (l->start > r->start) {
|
|
||||||
struct map *t = l;
|
|
||||||
l = r;
|
|
||||||
r = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (l->end > r->start)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t map__fprintf(struct map *self, FILE *fp)
|
|
||||||
{
|
|
||||||
return fprintf(fp, " %Lx-%Lx %Lx %s\n",
|
|
||||||
self->start, self->end, self->pgoff, self->dso->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct thread {
|
struct thread {
|
||||||
struct rb_node rb_node;
|
struct rb_node rb_node;
|
||||||
@@ -797,7 +720,7 @@ static int
|
|||||||
process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
|
process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
|
||||||
{
|
{
|
||||||
struct thread *thread = threads__findnew(event->mmap.pid);
|
struct thread *thread = threads__findnew(event->mmap.pid);
|
||||||
struct map *map = map__new(&event->mmap);
|
struct map *map = map__new(&event->mmap, NULL, 0);
|
||||||
|
|
||||||
dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
|
dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
|
||||||
(void *)(offset + head),
|
(void *)(offset + head),
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
|
||||||
#include "util/header.h"
|
#include "util/header.h"
|
||||||
|
#include "util/event.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
|
@@ -67,6 +67,10 @@ static char callchain_default_opt[] = "fractal,0.5";
|
|||||||
|
|
||||||
static int callchain;
|
static int callchain;
|
||||||
|
|
||||||
|
static char __cwd[PATH_MAX];
|
||||||
|
static char *cwd = __cwd;
|
||||||
|
static int cwdlen;
|
||||||
|
|
||||||
static
|
static
|
||||||
struct callchain_param callchain_param = {
|
struct callchain_param callchain_param = {
|
||||||
.mode = CHAIN_GRAPH_REL,
|
.mode = CHAIN_GRAPH_REL,
|
||||||
@@ -102,124 +106,6 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static char __cwd[PATH_MAX];
|
|
||||||
static char *cwd = __cwd;
|
|
||||||
static int cwdlen;
|
|
||||||
|
|
||||||
static int strcommon(const char *pathname)
|
|
||||||
{
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
while (n < cwdlen && pathname[n] == cwd[n])
|
|
||||||
++n;
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct map {
|
|
||||||
struct list_head node;
|
|
||||||
u64 start;
|
|
||||||
u64 end;
|
|
||||||
u64 pgoff;
|
|
||||||
u64 (*map_ip)(struct map *, u64);
|
|
||||||
struct dso *dso;
|
|
||||||
};
|
|
||||||
|
|
||||||
static u64 map__map_ip(struct map *map, u64 ip)
|
|
||||||
{
|
|
||||||
return ip - map->start + map->pgoff;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u64 vdso__map_ip(struct map *map __used, u64 ip)
|
|
||||||
{
|
|
||||||
return ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int is_anon_memory(const char *filename)
|
|
||||||
{
|
|
||||||
return strcmp(filename, "//anon") == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct map *map__new(struct mmap_event *event)
|
|
||||||
{
|
|
||||||
struct map *self = malloc(sizeof(*self));
|
|
||||||
|
|
||||||
if (self != NULL) {
|
|
||||||
const char *filename = event->filename;
|
|
||||||
char newfilename[PATH_MAX];
|
|
||||||
int anon;
|
|
||||||
|
|
||||||
if (cwd) {
|
|
||||||
int n = strcommon(filename);
|
|
||||||
|
|
||||||
if (n == cwdlen) {
|
|
||||||
snprintf(newfilename, sizeof(newfilename),
|
|
||||||
".%s", filename + n);
|
|
||||||
filename = newfilename;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anon = is_anon_memory(filename);
|
|
||||||
|
|
||||||
if (anon) {
|
|
||||||
snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
|
|
||||||
filename = newfilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->start = event->start;
|
|
||||||
self->end = event->start + event->len;
|
|
||||||
self->pgoff = event->pgoff;
|
|
||||||
|
|
||||||
self->dso = dsos__findnew(filename);
|
|
||||||
if (self->dso == NULL)
|
|
||||||
goto out_delete;
|
|
||||||
|
|
||||||
if (self->dso == vdso || anon)
|
|
||||||
self->map_ip = vdso__map_ip;
|
|
||||||
else
|
|
||||||
self->map_ip = map__map_ip;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
out_delete:
|
|
||||||
free(self);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct map *map__clone(struct map *self)
|
|
||||||
{
|
|
||||||
struct map *map = malloc(sizeof(*self));
|
|
||||||
|
|
||||||
if (!map)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memcpy(map, self, sizeof(*self));
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int map__overlap(struct map *l, struct map *r)
|
|
||||||
{
|
|
||||||
if (l->start > r->start) {
|
|
||||||
struct map *t = l;
|
|
||||||
l = r;
|
|
||||||
r = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (l->end > r->start)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t map__fprintf(struct map *self, FILE *fp)
|
|
||||||
{
|
|
||||||
return fprintf(fp, " %Lx-%Lx %Lx %s\n",
|
|
||||||
self->start, self->end, self->pgoff, self->dso->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct thread {
|
struct thread {
|
||||||
struct rb_node rb_node;
|
struct rb_node rb_node;
|
||||||
struct list_head maps;
|
struct list_head maps;
|
||||||
@@ -1474,7 +1360,7 @@ static int
|
|||||||
process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
|
process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
|
||||||
{
|
{
|
||||||
struct thread *thread = threads__findnew(event->mmap.pid);
|
struct thread *thread = threads__findnew(event->mmap.pid);
|
||||||
struct map *map = map__new(&event->mmap);
|
struct map *map = map__new(&event->mmap, cwd, cwdlen);
|
||||||
|
|
||||||
dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
|
dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
|
||||||
(void *)(offset + head),
|
(void *)(offset + head),
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
#include "../perf.h"
|
#include "../perf.h"
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/rbtree.h>
|
#include <linux/rbtree.h>
|
||||||
|
#include "util.h"
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
|
|
||||||
enum chain_mode {
|
enum chain_mode {
|
||||||
|
@@ -1,4 +1,8 @@
|
|||||||
|
#ifndef __PERF_EVENT_H
|
||||||
|
#define __PERF_EVENT_H
|
||||||
#include "../perf.h"
|
#include "../perf.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include <linux/list.h>
|
||||||
|
|
||||||
struct ip_event {
|
struct ip_event {
|
||||||
struct perf_event_header header;
|
struct perf_event_header header;
|
||||||
@@ -52,3 +56,29 @@ typedef union event_union {
|
|||||||
struct lost_event lost;
|
struct lost_event lost;
|
||||||
struct read_event read;
|
struct read_event read;
|
||||||
} event_t;
|
} event_t;
|
||||||
|
|
||||||
|
struct map {
|
||||||
|
struct list_head node;
|
||||||
|
u64 start;
|
||||||
|
u64 end;
|
||||||
|
u64 pgoff;
|
||||||
|
u64 (*map_ip)(struct map *, u64);
|
||||||
|
struct dso *dso;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline u64 map__map_ip(struct map *map, u64 ip)
|
||||||
|
{
|
||||||
|
return ip - map->start + map->pgoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u64 vdso__map_ip(struct map *map __used, u64 ip)
|
||||||
|
{
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
|
||||||
|
struct map *map__clone(struct map *self);
|
||||||
|
int map__overlap(struct map *l, struct map *r);
|
||||||
|
size_t map__fprintf(struct map *self, FILE *fp);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
97
tools/perf/util/map.c
Normal file
97
tools/perf/util/map.c
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#include "event.h"
|
||||||
|
#include "symbol.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static inline int is_anon_memory(const char *filename)
|
||||||
|
{
|
||||||
|
return strcmp(filename, "//anon") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int strcommon(const char *pathname, char *cwd, int cwdlen)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
while (n < cwdlen && pathname[n] == cwd[n])
|
||||||
|
++n;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
|
||||||
|
{
|
||||||
|
struct map *self = malloc(sizeof(*self));
|
||||||
|
|
||||||
|
if (self != NULL) {
|
||||||
|
const char *filename = event->filename;
|
||||||
|
char newfilename[PATH_MAX];
|
||||||
|
int anon;
|
||||||
|
|
||||||
|
if (cwd) {
|
||||||
|
int n = strcommon(filename, cwd, cwdlen);
|
||||||
|
|
||||||
|
if (n == cwdlen) {
|
||||||
|
snprintf(newfilename, sizeof(newfilename),
|
||||||
|
".%s", filename + n);
|
||||||
|
filename = newfilename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anon = is_anon_memory(filename);
|
||||||
|
|
||||||
|
if (anon) {
|
||||||
|
snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
|
||||||
|
filename = newfilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->start = event->start;
|
||||||
|
self->end = event->start + event->len;
|
||||||
|
self->pgoff = event->pgoff;
|
||||||
|
|
||||||
|
self->dso = dsos__findnew(filename);
|
||||||
|
if (self->dso == NULL)
|
||||||
|
goto out_delete;
|
||||||
|
|
||||||
|
if (self->dso == vdso || anon)
|
||||||
|
self->map_ip = vdso__map_ip;
|
||||||
|
else
|
||||||
|
self->map_ip = map__map_ip;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
out_delete:
|
||||||
|
free(self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct map *map__clone(struct map *self)
|
||||||
|
{
|
||||||
|
struct map *map = malloc(sizeof(*self));
|
||||||
|
|
||||||
|
if (!map)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(map, self, sizeof(*self));
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
int map__overlap(struct map *l, struct map *r)
|
||||||
|
{
|
||||||
|
if (l->start > r->start) {
|
||||||
|
struct map *t = l;
|
||||||
|
l = r;
|
||||||
|
r = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l->end > r->start)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t map__fprintf(struct map *self, FILE *fp)
|
||||||
|
{
|
||||||
|
return fprintf(fp, " %Lx-%Lx %Lx %s\n",
|
||||||
|
self->start, self->end, self->pgoff, self->dso->name);
|
||||||
|
}
|
@@ -6,6 +6,7 @@
|
|||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/rbtree.h>
|
#include <linux/rbtree.h>
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
#include "event.h"
|
||||||
|
|
||||||
struct symbol {
|
struct symbol {
|
||||||
struct rb_node rb_node;
|
struct rb_node rb_node;
|
||||||
|
@@ -83,7 +83,6 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "../../../include/linux/magic.h"
|
#include "../../../include/linux/magic.h"
|
||||||
|
|
||||||
#include "event.h"
|
|
||||||
|
|
||||||
#ifndef NO_ICONV
|
#ifndef NO_ICONV
|
||||||
#include <iconv.h>
|
#include <iconv.h>
|
||||||
|
Reference in New Issue
Block a user