Commit 26a5f13b8eb1281d0552fe323e869806f3cefbfb
1 parent
bed5cc52
variable dynamic translation buffer size
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4600 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
7 changed files
with
88 additions
and
54 deletions
cpu-all.h
| @@ -767,6 +767,7 @@ int page_get_flags(target_ulong address); | @@ -767,6 +767,7 @@ int page_get_flags(target_ulong address); | ||
| 767 | void page_set_flags(target_ulong start, target_ulong end, int flags); | 767 | void page_set_flags(target_ulong start, target_ulong end, int flags); |
| 768 | int page_check_range(target_ulong start, target_ulong len, int flags); | 768 | int page_check_range(target_ulong start, target_ulong len, int flags); |
| 769 | 769 | ||
| 770 | +void cpu_exec_init_all(unsigned long tb_size); | ||
| 770 | CPUState *cpu_copy(CPUState *env); | 771 | CPUState *cpu_copy(CPUState *env); |
| 771 | 772 | ||
| 772 | void cpu_dump_state(CPUState *env, FILE *f, | 773 | void cpu_dump_state(CPUState *env, FILE *f, |
darwin-user/main.c
| @@ -873,6 +873,7 @@ int main(int argc, char **argv) | @@ -873,6 +873,7 @@ int main(int argc, char **argv) | ||
| 873 | #endif | 873 | #endif |
| 874 | } | 874 | } |
| 875 | 875 | ||
| 876 | + cpu_exec_init_all(0); | ||
| 876 | /* NOTE: we need to init the CPU at this stage to get | 877 | /* NOTE: we need to init the CPU at this stage to get |
| 877 | qemu_host_page_size */ | 878 | qemu_host_page_size */ |
| 878 | env = cpu_init(cpu_model); | 879 | env = cpu_init(cpu_model); |
exec-all.h
| @@ -56,12 +56,6 @@ typedef void (GenOpFunc1)(long); | @@ -56,12 +56,6 @@ typedef void (GenOpFunc1)(long); | ||
| 56 | typedef void (GenOpFunc2)(long, long); | 56 | typedef void (GenOpFunc2)(long, long); |
| 57 | typedef void (GenOpFunc3)(long, long, long); | 57 | typedef void (GenOpFunc3)(long, long, long); |
| 58 | 58 | ||
| 59 | -#if defined(TARGET_I386) | ||
| 60 | - | ||
| 61 | -void optimize_flags_init(void); | ||
| 62 | - | ||
| 63 | -#endif | ||
| 64 | - | ||
| 65 | extern FILE *logfile; | 59 | extern FILE *logfile; |
| 66 | extern int loglevel; | 60 | extern int loglevel; |
| 67 | 61 | ||
| @@ -105,31 +99,7 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, | @@ -105,31 +99,7 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, | ||
| 105 | #define CODE_GEN_PHYS_HASH_BITS 15 | 99 | #define CODE_GEN_PHYS_HASH_BITS 15 |
| 106 | #define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) | 100 | #define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) |
| 107 | 101 | ||
| 108 | -/* maximum total translate dcode allocated */ | ||
| 109 | - | ||
| 110 | -/* NOTE: the translated code area cannot be too big because on some | ||
| 111 | - archs the range of "fast" function calls is limited. Here is a | ||
| 112 | - summary of the ranges: | ||
| 113 | - | ||
| 114 | - i386 : signed 32 bits | ||
| 115 | - arm : signed 26 bits | ||
| 116 | - ppc : signed 24 bits | ||
| 117 | - sparc : signed 32 bits | ||
| 118 | - alpha : signed 23 bits | ||
| 119 | -*/ | ||
| 120 | - | ||
| 121 | -#if defined(__alpha__) | ||
| 122 | -#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024) | ||
| 123 | -#elif defined(__ia64) | ||
| 124 | -#define CODE_GEN_BUFFER_SIZE (4 * 1024 * 1024) /* range of addl */ | ||
| 125 | -#elif defined(__powerpc__) | ||
| 126 | -#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024) | ||
| 127 | -#else | ||
| 128 | -/* XXX: make it dynamic on x86 */ | ||
| 129 | -#define CODE_GEN_BUFFER_SIZE (64 * 1024 * 1024) | ||
| 130 | -#endif | ||
| 131 | - | ||
| 132 | -//#define CODE_GEN_BUFFER_SIZE (128 * 1024) | 102 | +#define MIN_CODE_GEN_BUFFER_SIZE (1024 * 1024) |
| 133 | 103 | ||
| 134 | /* estimated block size for TB allocation */ | 104 | /* estimated block size for TB allocation */ |
| 135 | /* XXX: use a per code average code fragment size and modulate it | 105 | /* 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, | @@ -140,8 +110,6 @@ static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, | ||
| 140 | #define CODE_GEN_AVG_BLOCK_SIZE 64 | 110 | #define CODE_GEN_AVG_BLOCK_SIZE 64 |
| 141 | #endif | 111 | #endif |
| 142 | 112 | ||
| 143 | -#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE) | ||
| 144 | - | ||
| 145 | #if defined(__powerpc__) || defined(__x86_64__) || defined(__arm__) | 113 | #if defined(__powerpc__) || defined(__x86_64__) || defined(__arm__) |
| 146 | #define USE_DIRECT_JUMP | 114 | #define USE_DIRECT_JUMP |
| 147 | #endif | 115 | #endif |
| @@ -210,9 +178,8 @@ void tb_link_phys(TranslationBlock *tb, | @@ -210,9 +178,8 @@ void tb_link_phys(TranslationBlock *tb, | ||
| 210 | target_ulong phys_pc, target_ulong phys_page2); | 178 | target_ulong phys_pc, target_ulong phys_page2); |
| 211 | 179 | ||
| 212 | extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; | 180 | extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; |
| 213 | - | ||
| 214 | -extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; | ||
| 215 | extern uint8_t *code_gen_ptr; | 181 | extern uint8_t *code_gen_ptr; |
| 182 | +extern int code_gen_max_blocks; | ||
| 216 | 183 | ||
| 217 | #if defined(USE_DIRECT_JUMP) | 184 | #if defined(USE_DIRECT_JUMP) |
| 218 | 185 |
exec.c
| @@ -58,9 +58,6 @@ | @@ -58,9 +58,6 @@ | ||
| 58 | #undef DEBUG_TB_CHECK | 58 | #undef DEBUG_TB_CHECK |
| 59 | #endif | 59 | #endif |
| 60 | 60 | ||
| 61 | -/* threshold to flush the translated code buffer */ | ||
| 62 | -#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - code_gen_max_block_size()) | ||
| 63 | - | ||
| 64 | #define SMC_BITMAP_USE_THRESHOLD 10 | 61 | #define SMC_BITMAP_USE_THRESHOLD 10 |
| 65 | 62 | ||
| 66 | #define MMAP_AREA_START 0x00000000 | 63 | #define MMAP_AREA_START 0x00000000 |
| @@ -85,13 +82,17 @@ | @@ -85,13 +82,17 @@ | ||
| 85 | #endif | 82 | #endif |
| 86 | 83 | ||
| 87 | TranslationBlock *tbs; | 84 | TranslationBlock *tbs; |
| 85 | +int code_gen_max_blocks; | ||
| 88 | TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; | 86 | TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; |
| 89 | int nb_tbs; | 87 | int nb_tbs; |
| 90 | /* any access to the tbs or the page table must use this lock */ | 88 | /* any access to the tbs or the page table must use this lock */ |
| 91 | spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; | 89 | spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; |
| 92 | 90 | ||
| 93 | uint8_t code_gen_prologue[1024] __attribute__((aligned (32))); | 91 | uint8_t code_gen_prologue[1024] __attribute__((aligned (32))); |
| 94 | -uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32))); | 92 | +uint8_t *code_gen_buffer; |
| 93 | +unsigned long code_gen_buffer_size; | ||
| 94 | +/* threshold to flush the translated code buffer */ | ||
| 95 | +unsigned long code_gen_buffer_max_size; | ||
| 95 | uint8_t *code_gen_ptr; | 96 | uint8_t *code_gen_ptr; |
| 96 | 97 | ||
| 97 | ram_addr_t phys_ram_size; | 98 | ram_addr_t phys_ram_size; |
| @@ -215,9 +216,6 @@ static void page_init(void) | @@ -215,9 +216,6 @@ static void page_init(void) | ||
| 215 | #else | 216 | #else |
| 216 | qemu_real_host_page_size = getpagesize(); | 217 | qemu_real_host_page_size = getpagesize(); |
| 217 | #endif | 218 | #endif |
| 218 | - map_exec(code_gen_buffer, sizeof(code_gen_buffer)); | ||
| 219 | - map_exec(code_gen_prologue, sizeof(code_gen_prologue)); | ||
| 220 | - | ||
| 221 | if (qemu_host_page_size == 0) | 219 | if (qemu_host_page_size == 0) |
| 222 | qemu_host_page_size = qemu_real_host_page_size; | 220 | qemu_host_page_size = qemu_real_host_page_size; |
| 223 | if (qemu_host_page_size < TARGET_PAGE_SIZE) | 221 | 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, | @@ -328,18 +326,67 @@ static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, | ||
| 328 | target_ulong vaddr); | 326 | target_ulong vaddr); |
| 329 | #endif | 327 | #endif |
| 330 | 328 | ||
| 329 | +void code_gen_alloc(unsigned long tb_size) | ||
| 330 | +{ | ||
| 331 | + code_gen_buffer_size = tb_size; | ||
| 332 | + if (code_gen_buffer_size == 0) { | ||
| 333 | + /* XXX: needs ajustments */ | ||
| 334 | + code_gen_buffer_size = (int)(phys_ram_size / 4); | ||
| 335 | + } | ||
| 336 | + if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE) | ||
| 337 | + code_gen_buffer_size = MIN_CODE_GEN_BUFFER_SIZE; | ||
| 338 | + /* The code gen buffer location may have constraints depending on | ||
| 339 | + the host cpu and OS */ | ||
| 340 | +#if defined(__linux__) | ||
| 341 | + { | ||
| 342 | + int flags; | ||
| 343 | + flags = MAP_PRIVATE | MAP_ANONYMOUS; | ||
| 344 | +#if defined(__x86_64__) | ||
| 345 | + flags |= MAP_32BIT; | ||
| 346 | + /* Cannot map more than that */ | ||
| 347 | + if (code_gen_buffer_size > (800 * 1024 * 1024)) | ||
| 348 | + code_gen_buffer_size = (800 * 1024 * 1024); | ||
| 349 | +#endif | ||
| 350 | + code_gen_buffer = mmap(NULL, code_gen_buffer_size, | ||
| 351 | + PROT_WRITE | PROT_READ | PROT_EXEC, | ||
| 352 | + flags, -1, 0); | ||
| 353 | + if (code_gen_buffer == MAP_FAILED) { | ||
| 354 | + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); | ||
| 355 | + exit(1); | ||
| 356 | + } | ||
| 357 | + } | ||
| 358 | +#else | ||
| 359 | + code_gen_buffer = qemu_malloc(code_gen_buffer_size); | ||
| 360 | + if (!code_gen_buffer) { | ||
| 361 | + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); | ||
| 362 | + exit(1); | ||
| 363 | + } | ||
| 364 | + map_exec(code_gen_buffer, code_gen_buffer_size); | ||
| 365 | +#endif | ||
| 366 | + map_exec(code_gen_prologue, sizeof(code_gen_prologue)); | ||
| 367 | + code_gen_buffer_max_size = code_gen_buffer_size - | ||
| 368 | + code_gen_max_block_size(); | ||
| 369 | + code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE; | ||
| 370 | + tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock)); | ||
| 371 | +} | ||
| 372 | + | ||
| 373 | +/* Must be called before using the QEMU cpus. 'tb_size' is the size | ||
| 374 | + (in bytes) allocated to the translation buffer. Zero means default | ||
| 375 | + size. */ | ||
| 376 | +void cpu_exec_init_all(unsigned long tb_size) | ||
| 377 | +{ | ||
| 378 | + page_init(); | ||
| 379 | + cpu_gen_init(); | ||
| 380 | + code_gen_alloc(tb_size); | ||
| 381 | + code_gen_ptr = code_gen_buffer; | ||
| 382 | + io_mem_init(); | ||
| 383 | +} | ||
| 384 | + | ||
| 331 | void cpu_exec_init(CPUState *env) | 385 | void cpu_exec_init(CPUState *env) |
| 332 | { | 386 | { |
| 333 | CPUState **penv; | 387 | CPUState **penv; |
| 334 | int cpu_index; | 388 | int cpu_index; |
| 335 | 389 | ||
| 336 | - if (!code_gen_ptr) { | ||
| 337 | - cpu_gen_init(); | ||
| 338 | - tbs = qemu_malloc(CODE_GEN_MAX_BLOCKS * sizeof(TranslationBlock)); | ||
| 339 | - code_gen_ptr = code_gen_buffer; | ||
| 340 | - page_init(); | ||
| 341 | - io_mem_init(); | ||
| 342 | - } | ||
| 343 | env->next_cpu = NULL; | 390 | env->next_cpu = NULL; |
| 344 | penv = &first_cpu; | 391 | penv = &first_cpu; |
| 345 | cpu_index = 0; | 392 | cpu_index = 0; |
| @@ -390,7 +437,7 @@ void tb_flush(CPUState *env1) | @@ -390,7 +437,7 @@ void tb_flush(CPUState *env1) | ||
| 390 | nb_tbs, nb_tbs > 0 ? | 437 | nb_tbs, nb_tbs > 0 ? |
| 391 | ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0); | 438 | ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0); |
| 392 | #endif | 439 | #endif |
| 393 | - if ((unsigned long)(code_gen_ptr - code_gen_buffer) > CODE_GEN_BUFFER_SIZE) | 440 | + if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size) |
| 394 | cpu_abort(env1, "Internal error: code buffer overflow\n"); | 441 | cpu_abort(env1, "Internal error: code buffer overflow\n"); |
| 395 | 442 | ||
| 396 | nb_tbs = 0; | 443 | nb_tbs = 0; |
| @@ -960,8 +1007,8 @@ TranslationBlock *tb_alloc(target_ulong pc) | @@ -960,8 +1007,8 @@ TranslationBlock *tb_alloc(target_ulong pc) | ||
| 960 | { | 1007 | { |
| 961 | TranslationBlock *tb; | 1008 | TranslationBlock *tb; |
| 962 | 1009 | ||
| 963 | - if (nb_tbs >= CODE_GEN_MAX_BLOCKS || | ||
| 964 | - (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) | 1010 | + if (nb_tbs >= code_gen_max_blocks || |
| 1011 | + (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size) | ||
| 965 | return NULL; | 1012 | return NULL; |
| 966 | tb = &tbs[nb_tbs++]; | 1013 | tb = &tbs[nb_tbs++]; |
| 967 | tb->pc = pc; | 1014 | tb->pc = pc; |
| @@ -2990,7 +3037,10 @@ void dump_exec_info(FILE *f, | @@ -2990,7 +3037,10 @@ void dump_exec_info(FILE *f, | ||
| 2990 | } | 3037 | } |
| 2991 | /* XXX: avoid using doubles ? */ | 3038 | /* XXX: avoid using doubles ? */ |
| 2992 | cpu_fprintf(f, "Translation buffer state:\n"); | 3039 | cpu_fprintf(f, "Translation buffer state:\n"); |
| 2993 | - cpu_fprintf(f, "TB count %d\n", nb_tbs); | 3040 | + cpu_fprintf(f, "gen code size %ld/%ld\n", |
| 3041 | + code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size); | ||
| 3042 | + cpu_fprintf(f, "TB count %d/%d\n", | ||
| 3043 | + nb_tbs, code_gen_max_blocks); | ||
| 2994 | cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", | 3044 | cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", |
| 2995 | nb_tbs ? target_code_size / nb_tbs : 0, | 3045 | nb_tbs ? target_code_size / nb_tbs : 0, |
| 2996 | max_target_code_size); | 3046 | max_target_code_size); |
linux-user/main.c
| @@ -2115,6 +2115,7 @@ int main(int argc, char **argv) | @@ -2115,6 +2115,7 @@ int main(int argc, char **argv) | ||
| 2115 | cpu_model = "any"; | 2115 | cpu_model = "any"; |
| 2116 | #endif | 2116 | #endif |
| 2117 | } | 2117 | } |
| 2118 | + cpu_exec_init_all(0); | ||
| 2118 | /* NOTE: we need to init the CPU at this stage to get | 2119 | /* NOTE: we need to init the CPU at this stage to get |
| 2119 | qemu_host_page_size */ | 2120 | qemu_host_page_size */ |
| 2120 | env = cpu_init(cpu_model); | 2121 | env = cpu_init(cpu_model); |
target-i386/cpu.h
| @@ -723,6 +723,8 @@ static inline int cpu_mmu_index (CPUState *env) | @@ -723,6 +723,8 @@ static inline int cpu_mmu_index (CPUState *env) | ||
| 723 | return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0; | 723 | return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0; |
| 724 | } | 724 | } |
| 725 | 725 | ||
| 726 | +void optimize_flags_init(void); | ||
| 727 | + | ||
| 726 | typedef struct CCTable { | 728 | typedef struct CCTable { |
| 727 | int (*compute_all)(void); /* return all the flags */ | 729 | int (*compute_all)(void); /* return all the flags */ |
| 728 | int (*compute_c)(void); /* return the C flag */ | 730 | int (*compute_c)(void); /* return the C flag */ |
vl.c
| @@ -7378,6 +7378,7 @@ enum { | @@ -7378,6 +7378,7 @@ enum { | ||
| 7378 | QEMU_OPTION_old_param, | 7378 | QEMU_OPTION_old_param, |
| 7379 | QEMU_OPTION_clock, | 7379 | QEMU_OPTION_clock, |
| 7380 | QEMU_OPTION_startdate, | 7380 | QEMU_OPTION_startdate, |
| 7381 | + QEMU_OPTION_tb_size, | ||
| 7381 | }; | 7382 | }; |
| 7382 | 7383 | ||
| 7383 | typedef struct QEMUOption { | 7384 | typedef struct QEMUOption { |
| @@ -7489,6 +7490,7 @@ const QEMUOption qemu_options[] = { | @@ -7489,6 +7490,7 @@ const QEMUOption qemu_options[] = { | ||
| 7489 | #endif | 7490 | #endif |
| 7490 | { "clock", HAS_ARG, QEMU_OPTION_clock }, | 7491 | { "clock", HAS_ARG, QEMU_OPTION_clock }, |
| 7491 | { "startdate", HAS_ARG, QEMU_OPTION_startdate }, | 7492 | { "startdate", HAS_ARG, QEMU_OPTION_startdate }, |
| 7493 | + { "tb-size", HAS_ARG, QEMU_OPTION_tb_size }, | ||
| 7492 | { NULL }, | 7494 | { NULL }, |
| 7493 | }; | 7495 | }; |
| 7494 | 7496 | ||
| @@ -7697,6 +7699,7 @@ int main(int argc, char **argv) | @@ -7697,6 +7699,7 @@ int main(int argc, char **argv) | ||
| 7697 | const char *usb_devices[MAX_USB_CMDLINE]; | 7699 | const char *usb_devices[MAX_USB_CMDLINE]; |
| 7698 | int usb_devices_index; | 7700 | int usb_devices_index; |
| 7699 | int fds[2]; | 7701 | int fds[2]; |
| 7702 | + int tb_size; | ||
| 7700 | const char *pid_file = NULL; | 7703 | const char *pid_file = NULL; |
| 7701 | VLANState *vlan; | 7704 | VLANState *vlan; |
| 7702 | 7705 | ||
| @@ -7768,8 +7771,9 @@ int main(int argc, char **argv) | @@ -7768,8 +7771,9 @@ int main(int argc, char **argv) | ||
| 7768 | hda_index = -1; | 7771 | hda_index = -1; |
| 7769 | 7772 | ||
| 7770 | nb_nics = 0; | 7773 | nb_nics = 0; |
| 7771 | - /* default mac address of the first network interface */ | ||
| 7772 | 7774 | ||
| 7775 | + tb_size = 0; | ||
| 7776 | + | ||
| 7773 | optind = 1; | 7777 | optind = 1; |
| 7774 | for(;;) { | 7778 | for(;;) { |
| 7775 | if (optind >= argc) | 7779 | if (optind >= argc) |
| @@ -8296,6 +8300,11 @@ int main(int argc, char **argv) | @@ -8296,6 +8300,11 @@ int main(int argc, char **argv) | ||
| 8296 | } | 8300 | } |
| 8297 | } | 8301 | } |
| 8298 | break; | 8302 | break; |
| 8303 | + case QEMU_OPTION_tb_size: | ||
| 8304 | + tb_size = strtol(optarg, NULL, 0); | ||
| 8305 | + if (tb_size < 0) | ||
| 8306 | + tb_size = 0; | ||
| 8307 | + break; | ||
| 8299 | } | 8308 | } |
| 8300 | } | 8309 | } |
| 8301 | } | 8310 | } |
| @@ -8467,6 +8476,9 @@ int main(int argc, char **argv) | @@ -8467,6 +8476,9 @@ int main(int argc, char **argv) | ||
| 8467 | exit(1); | 8476 | exit(1); |
| 8468 | } | 8477 | } |
| 8469 | 8478 | ||
| 8479 | + /* init the dynamic translator */ | ||
| 8480 | + cpu_exec_init_all(tb_size * 1024 * 1024); | ||
| 8481 | + | ||
| 8470 | bdrv_init(); | 8482 | bdrv_init(); |
| 8471 | 8483 | ||
| 8472 | /* we always create the cdrom drive, even if no disk is there */ | 8484 | /* we always create the cdrom drive, even if no disk is there */ |