guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] 01/01: Use custom JIT code allocator


From: Andy Wingo
Subject: [Guile-commits] 01/01: Use custom JIT code allocator
Date: Fri, 7 Sep 2018 06:26:50 -0400 (EDT)

wingo pushed a commit to branch lightning
in repository guile.

commit f8229c603de079688d278dfa56cb07d2dc842a3f
Author: Andy Wingo <address@hidden>
Date:   Fri Sep 7 12:19:29 2018 +0200

    Use custom JIT code allocator
    
    * libguile/jit.c (struct code_arena): New data type.
    (struct scm_jit_state): Add code arena member.
    (allocate_code_arena): New helper.
    (emit_code): New helper.  Emits code into a thread-local code arena.
    (compute_mcode): Allow for failure to JIT.
    (scm_jit_compute_mcode): Stop automatic JIT compilation on resource
    exhaustion.
---
 libguile/jit.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 125 insertions(+), 11 deletions(-)

diff --git a/libguile/jit.c b/libguile/jit.c
index 9ddc125..c055bfe 100644
--- a/libguile/jit.c
+++ b/libguile/jit.c
@@ -22,7 +22,8 @@
 # include <config.h>
 #endif
 
-#include <stdio.h> // FIXME: Remove me!
+#include <stdio.h>
+#include <sys/mman.h>
 
 #if ENABLE_JIT
 #include <lightning.h>
@@ -148,6 +149,15 @@ static void *exit_mcode;
    instruction, compiled as a stub on the side to reduce code size.  */
 static void *handle_interrupts_trampoline;
 
+/* Thread-local buffer into which to write code.  */
+struct code_arena
+{
+  uint8_t *base;
+  size_t used;
+  size_t size;
+  struct code_arena *prev;
+};
+
 /* State of the JIT compiler for the current thread.  */
 struct scm_jit_state {
   jit_state_t *jit;
@@ -167,6 +177,7 @@ struct scm_jit_state {
   jit_fpr_t sp_cache_fpr;
   uint32_t sp_cache_gpr_idx;
   uint32_t sp_cache_fpr_idx;
+  struct code_arena *code_arena;
 };
 
 typedef struct scm_jit_state scm_jit_state;
@@ -1279,6 +1290,107 @@ initialize_handle_interrupts_trampoline (void)
   memcpy (j, &saved_jit_state, sizeof (*j));
 }
 
+/* To limit the number of mmap calls and re-emission of JIT code, use
+   256 kB code arenas.  Unused pages won't be resident.  Assume pages
+   are power-of-two-sized and this size is a multiple of the page size
+   on all architectures.  */
+static const size_t default_code_arena_size = 0x40000;
+
+static struct code_arena *
+allocate_code_arena (size_t size, struct code_arena *prev)
+{
+  struct code_arena *ret = malloc (sizeof (struct code_arena));
+
+  if (!ret) return NULL;
+
+  memset (ret, 0, sizeof (*ret));
+  ret->used = 0;
+  ret->size = size;
+  ret->prev = prev;
+  ret->base = mmap (NULL, ret->size,
+                    PROT_EXEC | PROT_READ | PROT_WRITE,
+                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+  if (ret->base == MAP_FAILED)
+    {
+      perror ("allocating JIT code buffer failed");
+      free (ret);
+      return NULL;
+    }
+
+  INFO ("allocated code arena, %p-%p\n", ret->base, ret->base + ret->size);
+
+  return ret;
+}
+
+static uint8_t *
+emit_code (scm_jit_state *j)
+{
+  uint8_t *ret = NULL;
+
+  jit_realize ();
+
+  if (!j->code_arena)
+    j->code_arena = allocate_code_arena (default_code_arena_size, NULL);
+
+  if (!j->code_arena)
+    /* Resource exhaustion; turn off JIT.  */
+    return NULL;
+
+  while (1)
+    {
+      struct code_arena *arena = j->code_arena;
+
+      jit_set_code (arena->base + arena->used, arena->size - arena->used);
+
+      ret = jit_emit ();
+
+      if (ret)
+        {
+          jit_word_t size = 0;
+          jit_get_code (&size);
+          ASSERT (size <= (arena->size - arena->used));
+          DEBUG ("mcode: %p,+%zu\n", ret, size);
+          arena->used += size;
+          /* Align next JIT to 16-byte boundaries to optimize initial
+             icache fetch.  */
+          arena->used = (arena->used + 15) & ~15;
+          /* Assertion should not be invalidated as arena size is a
+             multiple of 16.  */
+          ASSERT (arena->used <= arena->size);
+          return ret;
+        }
+      else
+        {
+          if (arena->used == 0)
+            {
+              /* Code too big to fit into empty arena; allocate a larger
+                 one.  */
+              INFO ("code didn't fit in empty arena of size %zu\n", 
arena->size);
+              arena = allocate_code_arena (arena->size * 2, arena->prev);
+              if (!arena)
+                return NULL;
+              munmap (j->code_arena->base, j->code_arena->size);
+              free (j->code_arena);
+              j->code_arena = arena;
+            }
+          else
+            {
+              /* Arena full; allocate another.  */
+              /* FIXME: If partial code that we wrote crosses a page
+                 boundary, we could tell the OS to forget about the tail
+                 pages.  */
+              INFO ("code didn't fit in arena tail %zu\n",
+                    arena->size - arena->used);
+              arena = allocate_code_arena (arena->size, arena);
+              if (!arena)
+                return NULL;
+              j->code_arena = arena;
+            }
+        }
+    }
+}
+
 static void
 emit_free_variable_ref (scm_jit_state *j, jit_gpr_t dst, jit_gpr_t prog,
                         size_t n)
@@ -4595,15 +4707,11 @@ compute_mcode (scm_thread *thread, uint32_t *entry_ip,
 
   compile (j);
 
-  data->mcode = jit_emit ();
-  entry_mcode = jit_address (j->entry_label);
-
-  {
-    jit_word_t size = 0;
-    jit_get_code (&size);
-    DEBUG ("mcode: %p,+%zu entry=+%zu\n", data->mcode, size,
-           entry_mcode - data->mcode);
-  }
+  data->mcode = emit_code (j);
+  if (data->mcode)
+    entry_mcode = jit_address (j->entry_label);
+  else
+    entry_mcode = NULL;
 
   free (j->op_attrs);
   j->op_attrs = NULL;
@@ -4661,7 +4769,13 @@ scm_jit_compute_mcode (scm_thread *thread, struct 
scm_jit_function_data *data)
     {
       uint8_t *mcode = compute_mcode (thread, thread->vm.ip, data);
 
-      if (--jit_stop_after == 0)
+      if (!mcode)
+        {
+          scm_jit_counter_threshold = -1;
+          fprintf (stderr, "JIT failed due to resource exhaustion\n");
+          fprintf (stderr, "disabling automatic JIT compilation\n");
+        }
+      else if (--jit_stop_after == 0)
         {
           scm_jit_counter_threshold = -1;
           fprintf (stderr, "stopping automatic JIT compilation, as 
requested\n");



reply via email to

[Prev in Thread] Current Thread [Next in Thread]