diff for duplicates of <20150824073422.GC13082@gmail.com> diff --git a/a/1.txt b/N1/1.txt index bba788d..e392f5d 100644 --- a/a/1.txt +++ b/N1/1.txt @@ -69,3 +69,146 @@ Thanks, Ingo ======================> +>From 1a4c168a22cc302282cbd1bf503ecfc4dc52b74f 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 | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 80 insertions(+), 3 deletions(-) + +diff --git a/mm/vmalloc.c b/mm/vmalloc.c +index 605138083880..23df06ebb48a 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,65 @@ 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 = READ_ONCE(vmap_info_gen); ++ ++ /* ++ * If the generation counter of the cache matches that of ++ * the vmalloc generation counter then return the cache: ++ */ ++ if (READ_ONCE(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 = READ_ONCE(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(); ++ ++ WRITE_ONCE(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 0165beb..c04cc8d 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -84,6 +84,149 @@ "\n" "\tIngo\n" "\n" - ======================> + "======================>\n" + ">From 1a4c168a22cc302282cbd1bf503ecfc4dc52b74f 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 | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---\n" + " 1 file changed, 80 insertions(+), 3 deletions(-)\n" + "\n" + "diff --git a/mm/vmalloc.c b/mm/vmalloc.c\n" + "index 605138083880..23df06ebb48a 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,65 @@ 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 = READ_ONCE(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 (READ_ONCE(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 = READ_ONCE(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" + "+\n" + "+\t\tWRITE_ONCE(vmap_info_cache_gen, gen);\n" + "+\t}\n" + "+\tspin_unlock(&vmap_info_lock);\n" + "+}\n" + "+\n" + +#endif /* CONFIG_PROC_FS */ -a5350ea5f16f29acc83177ed7b4da1bdd13088be09b7432b5afcd62d3a121b87 +ac2a533375fc21f421887ba1e3c6079354a6bf4548480aaf518dcd041b713e7c
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.