254585788f
(queuing them here since it's unclear if they'll go into .37 or wait for .38)
168 lines
5.4 KiB
Diff
168 lines
5.4 KiB
Diff
From 82e3d4969144377d13da97d511e849e8cf3e6dcc Mon Sep 17 00:00:00 2001
|
|
From: Mel Gorman <mel@csn.ul.ie>
|
|
Date: Wed, 24 Nov 2010 22:24:24 -0500
|
|
Subject: [PATCH 2/2] mm: vmstat: Use a single setter function and callback for adjusting percpu thresholds
|
|
|
|
reduce_pgdat_percpu_threshold() and restore_pgdat_percpu_threshold() exist
|
|
to adjust the per-cpu vmstat thresholds while kswapd is awake to avoid
|
|
errors due to counter drift. The functions duplicate some code so this
|
|
patch replaces them with a single set_pgdat_percpu_threshold() that takes
|
|
a callback function to calculate the desired threshold as a parameter.
|
|
|
|
Signed-off-by: Mel Gorman <mel@csn.ul.ie>
|
|
Reviewed-by: Christoph Lameter <cl@linux.com>
|
|
Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
|
|
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
|
[the various mmotm patches updating this were rolled up. --kyle]
|
|
[[http://userweb.kernel.org/~akpm/mmotm/broken-out/mm-vmstat-use-a-single-setter-function-and-callback-for-adjusting-percpu-thresholds-fix-set_pgdat_percpu_threshold-dont-use-for_each_online_cpu.patch]]
|
|
---
|
|
include/linux/vmstat.h | 10 ++++++----
|
|
mm/vmscan.c | 19 +++++++++++++++++--
|
|
mm/vmstat.c | 36 +++++++-----------------------------
|
|
3 files changed, 30 insertions(+), 35 deletions(-)
|
|
|
|
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
|
|
index e4cc21c..833e676 100644
|
|
--- a/include/linux/vmstat.h
|
|
+++ b/include/linux/vmstat.h
|
|
@@ -254,8 +254,11 @@ extern void dec_zone_state(struct zone *, enum zone_stat_item);
|
|
extern void __dec_zone_state(struct zone *, enum zone_stat_item);
|
|
|
|
void refresh_cpu_vm_stats(int);
|
|
-void reduce_pgdat_percpu_threshold(pg_data_t *pgdat);
|
|
-void restore_pgdat_percpu_threshold(pg_data_t *pgdat);
|
|
+
|
|
+int calculate_pressure_threshold(struct zone *zone);
|
|
+int calculate_normal_threshold(struct zone *zone);
|
|
+void set_pgdat_percpu_threshold(pg_data_t *pgdat,
|
|
+ int (*calculate_pressure)(struct zone *));
|
|
#else /* CONFIG_SMP */
|
|
|
|
/*
|
|
@@ -300,8 +303,7 @@ static inline void __dec_zone_page_state(struct page *page,
|
|
#define dec_zone_page_state __dec_zone_page_state
|
|
#define mod_zone_page_state __mod_zone_page_state
|
|
|
|
-static inline void reduce_pgdat_percpu_threshold(pg_data_t *pgdat) { }
|
|
-static inline void restore_pgdat_percpu_threshold(pg_data_t *pgdat) { }
|
|
+#define set_pgdat_percpu_threshold(pgdat, callback) { }
|
|
|
|
static inline void refresh_cpu_vm_stats(int cpu) { }
|
|
#endif
|
|
diff --git a/mm/vmscan.c b/mm/vmscan.c
|
|
index 3e71cb1..ba39948 100644
|
|
--- a/mm/vmscan.c
|
|
+++ b/mm/vmscan.c
|
|
@@ -2378,9 +2378,24 @@ static int kswapd(void *p)
|
|
*/
|
|
if (!sleeping_prematurely(pgdat, order, remaining)) {
|
|
trace_mm_vmscan_kswapd_sleep(pgdat->node_id);
|
|
- restore_pgdat_percpu_threshold(pgdat);
|
|
+
|
|
+ /*
|
|
+ * vmstat counters are not perfectly
|
|
+ * accurate and the estimated value
|
|
+ * for counters such as NR_FREE_PAGES
|
|
+ * can deviate from the true value by
|
|
+ * nr_online_cpus * threshold. To
|
|
+ * avoid the zone watermarks being
|
|
+ * breached while under pressure, we
|
|
+ * reduce the per-cpu vmstat threshold
|
|
+ * while kswapd is awake and restore
|
|
+ * them before going back to sleep.
|
|
+ */
|
|
+ set_pgdat_percpu_threshold(pgdat,
|
|
+ calculate_normal_threshold);
|
|
schedule();
|
|
- reduce_pgdat_percpu_threshold(pgdat);
|
|
+ set_pgdat_percpu_threshold(pgdat,
|
|
+ calculate_pressure_threshold);
|
|
} else {
|
|
if (remaining)
|
|
count_vm_event(KSWAPD_LOW_WMARK_HIT_QUICKLY);
|
|
diff --git a/mm/vmstat.c b/mm/vmstat.c
|
|
index 4d7faeb..511c2c0 100644
|
|
--- a/mm/vmstat.c
|
|
+++ b/mm/vmstat.c
|
|
@@ -81,7 +81,7 @@ EXPORT_SYMBOL(vm_stat);
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
-static int calculate_pressure_threshold(struct zone *zone)
|
|
+int calculate_pressure_threshold(struct zone *zone)
|
|
{
|
|
int threshold;
|
|
int watermark_distance;
|
|
@@ -105,7 +105,7 @@ static int calculate_pressure_threshold(struct zone *zone)
|
|
return threshold;
|
|
}
|
|
|
|
-static int calculate_threshold(struct zone *zone)
|
|
+int calculate_normal_threshold(struct zone *zone)
|
|
{
|
|
int threshold;
|
|
int mem; /* memory in 128 MB units */
|
|
@@ -164,7 +164,7 @@ static void refresh_zone_stat_thresholds(void)
|
|
for_each_populated_zone(zone) {
|
|
unsigned long max_drift, tolerate_drift;
|
|
|
|
- threshold = calculate_threshold(zone);
|
|
+ threshold = calculate_normal_threshold(zone);
|
|
|
|
for_each_online_cpu(cpu)
|
|
per_cpu_ptr(zone->pageset, cpu)->stat_threshold
|
|
@@ -183,46 +183,24 @@ static void refresh_zone_stat_thresholds(void)
|
|
}
|
|
}
|
|
|
|
-void reduce_pgdat_percpu_threshold(pg_data_t *pgdat)
|
|
+void set_pgdat_percpu_threshold(pg_data_t *pgdat,
|
|
+ int (*calculate_pressure)(struct zone *))
|
|
{
|
|
struct zone *zone;
|
|
int cpu;
|
|
int threshold;
|
|
int i;
|
|
|
|
- get_online_cpus();
|
|
- for (i = 0; i < pgdat->nr_zones; i++) {
|
|
- zone = &pgdat->node_zones[i];
|
|
- if (!zone->percpu_drift_mark)
|
|
- continue;
|
|
-
|
|
- threshold = calculate_pressure_threshold(zone);
|
|
- for_each_online_cpu(cpu)
|
|
- per_cpu_ptr(zone->pageset, cpu)->stat_threshold
|
|
- = threshold;
|
|
- }
|
|
- put_online_cpus();
|
|
-}
|
|
-
|
|
-void restore_pgdat_percpu_threshold(pg_data_t *pgdat)
|
|
-{
|
|
- struct zone *zone;
|
|
- int cpu;
|
|
- int threshold;
|
|
- int i;
|
|
-
|
|
- get_online_cpus();
|
|
for (i = 0; i < pgdat->nr_zones; i++) {
|
|
zone = &pgdat->node_zones[i];
|
|
if (!zone->percpu_drift_mark)
|
|
continue;
|
|
|
|
- threshold = calculate_threshold(zone);
|
|
- for_each_online_cpu(cpu)
|
|
+ threshold = (*calculate_pressure)(zone);
|
|
+ for_each_possible_cpu(cpu)
|
|
per_cpu_ptr(zone->pageset, cpu)->stat_threshold
|
|
= threshold;
|
|
}
|
|
- put_online_cpus();
|
|
}
|
|
|
|
/*
|
|
--
|
|
1.7.3.2
|
|
|