|
Message
From: =?unknown-8bit?Q?Gy=F6rgy?= 'nog' Jeney<nog@s...>
Date: Tue Jul 5 17:53:00 CEST 2005
Subject: [openrisc] [or1ksim #141] Hughe recompiler speed up
Hi,The recompiler spent too much of its time walking through the array of pages recompiled in find_dynd_page(). This removes this linked list infavour of an array lookup. The array is 524288 elements or 2mb in size. This increase in required memory isn't significant as the recompiler will use close to 40mb of memory while booting linux. Another big task is reduceing the insanely hughe size of the generated code.
Without patch: real 0m15.843s user 0m15.530s sys 0m0.310s
With patch: real 0m5.967s user 0m5.680s sys 0m0.290s
ChangeLog: * Use an array to keep track of the recompiled pages instead of a linked list.
nog. -------------- next part -------------- diff -upr --unidirectional-new-file ./cpu/common/execute.h /home/nog/or1ksim-ac/cpu/common/execute.h --- ./cpu/common/execute.h 2005-07-05 06:18:33.000000000 +0200 +++ /home/nog/or1ksim-ac/cpu/common/execute.h 2005-07-05 10:07:03.000000000 +0200 @@ -52,8 +52,8 @@ struct cpu_state { /* Current page in execution */ struct dyn_page *curr_page; - /* Linked list of recompiled pages with their status */ - struct dyn_page *dyn_pages; + /* Pointers to recompiled pages */ + struct dyn_page **dyn_pages; /* Micro operation queue. Only used to speed up recompile_page */ struct op_queue *opqs; diff -upr --unidirectional-new-file ./cpu/or32/dyn_rec.c /home/nog/or1ksim-ac/cpu/or32/dyn_rec.c --- ./cpu/or32/dyn_rec.c 2005-07-05 15:19:30.000000000 +0200 +++ /home/nog/or1ksim-ac/cpu/or32/dyn_rec.c 2005-07-05 15:53:03.000000000 +0200 @@ -314,7 +314,10 @@ void dyn_sigsegv_debug(int u, siginfo_t sigsegv_state++; case 1: /* Run through the recompiled pages, dumping them to disk as we go */ - for(dp = cpu_state.dyn_pages; dp; dp = dp->next) { + for(i = 0; i < (2 << (32 - config.dmmu.pagesize_log2)); i++) { + dp = cpu_state.dyn_pages[i]; + if(!dp) + continue; fprintf(stderr, "Dumping%s page 0x%"PRIxADDR" recompiled to %p (len: %u) to disk\n", dp->dirty ? " dirty" : "", dp->or_page, dp->host_page, dp->host_len); @@ -364,24 +367,6 @@ void dyn_sigsegv_debug(int u, siginfo_t } } -static void add_to_dp(struct dyn_page *new) -{ - struct dyn_page *cur; - struct dyn_page *prev; - - /* Find the location to insert the address */ - for(cur = cpu_state.dyn_pages, prev = NULL; cur; prev = cur, cur = cur->next) { - if(cur->or_page > new->or_page) - break; - } - - if(prev) - prev->next = new; - else - cpu_state.dyn_pages = new; - new->next = cur; -} - struct dyn_page *new_dp(oraddr_t page) { struct dyn_page *dp = malloc(sizeof(struct dyn_page)); @@ -393,25 +378,10 @@ struct dyn_page *new_dp(oraddr_t page) dp->host_page = NULL; dp->dirty = 1; - add_to_dp(dp); + cpu_state.dyn_pages[dp->or_page >> config.immu.pagesize_log2] = dp; return dp; } -struct dyn_page *find_dynd_page(oraddr_t addr) -{ - struct dyn_page *cur = cpu_state.dyn_pages; - - addr &= ~(config.immu.pagesize - 1); - while(cur) { - if(cur->or_page == addr) - return cur; - if(cur->or_page > addr) - return NULL; /* The dyn_page linked list is ordered */ - cur = cur->next; - } - return NULL; -} - /* This is called whenever the immu is either enabled/disabled or reconfigured
* while enabled. This checks if an itlb miss would occour and updates the immu
* hit delay counter */
@@ -516,12 +486,12 @@ void dirtyfy_page(struct dyn_page *dp)
void dyn_checkwrite(oraddr_t addr)
{
/* FIXME: Do this with mprotect() */
- struct dyn_page *dp;
+ struct dyn_page *dp = cpu_state.dyn_pages[addr >> config.immu.pagesize_log2];
/* Since the locations 0x0-0xff are nearly always written to in an exception
* handler, ignore any writes to these locations. If code ends up jumping
* out there, we'll recompile when the jump actually happens. */
- if((addr > 0x100) && (dp = find_dynd_page(addr)) && !dp->dirty)
+ if((addr > 0x100) && dp && !dp->dirty)
dirtyfy_page(dp);
}
@@ -684,7 +654,13 @@ void init_dyn_recomp(void)
rec_stack_base = get_sp();
cpu_state.curr_page = NULL;
- cpu_state.dyn_pages = NULL;
+ if(!(cpu_state.dyn_pages = malloc(sizeof(void *) * (2 << (32 -
+ config.immu.pagesize_log2))))) {
+ fprintf(stderr, "OOM\n");
+ exit(1);
+ }
+ memset(cpu_state.dyn_pages, 0,
+ sizeof(void *) * (2 << (32 - config.immu.pagesize_log2)));
/* Register our segmentation fault handler */
sigact.sa_sigaction = dyn_sigsegv_debug;
diff -upr --unidirectional-new-file ./cpu/or32/dyn_rec.h /home/nog/or1ksim-ac/cpu/or32/dyn_rec.h
--- ./cpu/or32/dyn_rec.h 2005-07-05 06:18:33.000000000 +0200
+++ /home/nog/or1ksim-ac/cpu/or32/dyn_rec.h 2005-07-05 15:52:57.000000000 +0200
@@ -33,10 +33,8 @@ struct dyn_page {
uint16_t ts_bound[2049]; /* What registers the temporaries back (on the
* begining boundry of the instruction) */
void **locs; /* Openrisc locations in the recompiled code */
- struct dyn_page *next;
};
-struct dyn_page *find_dynd_page(oraddr_t addr);
void recompile_page(struct dyn_page *dyn);
struct dyn_page *new_dp(oraddr_t page);
void add_to_opq(struct op_queue *opq, int end, int op);
diff -upr --unidirectional-new-file ./cpu/or32/op_support.c /home/nog/or1ksim-ac/cpu/or32/op_support.c
--- ./cpu/or32/op_support.c 2005-07-05 15:34:24.000000000 +0200
+++ /home/nog/or1ksim-ac/cpu/or32/op_support.c 2005-07-05 15:52:45.000000000 +0200
@@ -155,7 +155,7 @@ void do_jump(oraddr_t addr)
* it will produce wrong results */
runtime.sim.mem_cycles = 0;
- target_dp = find_dynd_page(phys_page);
+ target_dp = cpu_state.dyn_pages[phys_page >> config.immu.pagesize_log2];
if(!target_dp)
target_dp = new_dp(phys_page);
|
 |