svn commit: r313756 - head/sys/kern

Mark Johnston markj at FreeBSD.org
Wed Feb 15 01:51:00 UTC 2017


Author: markj
Date: Wed Feb 15 01:50:58 2017
New Revision: 313756
URL: https://svnweb.freebsd.org/changeset/base/313756

Log:
  Apply MADV_FREE to exec_map entries only after a lowmem event.
  
  This effectively provides the same benefit as applying MADV_FREE inline
  upon every execve, since the page daemon invokes lowmem handlers prior to
  scanning the inactive queue. It also has less overhead; the cost of
  applying MADV_FREE is very noticeable on many-CPU systems since it includes
  that of a TLB shootdown of global PTEs. For instance, this change nearly
  halves the system CPU usage during a buildkernel on a 128-vCPU EC2
  instance (with some other patches applied).
  
  Benchmarked by:	cperciva (earlier version)
  Reviewed by:	kib
  MFC after:	2 weeks
  Differential Revision:	https://reviews.freebsd.org/D9586

Modified:
  head/sys/kern/kern_exec.c

Modified: head/sys/kern/kern_exec.c
==============================================================================
--- head/sys/kern/kern_exec.c	Wed Feb 15 01:35:26 2017	(r313755)
+++ head/sys/kern/kern_exec.c	Wed Feb 15 01:50:58 2017	(r313756)
@@ -1320,6 +1320,7 @@ err_exit:
 
 struct exec_args_kva {
 	vm_offset_t addr;
+	u_int gen;
 	SLIST_ENTRY(exec_args_kva) next;
 };
 
@@ -1327,6 +1328,7 @@ static DPCPU_DEFINE(struct exec_args_kva
 
 static SLIST_HEAD(, exec_args_kva) exec_args_kva_freelist;
 static struct mtx exec_args_kva_mtx;
+static u_int exec_args_gen;
 
 static void
 exec_prealloc_args_kva(void *arg __unused)
@@ -1339,6 +1341,7 @@ exec_prealloc_args_kva(void *arg __unuse
 	for (i = 0; i < exec_map_entries; i++) {
 		argkva = malloc(sizeof(*argkva), M_PARGS, M_WAITOK);
 		argkva->addr = kmap_alloc_wait(exec_map, exec_map_entry_size);
+		argkva->gen = exec_args_gen;
 		SLIST_INSERT_HEAD(&exec_args_kva_freelist, argkva, next);
 	}
 }
@@ -1364,15 +1367,16 @@ exec_alloc_args_kva(void **cookie)
 }
 
 static void
-exec_free_args_kva(void *cookie)
+exec_release_args_kva(struct exec_args_kva *argkva, u_int gen)
 {
-	struct exec_args_kva *argkva;
 	vm_offset_t base;
 
-	argkva = cookie;
 	base = argkva->addr;
-
-	vm_map_madvise(exec_map, base, base + exec_map_entry_size, MADV_FREE);
+	if (argkva->gen != gen) {
+		vm_map_madvise(exec_map, base, base + exec_map_entry_size,
+		    MADV_FREE);
+		argkva->gen = gen;
+	}
 	if (!atomic_cmpset_ptr((uintptr_t *)DPCPU_PTR(exec_args_kva),
 	    (uintptr_t)NULL, (uintptr_t)argkva)) {
 		mtx_lock(&exec_args_kva_mtx);
@@ -1382,6 +1386,46 @@ exec_free_args_kva(void *cookie)
 	}
 }
 
+static void
+exec_free_args_kva(void *cookie)
+{
+
+	exec_release_args_kva(cookie, exec_args_gen);
+}
+
+static void
+exec_args_kva_lowmem(void *arg __unused)
+{
+	SLIST_HEAD(, exec_args_kva) head;
+	struct exec_args_kva *argkva;
+	u_int gen;
+	int i;
+
+	gen = atomic_fetchadd_int(&exec_args_gen, 1) + 1;
+
+	/*
+	 * Force an madvise of each KVA range. Any currently allocated ranges
+	 * will have MADV_FREE applied once they are freed.
+	 */
+	SLIST_INIT(&head);
+	mtx_lock(&exec_args_kva_mtx);
+	SLIST_SWAP(&head, &exec_args_kva_freelist, exec_args_kva);
+	mtx_unlock(&exec_args_kva_mtx);
+	while ((argkva = SLIST_FIRST(&head)) != NULL) {
+		SLIST_REMOVE_HEAD(&head, next);
+		exec_release_args_kva(argkva, gen);
+	}
+
+	CPU_FOREACH(i) {
+		argkva = (void *)atomic_readandclear_ptr(
+		    (uintptr_t *)DPCPU_ID_PTR(i, exec_args_kva));
+		if (argkva != NULL)
+			exec_release_args_kva(argkva, gen);
+	}
+}
+EVENTHANDLER_DEFINE(vm_lowmem, exec_args_kva_lowmem, NULL,
+    EVENTHANDLER_PRI_ANY);
+
 /*
  * Allocate temporary demand-paged, zero-filled memory for the file name,
  * argument, and environment strings.


More information about the svn-src-all mailing list