Skip to content

Commit d1187ed

Browse files
Christoph LameterLinus Torvalds
authored andcommitted
vmstat: use our own timer events
vmstat is currently using the cache reaper to periodically bring the statistics up to date. The cache reaper does only exists in SLUB as a way to provide compatibility with SLAB. This patch removes the vmstat calls from the slab allocators and provides its own handling. The advantage is also that we can use a different frequency for the updates. Refreshing vm stats is a pretty fast job so we can run this every second and stagger this by only one tick. This will lead to some overlap in large systems. F.e a system running at 250 HZ with 1024 processors will have 4 vm updates occurring at once. However, the vm stats update only accesses per node information. It is only necessary to stagger the vm statistics updates per processor in each node. Vm counter updates occurring on distant nodes will not cause cacheline contention. We could implement an alternate approach that runs the first processor on each node at the second and then each of the other processor on a node on a subsequent tick. That may be useful to keep a large amount of the second free of timer activity. Maybe the timer folks will have some feedback on this one? [jirislaby@gmail.com: add missing break] Cc: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Christoph Lameter <clameter@sgi.com> Signed-off-by: Jiri Slaby <jirislaby@gmail.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 455c017 commit d1187ed

File tree

4 files changed

+36
-9
lines changed

4 files changed

+36
-9
lines changed

include/linux/vmstat.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,6 @@ extern void dec_zone_state(struct zone *, enum zone_stat_item);
212212
extern void __dec_zone_state(struct zone *, enum zone_stat_item);
213213

214214
void refresh_cpu_vm_stats(int);
215-
void refresh_vm_stats(void);
216-
217215
#else /* CONFIG_SMP */
218216

219217
/*
@@ -260,7 +258,6 @@ static inline void __dec_zone_page_state(struct page *page,
260258
#define mod_zone_page_state __mod_zone_page_state
261259

262260
static inline void refresh_cpu_vm_stats(int cpu) { }
263-
static inline void refresh_vm_stats(void) { }
264261
#endif
265262

266263
#endif /* _LINUX_VMSTAT_H */

mm/slab.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4156,7 +4156,6 @@ static void cache_reap(struct work_struct *w)
41564156
check_irq_on();
41574157
mutex_unlock(&cache_chain_mutex);
41584158
next_reap_node();
4159-
refresh_cpu_vm_stats(smp_processor_id());
41604159
out:
41614160
/* Set up the next iteration */
41624161
schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_CPUC));

mm/slub.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2580,7 +2580,6 @@ static DEFINE_PER_CPU(struct delayed_work, reap_work);
25802580
static void cache_reap(struct work_struct *unused)
25812581
{
25822582
next_reap_node();
2583-
refresh_cpu_vm_stats(smp_processor_id());
25842583
schedule_delayed_work(&__get_cpu_var(reap_work),
25852584
REAPTIMEOUT_CPUC);
25862585
}

mm/vmstat.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,22 @@ const struct seq_operations vmstat_op = {
640640
#endif /* CONFIG_PROC_FS */
641641

642642
#ifdef CONFIG_SMP
643+
static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
644+
645+
static void vmstat_update(struct work_struct *w)
646+
{
647+
refresh_cpu_vm_stats(smp_processor_id());
648+
schedule_delayed_work(&__get_cpu_var(vmstat_work), HZ);
649+
}
650+
651+
static void __devinit start_cpu_timer(int cpu)
652+
{
653+
struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
654+
655+
INIT_DELAYED_WORK(vmstat_work, vmstat_update);
656+
schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
657+
}
658+
643659
/*
644660
* Use the cpu notifier to insure that the thresholds are recalculated
645661
* when necessary.
@@ -648,11 +664,22 @@ static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
648664
unsigned long action,
649665
void *hcpu)
650666
{
667+
long cpu = (long)hcpu;
668+
651669
switch (action) {
652-
case CPU_UP_PREPARE:
653-
case CPU_UP_PREPARE_FROZEN:
654-
case CPU_UP_CANCELED:
655-
case CPU_UP_CANCELED_FROZEN:
670+
case CPU_ONLINE:
671+
case CPU_ONLINE_FROZEN:
672+
start_cpu_timer(cpu);
673+
break;
674+
case CPU_DOWN_PREPARE:
675+
case CPU_DOWN_PREPARE_FROZEN:
676+
cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu));
677+
per_cpu(vmstat_work, cpu).work.func = NULL;
678+
break;
679+
case CPU_DOWN_FAILED:
680+
case CPU_DOWN_FAILED_FROZEN:
681+
start_cpu_timer(cpu);
682+
break;
656683
case CPU_DEAD:
657684
case CPU_DEAD_FROZEN:
658685
refresh_zone_stat_thresholds();
@@ -668,8 +695,13 @@ static struct notifier_block __cpuinitdata vmstat_notifier =
668695

669696
int __init setup_vmstat(void)
670697
{
698+
int cpu;
699+
671700
refresh_zone_stat_thresholds();
672701
register_cpu_notifier(&vmstat_notifier);
702+
703+
for_each_online_cpu(cpu)
704+
start_cpu_timer(cpu);
673705
return 0;
674706
}
675707
module_init(setup_vmstat)

0 commit comments

Comments
 (0)