All of lore.kernel.org
 help / color / mirror / Atom feed
diff for duplicates of <20150824075018.GB20106@gmail.com>

diff --git a/a/1.txt b/N1/1.txt
index 8261fa8..6369332 100644
--- a/a/1.txt
+++ b/N1/1.txt
@@ -15,3 +15,145 @@ Thanks,
 	Ingo
 
 ========================>
+>From 46a0507e0a395a7bc2fe4b46a4766e7457ac0140 Mon Sep 17 00:00:00 2001
+From: Ingo Molnar <mingo@kernel.org>
+Date: Sat, 22 Aug 2015 12:28:01 +0200
+Subject: [PATCH] mm/vmalloc: Cache the vmalloc memory info
+
+Linus reported that for scripting-intense workloads such as the
+Git build, glibc's qsort will read /proc/meminfo for every process
+created (by way of get_phys_pages()), which causes the Git build
+to generate a surprising amount of kernel overhead.
+
+A fair chunk of the overhead is due to get_vmalloc_info() - which
+walks a potentially long list to do its statistics.
+
+Modify Linus's jiffies based patch to use generation counters
+to cache the vmalloc info: vmap_unlock() increases the generation
+counter, and the get_vmalloc_info() reads it and compares it
+against a cached generation counter.
+
+Also use a seqlock to make sure we always print a consistent
+set of vmalloc statistics.
+
+Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Rik van Riel <riel@redhat.com>
+Cc: linux-mm@kvack.org
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+---
+ mm/vmalloc.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 79 insertions(+), 3 deletions(-)
+
+diff --git a/mm/vmalloc.c b/mm/vmalloc.c
+index 605138083880..2f8d9660e007 100644
+--- a/mm/vmalloc.c
++++ b/mm/vmalloc.c
+@@ -276,7 +276,21 @@ EXPORT_SYMBOL(vmalloc_to_pfn);
+ #define VM_LAZY_FREEING	0x02
+ #define VM_VM_AREA	0x04
+ 
+-static DEFINE_SPINLOCK(vmap_area_lock);
++static __cacheline_aligned_in_smp DEFINE_SPINLOCK(vmap_area_lock);
++
++#ifdef CONFIG_PROC_FS
++/*
++ * A seqlock and two generation counters for a simple cache of the
++ * vmalloc allocation statistics info printed in /proc/meminfo.
++ *
++ * ( The assumption of the optimization is that it's read frequently, but
++ *   modified infrequently. )
++ */
++static DEFINE_SPINLOCK(vmap_info_lock);
++static int vmap_info_gen = 1;
++static int vmap_info_cache_gen;
++static struct vmalloc_info vmap_info_cache;
++#endif
+ 
+ static inline void vmap_lock(void)
+ {
+@@ -285,6 +299,9 @@ static inline void vmap_lock(void)
+ 
+ static inline void vmap_unlock(void)
+ {
++#ifdef CONFIG_PROC_FS
++	WRITE_ONCE(vmap_info_gen, vmap_info_gen+1);
++#endif
+ 	spin_unlock(&vmap_area_lock);
+ }
+ 
+@@ -2699,7 +2716,7 @@ static int __init proc_vmalloc_init(void)
+ }
+ module_init(proc_vmalloc_init);
+ 
+-void get_vmalloc_info(struct vmalloc_info *vmi)
++static void calc_vmalloc_info(struct vmalloc_info *vmi)
+ {
+ 	struct vmap_area *va;
+ 	unsigned long free_area_size;
+@@ -2746,5 +2763,64 @@ void get_vmalloc_info(struct vmalloc_info *vmi)
+ out:
+ 	rcu_read_unlock();
+ }
+-#endif
+ 
++/*
++ * Return a consistent snapshot of the current vmalloc allocation
++ * statistics, for /proc/meminfo:
++ */
++void get_vmalloc_info(struct vmalloc_info *vmi)
++{
++	int gen = vmap_info_gen;
++
++	/*
++	 * If the generation counter of the cache matches that of
++	 * the vmalloc generation counter then return the cache:
++	 */
++	if (vmap_info_cache_gen == gen) {
++		int gen_after;
++
++		/*
++		 * The two read barriers make sure that we read
++		 * 'gen', 'vmap_info_cache' and 'gen_after' in
++		 * precisely that order:
++		 */
++		smp_rmb();
++		*vmi = vmap_info_cache;
++
++		smp_rmb();
++		gen_after = vmap_info_gen;
++
++		/* The cache is still valid: */
++		if (gen == gen_after)
++			return;
++
++		/* Ok, the cache got invalidated just now, regenerate it */
++		gen = gen_after;
++	}
++
++	/* Make sure 'gen' is read before the vmalloc info */
++	smp_rmb();
++
++	calc_vmalloc_info(vmi);
++
++	/*
++	 * All updates to vmap_info_cache_gen go through this spinlock,
++	 * so when the cache got invalidated, we'll only mark it valid
++	 * again if we first fully write the new vmap_info_cache.
++	 *
++	 * This ensures that partial results won't be used.
++	 */
++	spin_lock(&vmap_info_lock);
++	if (gen-vmap_info_cache_gen > 0) {
++		vmap_info_cache = *vmi;
++		/*
++		 * Make sure the new cached data is visible before
++		 * the generation counter update:
++		 */
++		smp_wmb();
++		vmap_info_cache_gen = gen;
++	}
++	spin_unlock(&vmap_info_lock);
++}
++
++#endif /* CONFIG_PROC_FS */
diff --git a/a/content_digest b/N1/content_digest
index a33d7b8..0111980 100644
--- a/a/content_digest
+++ b/N1/content_digest
@@ -32,6 +32,148 @@
  "\n"
  "\tIngo\n"
  "\n"
- ========================>
+ "========================>\n"
+ ">From 46a0507e0a395a7bc2fe4b46a4766e7457ac0140 Mon Sep 17 00:00:00 2001\n"
+ "From: Ingo Molnar <mingo@kernel.org>\n"
+ "Date: Sat, 22 Aug 2015 12:28:01 +0200\n"
+ "Subject: [PATCH] mm/vmalloc: Cache the vmalloc memory info\n"
+ "\n"
+ "Linus reported that for scripting-intense workloads such as the\n"
+ "Git build, glibc's qsort will read /proc/meminfo for every process\n"
+ "created (by way of get_phys_pages()), which causes the Git build\n"
+ "to generate a surprising amount of kernel overhead.\n"
+ "\n"
+ "A fair chunk of the overhead is due to get_vmalloc_info() - which\n"
+ "walks a potentially long list to do its statistics.\n"
+ "\n"
+ "Modify Linus's jiffies based patch to use generation counters\n"
+ "to cache the vmalloc info: vmap_unlock() increases the generation\n"
+ "counter, and the get_vmalloc_info() reads it and compares it\n"
+ "against a cached generation counter.\n"
+ "\n"
+ "Also use a seqlock to make sure we always print a consistent\n"
+ "set of vmalloc statistics.\n"
+ "\n"
+ "Reported-by: Linus Torvalds <torvalds@linux-foundation.org>\n"
+ "Cc: Andrew Morton <akpm@linux-foundation.org>\n"
+ "Cc: Rik van Riel <riel@redhat.com>\n"
+ "Cc: linux-mm@kvack.org\n"
+ "Signed-off-by: Ingo Molnar <mingo@kernel.org>\n"
+ "---\n"
+ " mm/vmalloc.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---\n"
+ " 1 file changed, 79 insertions(+), 3 deletions(-)\n"
+ "\n"
+ "diff --git a/mm/vmalloc.c b/mm/vmalloc.c\n"
+ "index 605138083880..2f8d9660e007 100644\n"
+ "--- a/mm/vmalloc.c\n"
+ "+++ b/mm/vmalloc.c\n"
+ "@@ -276,7 +276,21 @@ EXPORT_SYMBOL(vmalloc_to_pfn);\n"
+ " #define VM_LAZY_FREEING\t0x02\n"
+ " #define VM_VM_AREA\t0x04\n"
+ " \n"
+ "-static DEFINE_SPINLOCK(vmap_area_lock);\n"
+ "+static __cacheline_aligned_in_smp DEFINE_SPINLOCK(vmap_area_lock);\n"
+ "+\n"
+ "+#ifdef CONFIG_PROC_FS\n"
+ "+/*\n"
+ "+ * A seqlock and two generation counters for a simple cache of the\n"
+ "+ * vmalloc allocation statistics info printed in /proc/meminfo.\n"
+ "+ *\n"
+ "+ * ( The assumption of the optimization is that it's read frequently, but\n"
+ "+ *   modified infrequently. )\n"
+ "+ */\n"
+ "+static DEFINE_SPINLOCK(vmap_info_lock);\n"
+ "+static int vmap_info_gen = 1;\n"
+ "+static int vmap_info_cache_gen;\n"
+ "+static struct vmalloc_info vmap_info_cache;\n"
+ "+#endif\n"
+ " \n"
+ " static inline void vmap_lock(void)\n"
+ " {\n"
+ "@@ -285,6 +299,9 @@ static inline void vmap_lock(void)\n"
+ " \n"
+ " static inline void vmap_unlock(void)\n"
+ " {\n"
+ "+#ifdef CONFIG_PROC_FS\n"
+ "+\tWRITE_ONCE(vmap_info_gen, vmap_info_gen+1);\n"
+ "+#endif\n"
+ " \tspin_unlock(&vmap_area_lock);\n"
+ " }\n"
+ " \n"
+ "@@ -2699,7 +2716,7 @@ static int __init proc_vmalloc_init(void)\n"
+ " }\n"
+ " module_init(proc_vmalloc_init);\n"
+ " \n"
+ "-void get_vmalloc_info(struct vmalloc_info *vmi)\n"
+ "+static void calc_vmalloc_info(struct vmalloc_info *vmi)\n"
+ " {\n"
+ " \tstruct vmap_area *va;\n"
+ " \tunsigned long free_area_size;\n"
+ "@@ -2746,5 +2763,64 @@ void get_vmalloc_info(struct vmalloc_info *vmi)\n"
+ " out:\n"
+ " \trcu_read_unlock();\n"
+ " }\n"
+ "-#endif\n"
+ " \n"
+ "+/*\n"
+ "+ * Return a consistent snapshot of the current vmalloc allocation\n"
+ "+ * statistics, for /proc/meminfo:\n"
+ "+ */\n"
+ "+void get_vmalloc_info(struct vmalloc_info *vmi)\n"
+ "+{\n"
+ "+\tint gen = vmap_info_gen;\n"
+ "+\n"
+ "+\t/*\n"
+ "+\t * If the generation counter of the cache matches that of\n"
+ "+\t * the vmalloc generation counter then return the cache:\n"
+ "+\t */\n"
+ "+\tif (vmap_info_cache_gen == gen) {\n"
+ "+\t\tint gen_after;\n"
+ "+\n"
+ "+\t\t/*\n"
+ "+\t\t * The two read barriers make sure that we read\n"
+ "+\t\t * 'gen', 'vmap_info_cache' and 'gen_after' in\n"
+ "+\t\t * precisely that order:\n"
+ "+\t\t */\n"
+ "+\t\tsmp_rmb();\n"
+ "+\t\t*vmi = vmap_info_cache;\n"
+ "+\n"
+ "+\t\tsmp_rmb();\n"
+ "+\t\tgen_after = vmap_info_gen;\n"
+ "+\n"
+ "+\t\t/* The cache is still valid: */\n"
+ "+\t\tif (gen == gen_after)\n"
+ "+\t\t\treturn;\n"
+ "+\n"
+ "+\t\t/* Ok, the cache got invalidated just now, regenerate it */\n"
+ "+\t\tgen = gen_after;\n"
+ "+\t}\n"
+ "+\n"
+ "+\t/* Make sure 'gen' is read before the vmalloc info */\n"
+ "+\tsmp_rmb();\n"
+ "+\n"
+ "+\tcalc_vmalloc_info(vmi);\n"
+ "+\n"
+ "+\t/*\n"
+ "+\t * All updates to vmap_info_cache_gen go through this spinlock,\n"
+ "+\t * so when the cache got invalidated, we'll only mark it valid\n"
+ "+\t * again if we first fully write the new vmap_info_cache.\n"
+ "+\t *\n"
+ "+\t * This ensures that partial results won't be used.\n"
+ "+\t */\n"
+ "+\tspin_lock(&vmap_info_lock);\n"
+ "+\tif (gen-vmap_info_cache_gen > 0) {\n"
+ "+\t\tvmap_info_cache = *vmi;\n"
+ "+\t\t/*\n"
+ "+\t\t * Make sure the new cached data is visible before\n"
+ "+\t\t * the generation counter update:\n"
+ "+\t\t */\n"
+ "+\t\tsmp_wmb();\n"
+ "+\t\tvmap_info_cache_gen = gen;\n"
+ "+\t}\n"
+ "+\tspin_unlock(&vmap_info_lock);\n"
+ "+}\n"
+ "+\n"
+ +#endif /* CONFIG_PROC_FS */
 
-fe14fe3cd7bca331464e49bf844d8b983aa11a0615b54c642cc4fa3bbd7d4ba8
+fa7d04a1dd39f096d77235c42bb3eeaa02f0e80cfea6642448648b720d013e38

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.