Revert "mm: make vmstat_update periodic run conditional"
authorJon Medhurst (Tixy) <tixy@linaro.org>
Mon, 1 Jun 2015 11:35:25 +0000 (12:35 +0100)
committerKevin Hilman <khilman@linaro.org>
Mon, 1 Jun 2015 20:52:38 +0000 (13:52 -0700)
This reverts commit 7d252cd22a3f6cb459e8b012912dfd258157f7df because it
has been implicated in kernel crashes when its workqueue timer is
migrated during CPU hotplug.

When HMP was initially being developed against a 3.4 derived kernel, it
was observed that wakeups were occurring every 30s across every core to
give the vmstat accounting a kick. This was causing a noticeable
increase in energy consumption on the really quiet use cases such as
audio and video playback. So commit 7d252cd22a was used which turned off
the updates on idle CPUs to reduce that.

On the 3.10 derived LSK this revert does not result in a significant
increase in power consumption so it is assumed that changes since 3.4
have mitigated the initial problem.

Signed-off-by: Jon Medhurst <tixy@linaro.org>
Signed-off-by: Kevin Hilman <khilman@linaro.org>
include/linux/vmstat.h
mm/vmstat.c

index a30ab7910ff4ad3fafe04fc0bd7b92958f5610d7..c586679b6fefd4f8f15fe68d123295fc4d7af39f 100644 (file)
@@ -198,7 +198,7 @@ extern void __inc_zone_state(struct zone *, enum zone_stat_item);
 extern void dec_zone_state(struct zone *, enum zone_stat_item);
 extern void __dec_zone_state(struct zone *, enum zone_stat_item);
 
-bool refresh_cpu_vm_stats(int);
+void refresh_cpu_vm_stats(int);
 void refresh_zone_stat_thresholds(void);
 
 void drain_zonestat(struct zone *zone, struct per_cpu_pageset *);
index b916a43a6b37e17e065655bdfb4a854e850bfd58..f42745e65780b97a1875cde1df81fe527350d59a 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/cpu.h>
-#include <linux/cpumask.h>
 #include <linux/vmstat.h>
 #include <linux/sched.h>
 #include <linux/math64.h>
@@ -433,12 +432,11 @@ EXPORT_SYMBOL(dec_zone_page_state);
  * with the global counters. These could cause remote node cache line
  * bouncing and will have to be only done when necessary.
  */
-bool refresh_cpu_vm_stats(int cpu)
+void refresh_cpu_vm_stats(int cpu)
 {
        struct zone *zone;
        int i;
        int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
-       bool vm_activity = false;
 
        for_each_populated_zone(zone) {
                struct per_cpu_pageset *p;
@@ -485,21 +483,14 @@ bool refresh_cpu_vm_stats(int cpu)
                if (p->expire)
                        continue;
 
-               if (p->pcp.count) {
-                       vm_activity = true;
+               if (p->pcp.count)
                        drain_zone_pages(zone, &p->pcp);
-               }
 #endif
        }
 
        for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-               if (global_diff[i]) {
+               if (global_diff[i])
                        atomic_long_add(global_diff[i], &vm_stat[i]);
-                       vm_activity = true;
-               }
-
-       return vm_activity;
-
 }
 
 /*
@@ -1183,70 +1174,20 @@ static const struct file_operations proc_vmstat_file_operations = {
 #ifdef CONFIG_SMP
 static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
 int sysctl_stat_interval __read_mostly = HZ;
-static struct cpumask vmstat_off_cpus;
-struct delayed_work vmstat_monitor_work;
-
-static inline bool need_vmstat(int cpu)
-{
-       struct zone *zone;
-       int i;
-
-       for_each_populated_zone(zone) {
-               struct per_cpu_pageset *p;
 
-               p = per_cpu_ptr(zone->pageset, cpu);
-
-               for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-                       if (p->vm_stat_diff[i])
-                               return true;
-
-               if (zone_to_nid(zone) != numa_node_id() && p->pcp.count)
-                       return true;
-       }
-
-       return false;
-}
-
-static void vmstat_update(struct work_struct *w);
-
-static void start_cpu_timer(int cpu)
+static void vmstat_update(struct work_struct *w)
 {
-       struct delayed_work *work = &per_cpu(vmstat_work, cpu);
-
-       cpumask_clear_cpu(cpu, &vmstat_off_cpus);
-       schedule_delayed_work_on(cpu, work, __round_jiffies_relative(HZ, cpu));
+       refresh_cpu_vm_stats(smp_processor_id());
+       schedule_delayed_work(&__get_cpu_var(vmstat_work),
+               round_jiffies_relative(sysctl_stat_interval));
 }
 
-static void __cpuinit setup_cpu_timer(int cpu)
+static void __cpuinit start_cpu_timer(int cpu)
 {
        struct delayed_work *work = &per_cpu(vmstat_work, cpu);
 
        INIT_DEFERRABLE_WORK(work, vmstat_update);
-       start_cpu_timer(cpu);
-}
-
-static void vmstat_update_monitor(struct work_struct *w)
-{
-       int cpu;
-
-       for_each_cpu_and(cpu, &vmstat_off_cpus, cpu_online_mask)
-               if (need_vmstat(cpu))
-                       start_cpu_timer(cpu);
-
-       queue_delayed_work(system_unbound_wq, &vmstat_monitor_work,
-               round_jiffies_relative(sysctl_stat_interval));
-}
-
-
-static void vmstat_update(struct work_struct *w)
-{
-       int cpu = smp_processor_id();
-
-       if (likely(refresh_cpu_vm_stats(cpu)))
-               schedule_delayed_work(&__get_cpu_var(vmstat_work),
-                               round_jiffies_relative(sysctl_stat_interval));
-       else
-               cpumask_set_cpu(cpu, &vmstat_off_cpus);
+       schedule_delayed_work_on(cpu, work, __round_jiffies_relative(HZ, cpu));
 }
 
 /*
@@ -1263,19 +1204,17 @@ static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
                refresh_zone_stat_thresholds();
-               setup_cpu_timer(cpu);
+               start_cpu_timer(cpu);
                node_set_state(cpu_to_node(cpu), N_CPU);
                break;
        case CPU_DOWN_PREPARE:
        case CPU_DOWN_PREPARE_FROZEN:
-               if (!cpumask_test_cpu(cpu, &vmstat_off_cpus)) {
-                       cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));
-                       per_cpu(vmstat_work, cpu).work.func = NULL;
-               }
+               cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));
+               per_cpu(vmstat_work, cpu).work.func = NULL;
                break;
        case CPU_DOWN_FAILED:
        case CPU_DOWN_FAILED_FROZEN:
-               setup_cpu_timer(cpu);
+               start_cpu_timer(cpu);
                break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
@@ -1298,14 +1237,8 @@ static int __init setup_vmstat(void)
 
        register_cpu_notifier(&vmstat_notifier);
 
-       INIT_DEFERRABLE_WORK(&vmstat_monitor_work,
-                               vmstat_update_monitor);
-       queue_delayed_work(system_unbound_wq,
-                               &vmstat_monitor_work,
-                               round_jiffies_relative(HZ));
-
        for_each_online_cpu(cpu)
-               setup_cpu_timer(cpu);
+               start_cpu_timer(cpu);
 #endif
 #ifdef CONFIG_PROC_FS
        proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);