From patchwork Tue Oct 16 07:30:10 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 191749 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 872752C00A3 for ; Tue, 16 Oct 2012 18:31:19 +1100 (EST) Received: from localhost ([::1]:50190 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TO1cS-0004ZH-7A for incoming@patchwork.ozlabs.org; Tue, 16 Oct 2012 03:31:16 -0400 Received: from eggs.gnu.org ([208.118.235.92]:60894) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TO1bq-0003SJ-3X for qemu-devel@nongnu.org; Tue, 16 Oct 2012 03:30:39 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TO1bl-0001pP-6k for qemu-devel@nongnu.org; Tue, 16 Oct 2012 03:30:37 -0400 Received: from mail-pa0-f45.google.com ([209.85.220.45]:51531) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TO1bk-0001pC-Tf for qemu-devel@nongnu.org; Tue, 16 Oct 2012 03:30:33 -0400 Received: by mail-pa0-f45.google.com with SMTP id fb10so5591558pad.4 for ; Tue, 16 Oct 2012 00:30:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=xclVyXsDWaBiHIgBjfnC87VsCNuWJ6phf7flxknl7FA=; b=GoRkt2vggEseVHIwNgns02lsVn9+3CnYI88EZndb2iEhUw7NP3JfbM7jdYS9NjIgoq QPbECE2Yfs1efjXIcFvlbcGxCcfxWSDp47j4efpRivwYBv7l9CtGZxTqjYEs6Ib3zpYy qClPdmwdBpdOSUmRY2LQyH1PL/mlXxc19qhu6bS4n7sk4lMQZ4powbJPdsEUNLeVxTn1 RIRFS98byZPtXR7HdMLl83PTpOYwKGQ91gT0mnaZ8VomHsejh4QP6VV68wDZtIAomnTI GjBFqM+IbLi86LVYjCn16Lr5XdW88YHgckQ33vUtijYks1sdHoigkPZ4cRwCPHwoC53I lfCw== Received: by 10.66.75.73 with SMTP id a9mr39513440paw.43.1350372631955; Tue, 16 Oct 2012 00:30:31 -0700 (PDT) Received: from pebble.twiddle.home ([1.141.46.32]) by mx.google.com with ESMTPS id jw14sm10364647pbb.36.2012.10.16.00.30.29 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 16 Oct 2012 00:30:31 -0700 (PDT) From: Richard Henderson To: qemu-devel@nongnu.org Date: Tue, 16 Oct 2012 17:30:10 +1000 Message-Id: <1350372614-30041-2-git-send-email-rth@twiddle.net> X-Mailer: git-send-email 1.7.11.7 In-Reply-To: <1350372614-30041-1-git-send-email-rth@twiddle.net> References: <1350372614-30041-1-git-send-email-rth@twiddle.net> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.220.45 Cc: blauwirbel@gmail.com Subject: [Qemu-devel] [PATCH 1/5] exec: Split up and tidy code_gen_buffer X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org It now consists of: A macro definition of MAX_CODE_GEN_BUFFER_SIZE with host-specific values, A function size_code_gen_buffer that applies most of the reasoning for choosing a buffer size, Three variations of a function alloc_code_gen_buffer that contain all of the logic for allocating executable memory via a given allocation mechanism. Signed-off-by: Richard Henderson --- exec.c | 195 ++++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 103 insertions(+), 92 deletions(-) diff --git a/exec.c b/exec.c index 7899042..eecae2f 100644 --- a/exec.c +++ b/exec.c @@ -103,9 +103,9 @@ spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; uint8_t code_gen_prologue[1024] code_gen_section; static uint8_t *code_gen_buffer; -static unsigned long code_gen_buffer_size; +static size_t code_gen_buffer_size; /* threshold to flush the translated code buffer */ -static unsigned long code_gen_buffer_max_size; +static size_t code_gen_buffer_max_size; static uint8_t *code_gen_ptr; #if !defined(CONFIG_USER_ONLY) @@ -497,110 +497,121 @@ bool memory_region_is_unassigned(MemoryRegion *mr) #define mmap_unlock() do { } while(0) #endif -#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024) - #if defined(CONFIG_USER_ONLY) /* Currently it is not recommended to allocate big chunks of data in - user mode. It will change when a dedicated libc will be used */ + user mode. It will change when a dedicated libc will be used. */ +/* ??? 64-bit hosts ought to have no problem mmaping data outside the + region in which the guest needs to run. Revisit this. */ #define USE_STATIC_CODE_GEN_BUFFER #endif -#ifdef USE_STATIC_CODE_GEN_BUFFER -static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE] - __attribute__((aligned (CODE_GEN_ALIGN))); +/* ??? Should configure for this, not list operating systems here. */ +#if (defined(__linux__) \ + || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \ + || defined(__DragonFly__) || defined(__OpenBSD__) \ + || defined(__NetBSD__)) +# define USE_MMAP #endif -static void code_gen_alloc(unsigned long tb_size) +/* Maximum size of the code gen buffer we'd like to use. Unless otherwise + indicated, this is constrained by the range of direct branches on the + host cpu, as used by the TCG implementation of goto_tb. */ +#if defined(__x86_64__) +# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024) +#elif defined(__sparc__) +# define MAX_CODE_GEN_BUFFER_SIZE (2ul * 1024 * 1024 * 1024) +#elif defined(__arm__) +# define MAX_CODE_GEN_BUFFER_SIZE (16u * 1024 * 1024) +#elif defined(__s390x__) + /* We have a +- 4GB range on the branches; leave some slop. */ +# define MAX_CODE_GEN_BUFFER_SIZE (3ul * 1024 * 1024 * 1024) +#else +# define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) +#endif + +#define DEFAULT_CODE_GEN_BUFFER_SIZE (32u * 1024 * 1024) + +static inline size_t size_code_gen_buffer(size_t tb_size) { + /* Size the buffer. */ + if (tb_size == 0) { #ifdef USE_STATIC_CODE_GEN_BUFFER - code_gen_buffer = static_code_gen_buffer; - code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; - map_exec(code_gen_buffer, code_gen_buffer_size); -#else - code_gen_buffer_size = tb_size; - if (code_gen_buffer_size == 0) { -#if defined(CONFIG_USER_ONLY) - code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; + tb_size = DEFAULT_CODE_GEN_BUFFER_SIZE; #else - /* XXX: needs adjustments */ - code_gen_buffer_size = (unsigned long)(ram_size / 4); + /* ??? Needs adjustments. */ + /* ??? If we relax the requirement that CONFIG_USER_ONLY use the + static buffer, we could size this on RESERVED_VA, on the text + segment size of the executable, or continue to use the default. */ + tb_size = (unsigned long)(ram_size / 4); #endif } - 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; - void *start = NULL; - - 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); -#elif defined(__sparc__) && HOST_LONG_BITS == 64 - // Map the buffer below 2G, so we can use direct calls and branches - start = (void *) 0x40000000UL; - if (code_gen_buffer_size > (512 * 1024 * 1024)) - code_gen_buffer_size = (512 * 1024 * 1024); -#elif defined(__arm__) - /* Keep the buffer no bigger than 16MB to branch between blocks */ - if (code_gen_buffer_size > 16 * 1024 * 1024) - code_gen_buffer_size = 16 * 1024 * 1024; -#elif defined(__s390x__) - /* Map the buffer so that we can use direct calls and branches. */ - /* We have a +- 4GB range on the branches; leave some slop. */ - if (code_gen_buffer_size > (3ul * 1024 * 1024 * 1024)) { - code_gen_buffer_size = 3ul * 1024 * 1024 * 1024; - } - start = (void *)0x90000000UL; -#endif - code_gen_buffer = mmap(start, 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); - } + if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) { + tb_size = MIN_CODE_GEN_BUFFER_SIZE; } -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) \ - || defined(__DragonFly__) || defined(__OpenBSD__) \ - || defined(__NetBSD__) - { - int flags; - void *addr = NULL; - flags = MAP_PRIVATE | MAP_ANONYMOUS; -#if defined(__x86_64__) - /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume - * 0x40000000 is free */ - flags |= MAP_FIXED; - addr = (void *)0x40000000; - /* Cannot map more than that */ - if (code_gen_buffer_size > (800 * 1024 * 1024)) - code_gen_buffer_size = (800 * 1024 * 1024); -#elif defined(__sparc__) && HOST_LONG_BITS == 64 - // Map the buffer below 2G, so we can use direct calls and branches - addr = (void *) 0x40000000UL; - if (code_gen_buffer_size > (512 * 1024 * 1024)) { - code_gen_buffer_size = (512 * 1024 * 1024); - } -#endif - code_gen_buffer = mmap(addr, 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); - } + if (tb_size > MAX_CODE_GEN_BUFFER_SIZE) { + tb_size = MAX_CODE_GEN_BUFFER_SIZE; } + code_gen_buffer_size = tb_size; + return tb_size; +} + +#ifdef USE_STATIC_CODE_GEN_BUFFER +static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE] + __attribute__((aligned(CODE_GEN_ALIGN))); + +static inline void *alloc_code_gen_buffer(void) +{ + map_exec(static_code_gen_buffer, code_gen_buffer_size); + return static_code_gen_buffer; +} +#elif defined(USE_MMAP) +static inline void *alloc_code_gen_buffer(void) +{ + int flags = MAP_PRIVATE | MAP_ANONYMOUS; + uintptr_t start = 0; + void *buf; + + /* Constrain the position of the buffer based on the host cpu. + Note that these addresses are chosen in concert with the + addresses assigned in the relevant linker script file. */ +# if defined(__x86_64__) && defined(MAP_32BIT) + /* Force the memory down into low memory with the executable. + Leave the choice of exact location with the kernel. */ + flags |= MAP_32BIT; + /* Cannot expect to map more than 800MB in low memory. */ + if (code_gen_buffer_size > 800u * 1024 * 1024) { + code_gen_buffer_size = 800u * 1024 * 1024; + } +# elif defined(__sparc__) + start = 0x40000000ul; +# elif defined(__s390x__) + start = 0x90000000ul; +# endif + + buf = mmap((void *)start, code_gen_buffer_size, + PROT_WRITE | PROT_READ | PROT_EXEC, flags, -1, 0); + return buf == MAP_FAILED ? NULL : buf; +} #else - code_gen_buffer = g_malloc(code_gen_buffer_size); - map_exec(code_gen_buffer, code_gen_buffer_size); -#endif -#endif /* !USE_STATIC_CODE_GEN_BUFFER */ +static inline void *alloc_code_gen_buffer(void) +{ + void *buf = g_malloc(code_gen_buffer_size); + if (buf) { + map_exec(buf, code_gen_buffer_size); + } + return buf; +} +#endif /* USE_STATIC_CODE_GEN_BUFFER, USE_MMAP */ + +static inline void code_gen_alloc(size_t tb_size) +{ + code_gen_buffer_size = size_code_gen_buffer(tb_size); + code_gen_buffer = alloc_code_gen_buffer(); + if (code_gen_buffer == NULL) { + fprintf(stderr, "Could not allocate dynamic translator buffer\n"); + exit(1); + } + map_exec(code_gen_prologue, sizeof(code_gen_prologue)); code_gen_buffer_max_size = code_gen_buffer_size - (TCG_MAX_OP_SIZE * OPC_BUF_SIZE); @@ -4188,7 +4199,7 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf) } /* XXX: avoid using doubles ? */ cpu_fprintf(f, "Translation buffer state:\n"); - cpu_fprintf(f, "gen code size %td/%ld\n", + cpu_fprintf(f, "gen code size %td/%zd\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);