perf: 'perf kvm' tool for monitoring guest performance from host

Here is the patch of userspace perf tool.

Signed-off-by: Zhang Yanmin <yanmin_zhang@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
Zhang, Yanmin
2010-04-19 13:32:50 +08:00
committed by Avi Kivity
parent ff9d07a0e7
commit a1645ce12a
30 changed files with 1407 additions and 316 deletions

View File

@@ -190,7 +190,8 @@ static int write_padded(int fd, const void *bf, size_t count,
continue; \
else
static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
u16 misc, int fd)
{
struct dso *pos;
@@ -205,6 +206,7 @@ static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
len = ALIGN(len, NAME_ALIGN);
memset(&b, 0, sizeof(b));
memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
b.pid = pid;
b.header.misc = misc;
b.header.size = sizeof(b) + len;
err = do_write(fd, &b, sizeof(b));
@@ -219,13 +221,33 @@ static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
return 0;
}
static int dsos__write_buildid_table(int fd)
static int dsos__write_buildid_table(struct perf_header *header, int fd)
{
int err = __dsos__write_buildid_table(&dsos__kernel,
PERF_RECORD_MISC_KERNEL, fd);
if (err == 0)
err = __dsos__write_buildid_table(&dsos__user,
PERF_RECORD_MISC_USER, fd);
struct perf_session *session = container_of(header,
struct perf_session, header);
struct rb_node *nd;
int err = 0;
u16 kmisc, umisc;
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
rb_node);
if (is_host_kernel(pos)) {
kmisc = PERF_RECORD_MISC_KERNEL;
umisc = PERF_RECORD_MISC_USER;
} else {
kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
umisc = PERF_RECORD_MISC_GUEST_USER;
}
err = __dsos__write_buildid_table(&pos->dsos__kernel, pos->pid,
kmisc, fd);
if (err == 0)
err = __dsos__write_buildid_table(&pos->dsos__user,
pos->pid, umisc, fd);
if (err)
break;
}
return err;
}
@@ -342,9 +364,12 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
return err;
}
static int dsos__cache_build_ids(void)
static int dsos__cache_build_ids(struct perf_header *self)
{
int err_kernel, err_user;
struct perf_session *session = container_of(self,
struct perf_session, header);
struct rb_node *nd;
int ret = 0;
char debugdir[PATH_MAX];
snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
@@ -353,9 +378,30 @@ static int dsos__cache_build_ids(void)
if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
return -1;
err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir);
err_user = __dsos__cache_build_ids(&dsos__user, debugdir);
return err_kernel || err_user ? -1 : 0;
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
rb_node);
ret |= __dsos__cache_build_ids(&pos->dsos__kernel, debugdir);
ret |= __dsos__cache_build_ids(&pos->dsos__user, debugdir);
}
return ret ? -1 : 0;
}
static bool dsos__read_build_ids(struct perf_header *self, bool with_hits)
{
bool ret = false;
struct perf_session *session = container_of(self,
struct perf_session, header);
struct rb_node *nd;
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
rb_node);
ret |= __dsos__read_build_ids(&pos->dsos__kernel, with_hits);
ret |= __dsos__read_build_ids(&pos->dsos__user, with_hits);
}
return ret;
}
static int perf_header__adds_write(struct perf_header *self, int fd)
@@ -366,7 +412,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
u64 sec_start;
int idx = 0, err;
if (dsos__read_build_ids(true))
if (dsos__read_build_ids(self, true))
perf_header__set_feat(self, HEADER_BUILD_ID);
nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
@@ -401,14 +447,14 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
/* Write build-ids */
buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
err = dsos__write_buildid_table(fd);
err = dsos__write_buildid_table(self, fd);
if (err < 0) {
pr_debug("failed to write buildid table\n");
goto out_free;
}
buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
buildid_sec->offset;
dsos__cache_build_ids();
dsos__cache_build_ids(self);
}
lseek(fd, sec_start, SEEK_SET);
@@ -633,6 +679,85 @@ int perf_file_header__read(struct perf_file_header *self,
return 0;
}
static int __event_process_build_id(struct build_id_event *bev,
char *filename,
struct perf_session *session)
{
int err = -1;
struct list_head *head;
struct kernel_info *kerninfo;
u16 misc;
struct dso *dso;
enum dso_kernel_type dso_type;
kerninfo = kerninfo__findnew(&session->kerninfo_root, bev->pid);
if (!kerninfo)
goto out;
misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
switch (misc) {
case PERF_RECORD_MISC_KERNEL:
dso_type = DSO_TYPE_KERNEL;
head = &kerninfo->dsos__kernel;
break;
case PERF_RECORD_MISC_GUEST_KERNEL:
dso_type = DSO_TYPE_GUEST_KERNEL;
head = &kerninfo->dsos__kernel;
break;
case PERF_RECORD_MISC_USER:
case PERF_RECORD_MISC_GUEST_USER:
dso_type = DSO_TYPE_USER;
head = &kerninfo->dsos__user;
break;
default:
goto out;
}
dso = __dsos__findnew(head, filename);
if (dso != NULL) {
dso__set_build_id(dso, &bev->build_id);
if (filename[0] == '[')
dso->kernel = dso_type;
}
err = 0;
out:
return err;
}
static int perf_header__read_build_ids(struct perf_header *self,
int input, u64 offset, u64 size)
{
struct perf_session *session = container_of(self,
struct perf_session, header);
struct build_id_event bev;
char filename[PATH_MAX];
u64 limit = offset + size;
int err = -1;
while (offset < limit) {
ssize_t len;
if (read(input, &bev, sizeof(bev)) != sizeof(bev))
goto out;
if (self->needs_swap)
perf_event_header__bswap(&bev.header);
len = bev.header.size - sizeof(bev);
if (read(input, filename, len) != len)
goto out;
__event_process_build_id(&bev, filename, session);
offset += bev.header.size;
}
err = 0;
out:
return err;
}
static int perf_file_section__process(struct perf_file_section *self,
struct perf_header *ph,
int feat, int fd)
@@ -989,6 +1114,7 @@ int event__process_tracing_data(event_t *self,
int event__synthesize_build_id(struct dso *pos, u16 misc,
event__handler_t process,
struct kernel_info *kerninfo,
struct perf_session *session)
{
event_t ev;
@@ -1005,6 +1131,7 @@ int event__synthesize_build_id(struct dso *pos, u16 misc,
memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id));
ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;
ev.build_id.header.misc = misc;
ev.build_id.pid = kerninfo->pid;
ev.build_id.header.size = sizeof(ev.build_id) + len;
memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
@@ -1015,6 +1142,7 @@ int event__synthesize_build_id(struct dso *pos, u16 misc,
static int __event_synthesize_build_ids(struct list_head *head, u16 misc,
event__handler_t process,
struct kernel_info *kerninfo,
struct perf_session *session)
{
struct dso *pos;
@@ -1024,7 +1152,8 @@ static int __event_synthesize_build_ids(struct list_head *head, u16 misc,
if (!pos->hit)
continue;
err = event__synthesize_build_id(pos, misc, process, session);
err = event__synthesize_build_id(pos, misc, process,
kerninfo, session);
if (err < 0)
return err;
}
@@ -1035,44 +1164,48 @@ static int __event_synthesize_build_ids(struct list_head *head, u16 misc,
int event__synthesize_build_ids(event__handler_t process,
struct perf_session *session)
{
int err;
int err = 0;
u16 kmisc, umisc;
struct kernel_info *pos;
struct rb_node *nd;
if (!dsos__read_build_ids(true))
if (!dsos__read_build_ids(&session->header, true))
return 0;
err = __event_synthesize_build_ids(&dsos__kernel,
PERF_RECORD_MISC_KERNEL,
process, session);
if (err == 0)
err = __event_synthesize_build_ids(&dsos__user,
PERF_RECORD_MISC_USER,
process, session);
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
pos = rb_entry(nd, struct kernel_info, rb_node);
if (is_host_kernel(pos)) {
kmisc = PERF_RECORD_MISC_KERNEL;
umisc = PERF_RECORD_MISC_USER;
} else {
kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
umisc = PERF_RECORD_MISC_GUEST_USER;
}
err = __event_synthesize_build_ids(&pos->dsos__kernel,
kmisc, process, pos, session);
if (err == 0)
err = __event_synthesize_build_ids(&pos->dsos__user,
umisc, process, pos, session);
if (err)
break;
}
if (err < 0) {
pr_debug("failed to synthesize build ids\n");
return err;
}
dsos__cache_build_ids();
dsos__cache_build_ids(&session->header);
return 0;
}
int event__process_build_id(event_t *self,
struct perf_session *session __unused)
struct perf_session *session)
{
struct list_head *head = &dsos__user;
struct dso *dso;
if (self->build_id.header.misc & PERF_RECORD_MISC_KERNEL)
head = &dsos__kernel;
dso = __dsos__findnew(head, self->build_id.filename);
if (dso != NULL) {
dso__set_build_id(dso, &self->build_id.build_id);
if (head == &dsos__kernel && self->build_id.filename[0] == '[')
dso->kernel = 1;
}
__event_process_build_id(&self->build_id,
self->build_id.filename,
session);
return 0;
}