Advise operating system about memory access during GC.
authorTaylor R Campbell <campbell@mumble.net>
Tue, 5 Apr 2011 00:33:40 +0000 (00:33 +0000)
committerTaylor R Campbell <campbell@mumble.net>
Tue, 5 Apr 2011 00:33:40 +0000 (00:33 +0000)
- Expect sequential access to oldspace during gc_scan_oldspace.
- Free heap pages (newspace) before copying tospace over them.
- Free tospace pages after saving tospace.

The OS hooks are implemented only for Unix, in terms of posix_madvise
and madvise.  Implementing them for Windows and/or OS/2 is left as an
exercise for the reader.

src/microcode/configure.ac
src/microcode/gcloop.c
src/microcode/memmag.c
src/microcode/nttop.c
src/microcode/os2top.c
src/microcode/ostop.h
src/microcode/uxtop.c

index b670c64eda676e332200ee405f355e36c8c6e49e..3a8501280af25a135328a2f8a0b54de256c2f63f 100644 (file)
@@ -717,9 +717,9 @@ AC_CHECK_FUNCS([getcwd gethostbyname gethostname getlogin getpagesize getpgrp])
 AC_CHECK_FUNCS([getpt gettimeofday getwd grantpt])
 AC_CHECK_FUNCS([kill])
 AC_CHECK_FUNCS([lockf])
-AC_CHECK_FUNCS([memcpy mkdir mktime modf])
+AC_CHECK_FUNCS([madvise memcpy mkdir mktime modf])
 AC_CHECK_FUNCS([nice ntp_adjtime ntp_gettime])
-AC_CHECK_FUNCS([poll prealloc])
+AC_CHECK_FUNCS([poll posix_madvise prealloc])
 AC_CHECK_FUNCS([rename rmdir])
 AC_CHECK_FUNCS([select setitimer setpgrp setpgrp2 shmat sigaction])
 AC_CHECK_FUNCS([sighold socket statfs strchr strerror strstr strtol])
index 52c02189aa7a2e5c8730f8c1de19f42ab9999f7a..8c0a22fc646adf9c9dece7af64460215befc2c14 100644 (file)
@@ -65,6 +65,9 @@ USA.
 /* For ephemeron layout.  */
 #include "sdata.h"
 
+/* For memory advice.  */
+#include "ostop.h"
+
 static SCHEME_OBJECT ** p_fromspace_start;
 static SCHEME_OBJECT ** p_fromspace_end;
 static gc_tospace_allocator_t * gc_tospace_allocator;
@@ -226,6 +229,7 @@ save_tospace (gc_walk_proc_t * proc, void * ctx)
   GUARANTEE_TOSPACE_OPEN ();
   CHECK_NEWSPACE_SYNC ();
   ok = (proc (tospace_start, tospace_next, ctx));
+  OS_free_pages (tospace_start, tospace_end);
   CLOSE_TOSPACE ();
   return (ok);
 }
@@ -235,6 +239,7 @@ discard_tospace (void)
 {
   GUARANTEE_TOSPACE_OPEN ();
   CHECK_NEWSPACE_SYNC ();
+  OS_free_pages (tospace_start, tospace_end);
   CLOSE_TOSPACE ();
 }
 
@@ -387,7 +392,9 @@ std_gc_table (void)
 void
 gc_scan_oldspace (SCHEME_OBJECT * scan, SCHEME_OBJECT * end)
 {
+  OS_expect_sequential_access (scan, end);
   run_gc_loop (scan, (&end));
+  OS_expect_normal_access (scan, end);
 }
 
 void
index 498514e496557b94b9771601dadb64a468c424b5..d8552fd57e25cc95e3bdbc1383586c47293dcd72 100644 (file)
@@ -30,6 +30,7 @@ USA.
 #include "history.h"
 #include "gccode.h"
 #include "osscheme.h"
+#include "ostop.h"
 
 #ifdef __WIN32__
    extern void win32_allocate_registers (void);
@@ -315,6 +316,7 @@ void
 std_gc_pt2 (void)
 {
   SCHEME_OBJECT * p = (get_newspace_ptr ());
+  OS_free_pages (heap_start, heap_end);
   (void) save_tospace (save_tospace_copy, 0);
   Free = p;
 
index bc89e439a8300b6a74e5e4343e03d0e2542e928a..c68ea13c42811e998a5858af9ffdac0e6ede0e89 100644 (file)
@@ -1980,3 +1980,24 @@ win32_error_code_to_syserr (DWORD code)
     default: return (syserr_unknown);
     }
 }
+\f
+void
+OS_expect_sequential_access (void *start, void *end)
+{
+  (void) start;                 /* ignore */
+  (void) end;                   /* ignore */
+}
+
+void
+OS_expect_normal_access (void *start, void *end)
+{
+  (void) start;                 /* ignore */
+  (void) end;                   /* ignore */
+}
+
+void
+OS_free_pages (void *start, void *end)
+{
+  (void) start;                 /* ignore */
+  (void) end;                   /* ignore */
+}
index b198fc6584f6039ec151be9e87acc62e15d870fd..53e11a924899e2e7890765c267f0cac26d3da0b6 100644 (file)
@@ -2525,3 +2525,24 @@ OS_syscall_names (unsigned long * length, const char *** names)
   (*length) = ((sizeof (syscall_names_table)) / (sizeof (char *)));
   (*names) = syscall_names_table;
 }
+\f
+void
+OS_expect_sequential_access (void *start, void *end)
+{
+  (void) start;                 /* ignore */
+  (void) end;                   /* ignore */
+}
+
+void
+OS_expect_normal_access (void *start, void *end)
+{
+  (void) start;                 /* ignore */
+  (void) end;                   /* ignore */
+}
+
+void
+OS_free_pages (void *start, void *end)
+{
+  (void) start;                 /* ignore */
+  (void) end;                   /* ignore */
+}
index 06f0273fdd9f4d4bef96e3c5ace644d671dd644e..417f7e8899d1846516bf3a2880e4bf55aaf88f70 100644 (file)
@@ -38,5 +38,8 @@ extern void OS_save_internal_state (void);
 extern void OS_restore_internal_state (void);
 extern void OS_restore_external_state (void);
 extern const char * OS_error_code_to_message (unsigned int code);
+extern void OS_expect_sequential_access (void *start, void *end);
+extern void OS_expect_normal_access (void *start, void *end);
+extern void OS_free_pages (void *start, void *end);
 
 #endif /* SCM_OSTOP_H */
index 81b4df9caa5c24349eac3960785eaf8bb2266499..7cb446c00bd4e7eeffd1ae8238dd5aed2ebf4b2e 100644 (file)
@@ -558,3 +558,88 @@ OS_syserr_names (unsigned long * length, const char *** names)
   (*length) = ((sizeof (syserr_names_table)) / (sizeof (char *)));
   (*names) = syserr_names_table;
 }
+\f
+static unsigned long
+round_up (unsigned long n, unsigned long factor)
+{
+  return (((n + (factor - 1)) / factor) * factor);
+}
+
+static unsigned long
+round_down (unsigned long n, unsigned long factor)
+{
+  return ((n / factor) * factor);
+}
+
+static void
+estimate_pages (void *start, void *end,
+                unsigned long (*round_start) (unsigned long, unsigned long),
+                unsigned long (*round_end) (unsigned long, unsigned long),
+                void **addr, size_t *len)
+{
+  if (end <= start)
+    {
+      (*addr) = start;
+      (*len) = 0;
+      return;
+    }
+
+  {
+    unsigned long page_size = (UX_getpagesize ());
+    char *page_start
+      = ((char *) ((*round_start) (((unsigned long) start), page_size)));
+    char *page_end
+      = ((char *) ((*round_end) (((unsigned long) end), page_size)));
+    (*addr) = ((void *) page_start);
+    (*len) = ((page_start < page_end) ? (page_end - page_start) : 0);
+  }
+}
+
+static void
+underestimate_pages (void *start, void *end, void **addr, size_t *len)
+{
+  estimate_pages (start, end, (&round_up), (&round_down), addr, len);
+}
+
+static void
+overestimate_pages (void *start, void *end, void **addr, size_t *len)
+{
+  estimate_pages (start, end, (&round_down), (&round_up), addr, len);
+}
+\f
+void
+OS_expect_sequential_access (void *start, void *end)
+{
+  void *addr;
+  size_t len;
+  overestimate_pages (start, end, (&addr), (&len));
+#if ((defined (HAVE_POSIX_MADVISE)) && (defined (POSIX_MADV_SEQUENTIAL)))
+  (void) posix_madvise (addr, len, POSIX_MADV_SEQUENTIAL);
+#elif ((defined (HAVE_MADVISE)) && (defined (MADV_SEQUENTIAL)))
+  (void) madvise (addr, len, MADV_SEQUENTIAL);
+#endif
+}
+
+void
+OS_expect_normal_access (void *start, void *end)
+{
+  void *addr;
+  size_t len;
+  overestimate_pages (start, end, (&addr), (&len));
+#if ((defined (HAVE_POSIX_MADVISE)) && (defined (POSIX_MADV_NORMAL)))
+  (void) posix_madvise (addr, len, POSIX_MADV_NORMAL);
+#elif ((defined (HAVE_MADVISE)) && (defined (MADV_NORMAL)))
+  (void) madvise (addr, len, MADV_NORMAL);
+#endif
+}
+
+void
+OS_free_pages (void *start, void *end)
+{
+  void *addr;
+  size_t len;
+  underestimate_pages (start, end, (&addr), (&len));
+#if ((defined (HAVE_MADVISE)) && (defined (MADV_FREE)))
+  (void) madvise (addr, len, MADV_FREE);
+#endif
+}