[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 7 of 8] xenalyze: Introduce more efficient read mechanism
The pread functionality was convenient for reading at arbitrary offsets within a file, but it was incredibly inefficient; after recent optimizations, a summary analysis was spending 30% of its time doing system calls, and indications were that a big chunk of the rest of the overhead was due to cache misses coming out of that path. This patch introduces a read using mmap. Because the file may be too big to map on 32-bit systems, I use a "mapcache" of 8 different 2MiB buffers. If an offset is in what's already mapped, I just copy it; if not, I unmap one of the buffers and map it instead. This optimization alone took the summary processing time for my test trace from 34s down to 10s. Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxxxxx> diff -r 108d02354403 -r f86ebfe66384 Makefile --- a/Makefile Thu Jan 26 17:17:53 2012 +0000 +++ b/Makefile Thu Jan 26 17:18:13 2012 +0000 @@ -13,7 +13,7 @@ CFLAGS += -Werror BIN = xenalyze dump-raw -HDRS = trace.h analyze.h +HDRS = trace.h analyze.h mread.h all: $(BIN) @@ -23,3 +23,6 @@ clean: %: %.c $(HDRS) Makefile $(CC) $(CFLAGS) -o $@ $< + +xenalyze: xenalyze.o mread.o + $(CC) $(CFLAGS) -o $@ $^ diff -r 108d02354403 -r f86ebfe66384 mread.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mread.c Thu Jan 26 17:18:13 2012 +0000 @@ -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, len); + + /* 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 +} diff -r 108d02354403 -r f86ebfe66384 mread.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mread.h Thu Jan 26 17:18:13 2012 +0000 @@ -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); diff -r 108d02354403 -r f86ebfe66384 xenalyze.c --- a/xenalyze.c Thu Jan 26 17:17:53 2012 +0000 +++ b/xenalyze.c Thu Jan 26 17:18:13 2012 +0000 @@ -31,11 +31,15 @@ #include <unistd.h> #include "trace.h" #include "analyze.h" +#include "mread.h" #include <errno.h> #include <strings.h> #include <string.h> #include <assert.h> +struct mread_ctrl; + + typedef unsigned long long tsc_t; #define DEFAULT_CPU_HZ 2400000000LL @@ -60,6 +64,7 @@ struct array_struct { /* -- Global variables -- */ struct { int fd; + struct mread_ctrl *mh; struct symbol_struct * symbols; char * symbol_file; char * trace_file; @@ -257,18 +262,23 @@ struct { /* -- on-disk trace buffer definitions -- */ struct trace_record { - 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; + 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]; + }; }; FILE *warn = NULL; @@ -1943,7 +1953,7 @@ char * pcpu_string(int pcpu); void pcpu_string_draw(struct pcpu_info *p); void process_generic(struct record_info *ri); void dump_generic(FILE *f, struct record_info *ri); -ssize_t __read_record(int fd, struct trace_record *rec, loff_t offset); +ssize_t __read_record(struct trace_record *rec, loff_t offset); void error(enum error_level l, struct record_info *ri); void update_io_address(struct io_address ** list, unsigned int pa, int dir, tsc_t arc_cycles, unsigned int va); @@ -8123,17 +8133,26 @@ void dump_raw(char * s, struct record_in int i; if(ri->rec.cycle_flag) - printf("%s %x %d %lld [", + printf("%s %7x %d %14lld [", s, ri->event, ri->extra_words, ri->tsc); else - printf("%s %x %d - [", - s, ri->event, ri->extra_words); - - for(i=0; i<ri->extra_words; i++) { - printf(" %x", ri->d[i]); + printf("%s %7x %d %14s [", + s, ri->event, ri->extra_words, "-"); + + for(i=0; i<7; i++) { + if ( i < ri->extra_words ) + printf(" %8x", ri->d[i]); + else + printf(" "); } - printf(" ]\n"); + printf(" ] | "); + + for (i=0; i<8; i++) { + printf(" %08x", ri->rec.raw[i]); + } + + printf(" |\n"); } void error(enum error_level l, struct record_info *ri) @@ -8455,7 +8474,7 @@ loff_t scan_for_new_pcpu(loff_t offset) struct trace_record rec; struct cpu_change_data *cd; - r=__read_record(G.fd, &rec, offset); + r=__read_record(&rec, offset); if(r==0) return 0; @@ -9028,11 +9047,11 @@ void progress_finish(void) { } } -ssize_t __read_record(int fd, struct trace_record *rec, loff_t offset) +ssize_t __read_record(struct trace_record *rec, loff_t offset) { ssize_t r, rsize; - r=pread64(G.fd, rec, sizeof(*rec), offset); + r=mread64(G.mh, rec, sizeof(*rec), offset); if(r < 0) { /* Read error */ @@ -9110,14 +9129,14 @@ void __fill_in_record_info(struct pcpu_i ri->cpu = p->pid; } -ssize_t read_record(int fd, struct pcpu_info * p) { +ssize_t read_record(struct pcpu_info * p) { loff_t * offset; struct record_info *ri; offset = &p->file_offset; ri = &p->ri; - ri->size = __read_record(fd, &ri->rec, *offset); + ri->size = __read_record(&ri->rec, *offset); if(ri->size) { __fill_in_record_info(p); @@ -9317,7 +9336,7 @@ void process_records(void) { } } else - read_record(G.fd, p); + read_record(p); /* Update this pcpu in the processing order */ if ( p->active ) @@ -10304,6 +10323,10 @@ int main(int argc, char *argv[]) { fstat64(G.fd, &s); G.file_size = s.st_size; } + + if ( (G.mh = mread_init(G.fd)) == NULL ) + perror("mread"); + if (G.symbol_file != NULL) parse_symbol_file(G.symbol_file); _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |