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

diff --git a/a/1.txt b/N1/1.txt
index 89b0acf..4e7f22a 100644
--- a/a/1.txt
+++ b/N1/1.txt
@@ -54,3 +54,141 @@ Thanks,
 	Ingo
 
 ==============================>
+>From 8364822f9cff9da9f9858f0ca1f1ddc5bd3ad3a1 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 certain workloads such as 'make test' in 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 spinlock to make sure we always print a consistent
+set of vmalloc statistics, FWIIW.
+
+Reported-by: Linus Torvalds <torvalds@linux-foundation.org>
+Reviewed-by: George Spelvin <linux@horizon.com>
+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 | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 74 insertions(+), 3 deletions(-)
+
+diff --git a/mm/vmalloc.c b/mm/vmalloc.c
+index 605138083880..a0a4274a7be9 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 unsigned int vmap_info_gen = 1;
++static unsigned 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,59 @@ 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)
++{
++	unsigned int cache_gen, gen;
++
++	/*
++	 * The common case is that the cache is valid, so first
++	 * read it, then check its validity.
++	 *
++	 * The two read barriers make sure that we read
++	 * 'cache_gen', 'vmap_info_cache' and 'gen' in
++	 * precisely that order:
++	 */
++	cache_gen = vmap_info_cache_gen;
++	smp_rmb();
++	*vmi = vmap_info_cache;
++	smp_rmb();
++	gen = vmap_info_gen;
++
++	/*
++	 * If the generation counter of the cache matches that of
++	 * the vmalloc generation counter then return the cache:
++	 */
++	if (cache_gen == gen)
++		return;
++
++	/* 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 and that the
++	 * vmalloc info belonging to the freshest update is used:
++	 */
++	spin_lock(&vmap_info_lock);
++	if ((int)(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 9296506..90b6279 100644
--- a/a/content_digest
+++ b/N1/content_digest
@@ -69,6 +69,144 @@
  "\n"
  "\tIngo\n"
  "\n"
- ==============================>
+ "==============================>\n"
+ ">From 8364822f9cff9da9f9858f0ca1f1ddc5bd3ad3a1 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 certain workloads such as 'make test' in 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 spinlock to make sure we always print a consistent\n"
+ "set of vmalloc statistics, FWIIW.\n"
+ "\n"
+ "Reported-by: Linus Torvalds <torvalds@linux-foundation.org>\n"
+ "Reviewed-by: George Spelvin <linux@horizon.com>\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 | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---\n"
+ " 1 file changed, 74 insertions(+), 3 deletions(-)\n"
+ "\n"
+ "diff --git a/mm/vmalloc.c b/mm/vmalloc.c\n"
+ "index 605138083880..a0a4274a7be9 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 unsigned int vmap_info_gen = 1;\n"
+ "+static unsigned 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,59 @@ 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"
+ "+\tunsigned int cache_gen, gen;\n"
+ "+\n"
+ "+\t/*\n"
+ "+\t * The common case is that the cache is valid, so first\n"
+ "+\t * read it, then check its validity.\n"
+ "+\t *\n"
+ "+\t * The two read barriers make sure that we read\n"
+ "+\t * 'cache_gen', 'vmap_info_cache' and 'gen' in\n"
+ "+\t * precisely that order:\n"
+ "+\t */\n"
+ "+\tcache_gen = vmap_info_cache_gen;\n"
+ "+\tsmp_rmb();\n"
+ "+\t*vmi = vmap_info_cache;\n"
+ "+\tsmp_rmb();\n"
+ "+\tgen = 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 (cache_gen == gen)\n"
+ "+\t\treturn;\n"
+ "+\n"
+ "+\t/* Make sure 'gen' is read before the vmalloc info: */\n"
+ "+\tsmp_rmb();\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 and that the\n"
+ "+\t * vmalloc info belonging to the freshest update is used:\n"
+ "+\t */\n"
+ "+\tspin_lock(&vmap_info_lock);\n"
+ "+\tif ((int)(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 */
 
-79fce9abfca5a314584149b6a5ebde7334c1d4f2f9d972c947f41fa940ff303d
+22b2ff9ad4f653d947bbf8a3cb31ae932ab33efbdf2e62f244b01cd734c4109e

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.