mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xenalyze: add to tools/xentrace/
This merges xenalyze.hg, changeset 150:24308507be1d, into tools/xentrace/xenalyze.c to have the tool and public/trace.h in one place. Adjust code to use public/trace.h instead of private trace.h Signed-off-by: Olaf Hering <olaf@aepfle.de> Acked-by: Wei Liu <wei.liu2@citrix.com> Acked-by: George Dunlap <george.dunlap@eu.citrix.com> Cc: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> Cc: Wei Liu <wei.liu2@citrix.com> [ ijc -- wrap $(BIN) install in a check in case it is empty (which it is on !x86, avoid BIN += since it results in BIN = ' ' on !x86 ]
This commit is contained in:
1 parent
2fdf3c433a
commit
fd19a9976e
7 files changed
+10742
-1
No files matched your search
@@ -173,6 +173,7 @@ tools/misc/gtracestat
|
||||
tools/misc/xenlockprof
|
||||
tools/misc/lowmemd
|
||||
tools/misc/xencov
|
||||
tools/xentrace/xenalyze
|
||||
tools/pygrub/build/*
|
||||
tools/python/build/*
|
||||
tools/security/secpol_tool
|
||||
|
||||
@@ -6,7 +6,8 @@ CFLAGS += -Werror
|
||||
CFLAGS += $(CFLAGS_libxenctrl)
|
||||
LDLIBS += $(LDLIBS_libxenctrl)
|
||||
|
||||
BIN =
|
||||
BIN-$(CONFIG_X86) = xenalyze
|
||||
BIN = $(BIN-y)
|
||||
SBIN = xentrace xentrace_setsize
|
||||
LIBBIN = xenctx
|
||||
SCRIPTS = xentrace_format
|
||||
@@ -26,6 +27,9 @@ install: build
|
||||
[ -z "$(LIBBIN)" ] || $(INSTALL_DIR) $(DESTDIR)$(LIBEXEC_BIN)
|
||||
$(INSTALL_DIR) $(DESTDIR)$(MAN1DIR)
|
||||
$(INSTALL_DIR) $(DESTDIR)$(MAN8DIR)
|
||||
ifneq ($(BIN),)
|
||||
$(INSTALL_PROG) $(BIN) $(DESTDIR)$(bindir)
|
||||
endif
|
||||
$(INSTALL_PROG) $(SBIN) $(DESTDIR)$(sbindir)
|
||||
$(INSTALL_PYTHON_PROG) $(SCRIPTS) $(DESTDIR)$(bindir)
|
||||
[ -z "$(LIBBIN)" ] || $(INSTALL_PROG) $(LIBBIN) $(DESTDIR)$(LIBEXEC_BIN)
|
||||
@@ -48,5 +52,8 @@ xenctx: xenctx.o
|
||||
xentrace_setsize: setsize.o
|
||||
$(CC) $(LDFLAGS) -o $@ $< $(LDLIBS) $(APPEND_LDFLAGS)
|
||||
|
||||
xenalyze: xenalyze.o mread.o
|
||||
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(APPEND_LDFLAGS)
|
||||
|
||||
-include $(DEPS)
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#ifndef __ANALYZE_H
|
||||
# define __ANALYZE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
#define TRC_GEN_MAIN 0
|
||||
#define TRC_SCHED_MAIN 1
|
||||
#define TRC_DOM0OP_MAIN 2
|
||||
#define TRC_HVM_MAIN 3
|
||||
#define TRC_MEM_MAIN 4
|
||||
#define TRC_PV_MAIN 5
|
||||
#define TRC_SHADOW_MAIN 6
|
||||
#define TRC_HW_MAIN 7
|
||||
|
||||
#define TRC_LOST_RECORDS_END (TRC_GEN + 50)
|
||||
|
||||
#define NR_CPUS 128
|
||||
#if __x86_64__
|
||||
# define BITS_PER_LONG 64
|
||||
#else
|
||||
# define BITS_PER_LONG 32
|
||||
#endif
|
||||
|
||||
#define BITS_TO_LONGS(bits) \
|
||||
(((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
|
||||
#define DECLARE_BITMAP(name,bits) \
|
||||
unsigned long name[BITS_TO_LONGS(bits)]
|
||||
typedef struct cpumask{ DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
|
||||
|
||||
enum {
|
||||
TRCE_SFLAG_SET_AD,
|
||||
TRCE_SFLAG_SET_A,
|
||||
TRCE_SFLAG_SHADOW_L1_GET_REF,
|
||||
TRCE_SFLAG_SHADOW_L1_PUT_REF,
|
||||
TRCE_SFLAG_L2_PROPAGATE,
|
||||
TRCE_SFLAG_SET_CHANGED,
|
||||
TRCE_SFLAG_SET_FLUSH,
|
||||
TRCE_SFLAG_SET_ERROR,
|
||||
TRCE_SFLAG_DEMOTE,
|
||||
TRCE_SFLAG_PROMOTE,
|
||||
TRCE_SFLAG_WRMAP,
|
||||
TRCE_SFLAG_WRMAP_GUESS_FOUND,
|
||||
TRCE_SFLAG_WRMAP_BRUTE_FORCE,
|
||||
TRCE_SFLAG_EARLY_UNSHADOW,
|
||||
TRCE_SFLAG_EMULATION_2ND_PT_WRITTEN,
|
||||
TRCE_SFLAG_EMULATION_LAST_FAILED,
|
||||
TRCE_SFLAG_EMULATE_FULL_PT,
|
||||
TRCE_SFLAG_PREALLOC_UNPIN,
|
||||
TRCE_SFLAG_PREALLOC_UNHOOK
|
||||
};
|
||||
|
||||
#define TRC_HVM_OP_DESTROY_PROC (TRC_HVM_HANDLER + 0x100)
|
||||
|
||||
typedef unsigned long long tsc_t;
|
||||
|
||||
/* -- on-disk trace buffer definitions -- */
|
||||
struct trace_record {
|
||||
union {
|
||||
struct {
|
||||
unsigned event:28,
|
||||
extra_words:3,
|
||||
cycle_flag:1;
|
||||
union {
|
||||
struct {
|
||||
uint32_t tsc_lo, tsc_hi;
|
||||
uint32_t data[7];
|
||||
} tsc;
|
||||
struct {
|
||||
uint32_t data[7];
|
||||
} notsc;
|
||||
} u;
|
||||
};
|
||||
uint32_t raw[8];
|
||||
};
|
||||
};
|
||||
|
||||
/* -- General info about a current record -- */
|
||||
struct time_struct {
|
||||
unsigned long long time;
|
||||
unsigned int s, ns;
|
||||
};
|
||||
|
||||
#define DUMP_HEADER_MAX 256
|
||||
|
||||
struct record_info {
|
||||
int cpu;
|
||||
tsc_t tsc;
|
||||
union {
|
||||
unsigned event;
|
||||
struct {
|
||||
unsigned minor:12,
|
||||
sub:4,
|
||||
main:12,
|
||||
unused:4;
|
||||
} evt;
|
||||
};
|
||||
int extra_words;
|
||||
int size;
|
||||
uint32_t *d;
|
||||
char dump_header[DUMP_HEADER_MAX];
|
||||
struct time_struct t;
|
||||
struct trace_record rec;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,160 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#include "mread.h"
|
||||
|
||||
mread_handle_t mread_init(int fd)
|
||||
{
|
||||
struct stat64 s;
|
||||
mread_handle_t h;
|
||||
|
||||
h=malloc(sizeof(struct mread_ctrl));
|
||||
|
||||
if (!h)
|
||||
{
|
||||
perror("malloc");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bzero(h, sizeof(struct mread_ctrl));
|
||||
|
||||
h->fd = fd;
|
||||
|
||||
fstat64(fd, &s);
|
||||
h->file_size = s.st_size;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
ssize_t mread64(mread_handle_t h, void *rec, ssize_t len, loff_t offset)
|
||||
{
|
||||
/* Idea: have a "cache" of N mmaped regions. If the offset is
|
||||
* in one of the regions, just copy it. If not, evict one of the
|
||||
* regions and map the appropriate range.
|
||||
*
|
||||
* Basic algorithm:
|
||||
* - See if the offset is in one of the regions
|
||||
* - If not, map it
|
||||
* - evict an old region
|
||||
* - map the new region
|
||||
* - Copy
|
||||
*/
|
||||
char * b=NULL;
|
||||
int bind=-1;
|
||||
loff_t boffset=0;
|
||||
ssize_t bsize;
|
||||
|
||||
#define dprintf(x...)
|
||||
//#define dprintf fprintf
|
||||
|
||||
dprintf(warn, "%s: offset %llx len %d\n", __func__,
|
||||
offset, len);
|
||||
if ( offset > h->file_size )
|
||||
{
|
||||
dprintf(warn, " offset > file size %llx, returning 0\n",
|
||||
h->file_size);
|
||||
return 0;
|
||||
}
|
||||
if ( offset + len > h->file_size )
|
||||
{
|
||||
dprintf(warn, " offset+len > file size %llx, truncating\n",
|
||||
h->file_size);
|
||||
len = h->file_size - offset;
|
||||
}
|
||||
|
||||
/* Try to find the offset in our range */
|
||||
dprintf(warn, " Trying last, %d\n", last);
|
||||
if ( h->map[h->last].buffer
|
||||
&& (offset & MREAD_BUF_MASK) == h->map[h->last].start_offset )
|
||||
{
|
||||
bind=h->last;
|
||||
goto copy;
|
||||
}
|
||||
|
||||
/* Scan to see if it's anywhere else */
|
||||
dprintf(warn, " Scanning\n");
|
||||
for(bind=0; bind<MREAD_MAPS; bind++)
|
||||
if ( h->map[bind].buffer
|
||||
&& (offset & MREAD_BUF_MASK) == h->map[bind].start_offset )
|
||||
{
|
||||
dprintf(warn, " Found, index %d\n", bind);
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we didn't find it, evict someone and map it */
|
||||
if ( bind == MREAD_MAPS )
|
||||
{
|
||||
dprintf(warn, " Clock\n");
|
||||
while(1)
|
||||
{
|
||||
h->clock++;
|
||||
if(h->clock >= MREAD_MAPS)
|
||||
h->clock=0;
|
||||
dprintf(warn, " %d\n", h->clock);
|
||||
if(h->map[h->clock].buffer == NULL)
|
||||
{
|
||||
dprintf(warn, " Buffer null, using\n");
|
||||
break;
|
||||
}
|
||||
if(!h->map[h->clock].accessed)
|
||||
{
|
||||
dprintf(warn, " Not accessed, using\n");
|
||||
break;
|
||||
}
|
||||
h->map[h->clock].accessed=0;
|
||||
}
|
||||
if(h->map[h->clock].buffer)
|
||||
{
|
||||
dprintf(warn, " Unmapping\n");
|
||||
munmap(h->map[h->clock].buffer, MREAD_BUF_SIZE);
|
||||
}
|
||||
/* FIXME: Try MAP_HUGETLB? */
|
||||
/* FIXME: Make sure this works on large files... */
|
||||
h->map[h->clock].start_offset = offset & MREAD_BUF_MASK;
|
||||
dprintf(warn, " Mapping %llx from offset %llx\n",
|
||||
MREAD_BUF_SIZE, h->map[h->clock].start_offset);
|
||||
h->map[h->clock].buffer = mmap(NULL, MREAD_BUF_SIZE, PROT_READ,
|
||||
MAP_SHARED,
|
||||
h->fd,
|
||||
h->map[h->clock].start_offset);
|
||||
dprintf(warn, " mmap returned %p\n", h->map[h->clock].buffer);
|
||||
if ( h->map[h->clock].buffer == MAP_FAILED )
|
||||
{
|
||||
h->map[h->clock].buffer = NULL;
|
||||
perror("mmap");
|
||||
exit(1);
|
||||
}
|
||||
bind = h->clock;
|
||||
}
|
||||
|
||||
h->last=bind;
|
||||
copy:
|
||||
h->map[bind].accessed=1;
|
||||
b=h->map[bind].buffer;
|
||||
boffset=offset - h->map[bind].start_offset;
|
||||
if ( boffset + len > MREAD_BUF_SIZE )
|
||||
bsize = MREAD_BUF_SIZE - boffset;
|
||||
else
|
||||
bsize = len;
|
||||
dprintf(warn, " Using index %d, buffer at %p, buffer offset %llx len %d\n",
|
||||
bind, b, boffset, bsize);
|
||||
|
||||
bcopy(b+boffset, rec, bsize);
|
||||
|
||||
/* Handle the boundary case; make sure this is after doing anything
|
||||
* with the static variables*/
|
||||
if ( len > bsize )
|
||||
{
|
||||
dprintf(warn, " Finishing up by reading l %d o %llx\n",
|
||||
len-bsize, offset+bsize);
|
||||
mread64(h, rec+bsize, len-bsize, offset+bsize);
|
||||
}
|
||||
|
||||
/* FIXME: ?? */
|
||||
return len;
|
||||
#undef dprintf
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#define MREAD_MAPS 8
|
||||
#define MREAD_BUF_SHIFT 9
|
||||
#define PAGE_SHIFT 12
|
||||
#define MREAD_BUF_SIZE (1ULL<<(PAGE_SHIFT+MREAD_BUF_SHIFT))
|
||||
#define MREAD_BUF_MASK (~(MREAD_BUF_SIZE-1))
|
||||
typedef struct mread_ctrl {
|
||||
int fd;
|
||||
loff_t file_size;
|
||||
struct mread_buffer {
|
||||
char * buffer;
|
||||
loff_t start_offset;
|
||||
int accessed;
|
||||
} map[MREAD_MAPS];
|
||||
int clock, last;
|
||||
} *mread_handle_t;
|
||||
|
||||
mread_handle_t mread_init(int fd);
|
||||
ssize_t mread64(mread_handle_t h, void *dst, ssize_t len, loff_t offset);
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* PV event decoding.
|
||||
*
|
||||
* Copyright (C) 2012 Citrix Systems R&D Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef __PV_H
|
||||
|
||||
#include "analyze.h"
|
||||
#include <xen/trace.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ARG_MISSING 0x0
|
||||
#define ARG_32BIT 0x1
|
||||
#define ARG_64BIT 0x2
|
||||
|
||||
#define MMU_UPDATE_PREEMPTED (~(~0U>>1))
|
||||
|
||||
static inline uint32_t pv_hypercall_op(const struct record_info *ri)
|
||||
{
|
||||
return ri->d[0] & ~TRC_PV_HYPERCALL_V2_ARG_MASK;
|
||||
}
|
||||
|
||||
static inline int pv_hypercall_arg_present(const struct record_info *ri, int arg)
|
||||
{
|
||||
return (ri->d[0] >> (20 + 2*arg)) & 0x3;
|
||||
}
|
||||
|
||||
void pv_hypercall_gather_args(const struct record_info *ri, uint64_t *args);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff