summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2008-05-28 12:30:31 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2008-05-28 12:30:31 +0000
commit26a5f13b8eb1281d0552fe323e869806f3cefbfb (patch)
tree6b5d393ea5fba9a28e651dc908f4a3ba9b8ebc32
parentbed5cc520707ba4382444c4fb2afd428df080e6c (diff)
downloadqemu-26a5f13b8eb1281d0552fe323e869806f3cefbfb.tar.gz
variable dynamic translation buffer size
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4600 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--cpu-all.h1
-rw-r--r--darwin-user/main.c1
-rw-r--r--exec-all.h37
-rw-r--r--exec.c86
-rw-r--r--linux-user/main.c1
-rw-r--r--target-i386/cpu.h2
-rw-r--r--vl.c14
7 files changed, 88 insertions, 54 deletions
diff --git a/cpu-all.h b/cpu-all.h
index 9a2a548d70..06dc6d7b16 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -767,6 +767,7 @@ int page_get_flags(target_ulong address);
void page_set_flags(target_ulong start, target_ulong end, int flags);
int page_check_range(target_ulong start, target_ulong len, int flags);
+void cpu_exec_init_all(unsigned long tb_size);
CPUState *cpu_copy(CPUState *env);
void cpu_dump_state(CPUState *env, FILE *f,
diff --git a/darwin-user/main.c b/darwin-user/main.c
index 10b7fcb9a9..20fde19687 100644
--- a/darwin-user/main.c
+++ b/darwin-user/main.c
@@ -873,6 +873,7 @@ int main(int argc, char **argv)
#endif
}
+ cpu_exec_init_all(0);
/* NOTE: we need to init the CPU at this stage to get
qemu_host_page_size */
env = cpu_init(cpu_model);
diff --git a/exec-all.h b/exec-all.h
index d1e581b105..eaf7c40613 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -56,12 +56,6 @@ typedef void (GenOpFunc1)(long);
typedef void (GenOpFunc2)(long, long);
typedef void (GenOpFunc3)(long, long, long);
-#if defined(TARGET_I386)
-
-void optimize_flags_init(void);
-
-#endif
-
extern FILE *logfile;
extern int loglevel;
@@ -105,31 +99,7 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr,
#define CODE_GEN_PHYS_HASH_BITS 15
#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS)
-/* maximum total translate dcode allocated */
-
-/* NOTE: the translated code area cannot be too big because on some
- archs the range of "fast" function calls is limited. Here is a
- summary of the ranges:
-
- i386 : signed 32 bits
- arm : signed 26 bits
- ppc : signed 24 bits
- sparc : signed 32 bits
- alpha : signed 23 bits
-*/
-
-#if defined(__alpha__)
-#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024)
-#elif defined(__ia64)
-#define CODE_GEN_BUFFER_SIZE (4 * 1024 * 1024) /* range of addl */
-#elif defined(__powerpc__)
-#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024)
-#else
-/* XXX: make it dynamic on x86 */
-#define CODE_GEN_BUFFER_SIZE (64 * 1024 * 1024)
-#endif
-
-//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
+#define MIN_CODE_GEN_BUFFER_SIZE (1024 * 1024)
/* estimated block size for TB allocation */
/* XXX: use a per code average code fragment size and modulate it
@@ -140,8 +110,6 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr,
#define CODE_GEN_AVG_BLOCK_SIZE 64
#endif
-#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE)
-
#if defined(__powerpc__) || defined(__x86_64__) || defined(__arm__)
#define USE_DIRECT_JUMP
#endif
@@ -210,9 +178,8 @@ void tb_link_phys(TranslationBlock *tb,
target_ulong phys_pc, target_ulong phys_page2);
extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
-
-extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
extern uint8_t *code_gen_ptr;
+extern int code_gen_max_blocks;
#if defined(USE_DIRECT_JUMP)
diff --git a/exec.c b/exec.c
index 0aaa8358c9..4b6f9bb443 100644
--- a/exec.c
+++ b/exec.c
@@ -58,9 +58,6 @@
#undef DEBUG_TB_CHECK
#endif
-/* threshold to flush the translated code buffer */
-#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - code_gen_max_block_size())
-
#define SMC_BITMAP_USE_THRESHOLD 10
#define MMAP_AREA_START 0x00000000
@@ -85,13 +82,17 @@
#endif
TranslationBlock *tbs;
+int code_gen_max_blocks;
TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
int nb_tbs;
/* any access to the tbs or the page table must use this lock */
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
uint8_t code_gen_prologue[1024] __attribute__((aligned (32)));
-uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32)));
+uint8_t *code_gen_buffer;
+unsigned long code_gen_buffer_size;
+/* threshold to flush the translated code buffer */
+unsigned long code_gen_buffer_max_size;
uint8_t *code_gen_ptr;
ram_addr_t phys_ram_size;
@@ -215,9 +216,6 @@ static void page_init(void)
#else
qemu_real_host_page_size = getpagesize();
#endif
- map_exec(code_gen_buffer, sizeof(code_gen_buffer));
- map_exec(code_gen_prologue, sizeof(code_gen_prologue));
-
if (qemu_host_page_size == 0)
qemu_host_page_size = qemu_real_host_page_size;
if (qemu_host_page_size < TARGET_PAGE_SIZE)
@@ -328,18 +326,67 @@ static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
target_ulong vaddr);
#endif
+void code_gen_alloc(unsigned long tb_size)
+{
+ code_gen_buffer_size = tb_size;
+ if (code_gen_buffer_size == 0) {
+ /* XXX: needs ajustments */
+ code_gen_buffer_size = (int)(phys_ram_size / 4);
+ }
+ if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
+ code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE;
+ /* The code gen buffer location may have constraints depending on
+ the host cpu and OS */
+#if defined(__linux__)
+ {
+ int flags;
+ flags = MAP_PRIVATE | MAP_ANONYMOUS;
+#if defined(__x86_64__)
+ flags |= MAP_32BIT;
+ /* Cannot map more than that */
+ if (code_gen_buffer_size > (800 * 1024 * 1024))
+ code_gen_buffer_size = (800 * 1024 * 1024);
+#endif
+ code_gen_buffer = mmap(NULL, code_gen_buffer_size,
+ PROT_WRITE | PROT_READ | PROT_EXEC,
+ flags, -1, 0);
+ if (code_gen_buffer == MAP_FAILED) {
+ fprintf(stderr, "Could not allocate dynamic translator buffer\n");
+ exit(1);
+ }
+ }
+#else
+ code_gen_buffer = qemu_malloc(code_gen_buffer_size);
+ if (!code_gen_buffer) {
+ fprintf(stderr, "Could not allocate dynamic translator buffer\n");
+ exit(1);
+ }
+ map_exec(code_gen_buffer, code_gen_buffer_size);
+#endif
+ map_exec(code_gen_prologue, sizeof(code_gen_prologue));
+ code_gen_buffer_max_size = code_gen_buffer_size -
+ code_gen_max_block_size();
+ code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
+ tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
+}
+
+/* Must be called before using the QEMU cpus. 'tb_size' is the size
+ (in bytes) allocated to the translation buffer. Zero means default
+ size. */
+void cpu_exec_init_all(unsigned long tb_size)
+{
+ page_init();
+ cpu_gen_init();
+ code_gen_alloc(tb_size);
+ code_gen_ptr = code_gen_buffer;
+ io_mem_init();
+}
+
void cpu_exec_init(CPUState *env)
{
CPUState **penv;
int cpu_index;
- if (!code_gen_ptr) {
- cpu_gen_init();
- tbs = qemu_malloc(CODE_GEN_MAX_BLOCKS * sizeof(TranslationBlock));
- code_gen_ptr = code_gen_buffer;
- page_init();
- io_mem_init();
- }
env->next_cpu = NULL;
penv = &first_cpu;
cpu_index = 0;
@@ -390,7 +437,7 @@ void tb_flush(CPUState *env1)
nb_tbs, nb_tbs > 0 ?
((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
#endif
- if ((unsigned long)(code_gen_ptr - code_gen_buffer) > CODE_GEN_BUFFER_SIZE)
+ if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
cpu_abort(env1, "Internal error: code buffer overflow\n");
nb_tbs = 0;
@@ -960,8 +1007,8 @@ TranslationBlock *tb_alloc(target_ulong pc)
{
TranslationBlock *tb;
- if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
- (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
+ if (nb_tbs >= code_gen_max_blocks ||
+ (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
return NULL;
tb = &tbs[nb_tbs++];
tb->pc = pc;
@@ -2990,7 +3037,10 @@ void dump_exec_info(FILE *f,
}
/* XXX: avoid using doubles ? */
cpu_fprintf(f, "Translation buffer state:\n");
- cpu_fprintf(f, "TB count %d\n", nb_tbs);
+ cpu_fprintf(f, "gen code size %ld/%ld\n",
+ code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
+ cpu_fprintf(f, "TB count %d/%d\n",
+ nb_tbs, code_gen_max_blocks);
cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
nb_tbs ? target_code_size / nb_tbs : 0,
max_target_code_size);
diff --git a/linux-user/main.c b/linux-user/main.c
index d5bb1240ca..4087a11ff6 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2115,6 +2115,7 @@ int main(int argc, char **argv)
cpu_model = "any";
#endif
}
+ cpu_exec_init_all(0);
/* NOTE: we need to init the CPU at this stage to get
qemu_host_page_size */
env = cpu_init(cpu_model);
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index f23a782dd6..364485e008 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -723,6 +723,8 @@ static inline int cpu_mmu_index (CPUState *env)
return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0;
}
+void optimize_flags_init(void);
+
typedef struct CCTable {
int (*compute_all)(void); /* return all the flags */
int (*compute_c)(void); /* return the C flag */
diff --git a/vl.c b/vl.c
index 5430ae6430..18ddcce1f9 100644
--- a/vl.c
+++ b/vl.c
@@ -7378,6 +7378,7 @@ enum {
QEMU_OPTION_old_param,
QEMU_OPTION_clock,
QEMU_OPTION_startdate,
+ QEMU_OPTION_tb_size,
};
typedef struct QEMUOption {
@@ -7489,6 +7490,7 @@ const QEMUOption qemu_options[] = {
#endif
{ "clock", HAS_ARG, QEMU_OPTION_clock },
{ "startdate", HAS_ARG, QEMU_OPTION_startdate },
+ { "tb-size", HAS_ARG, QEMU_OPTION_tb_size },
{ NULL },
};
@@ -7697,6 +7699,7 @@ int main(int argc, char **argv)
const char *usb_devices[MAX_USB_CMDLINE];
int usb_devices_index;
int fds[2];
+ int tb_size;
const char *pid_file = NULL;
VLANState *vlan;
@@ -7768,8 +7771,9 @@ int main(int argc, char **argv)
hda_index = -1;
nb_nics = 0;
- /* default mac address of the first network interface */
+ tb_size = 0;
+
optind = 1;
for(;;) {
if (optind >= argc)
@@ -8296,6 +8300,11 @@ int main(int argc, char **argv)
}
}
break;
+ case QEMU_OPTION_tb_size:
+ tb_size = strtol(optarg, NULL, 0);
+ if (tb_size < 0)
+ tb_size = 0;
+ break;
}
}
}
@@ -8467,6 +8476,9 @@ int main(int argc, char **argv)
exit(1);
}
+ /* init the dynamic translator */
+ cpu_exec_init_all(tb_size * 1024 * 1024);
+
bdrv_init();
/* we always create the cdrom drive, even if no disk is there */