From b362e5e067835d04ddde5fb1277272d4b498b970 Mon Sep 17 00:00:00 2001 From: pbrook Date: Sun, 12 Nov 2006 20:40:55 +0000 Subject: [PATCH] Speed up tlb_flush_page (Daniel Jacobowitz). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2210 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 8 ++++++++ exec-all.h | 12 +++++++++++- exec.c | 15 +++++++-------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 674c0bd..0b49c89 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -80,6 +80,14 @@ typedef unsigned long ram_addr_t; #define TB_JMP_CACHE_BITS 12 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) +/* Only the bottom TB_JMP_PAGE_BITS of the jump cache hash bits vary for + addresses on the same page. The top bits are the same. This allows + TLB invalidation to quickly clear a subset of the hash table. */ +#define TB_JMP_PAGE_BITS (TB_JMP_CACHE_BITS / 2) +#define TB_JMP_PAGE_SIZE (1 << TB_JMP_PAGE_BITS) +#define TB_JMP_ADDR_MASK (TB_JMP_PAGE_SIZE - 1) +#define TB_JMP_PAGE_MASK (TB_JMP_CACHE_SIZE - TB_JMP_PAGE_SIZE) + #define CPU_TLB_BITS 8 #define CPU_TLB_SIZE (1 << CPU_TLB_BITS) diff --git a/exec-all.h b/exec-all.h index b598948..82ef3ac 100644 --- a/exec-all.h +++ b/exec-all.h @@ -196,9 +196,19 @@ typedef struct TranslationBlock { struct TranslationBlock *jmp_first; } TranslationBlock; +static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) +{ + target_ulong tmp; + tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); + return (tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK; +} + static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) { - return (pc ^ (pc >> TB_JMP_CACHE_BITS)) & (TB_JMP_CACHE_SIZE - 1); + target_ulong tmp; + tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); + return (((tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK) | + (tmp & TB_JMP_ADDR_MASK)); } static inline unsigned int tb_phys_hash_func(unsigned long pc) diff --git a/exec.c b/exec.c index 20870ad..762d6dc 100644 --- a/exec.c +++ b/exec.c @@ -1288,14 +1288,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr) tlb_flush_entry(&env->tlb_table[0][i], addr); tlb_flush_entry(&env->tlb_table[1][i], addr); - for(i = 0; i < TB_JMP_CACHE_SIZE; i++) { - tb = env->tb_jmp_cache[i]; - if (tb && - ((tb->pc & TARGET_PAGE_MASK) == addr || - ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr)) { - env->tb_jmp_cache[i] = NULL; - } - } + /* Discard jump cache entries for any tb which might potentially + overlap the flushed page. */ + i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE); + memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb)); + + i = tb_jmp_cache_hash_page(addr); + memset (&env->tb_jmp_cache[i], 0, TB_JMP_PAGE_SIZE * sizeof(tb)); #if !defined(CONFIG_SOFTMMU) if (addr < MMAP_AREA_END) -- 2.7.4