]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
tick-sched: add specific do_timer_cpu value for nohz off mode
authorDimitri Sivanich <sivanich@sgi.com>
Fri, 16 Dec 2011 04:49:32 +0000 (15:49 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Wed, 21 Dec 2011 06:00:13 +0000 (17:00 +1100)
Show and modify the tick_do_timer_cpu via sysfs.  This determines the cpu
on which global time (jiffies) updates occur.  Modification can only be
done on systems with nohz mode turned off.

While not necessarily harmful, doing jiffies updates on an application cpu
does cause some extra overhead that HPC benchmarking people notice.  They
prefer to have OS activity isolated to certain cpus.  They like
reproducibility of results, and having jiffies updates bouncing around
introduces variability.

Signed-off-by: Dimitri Sivanich <sivanich@sgi.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Documentation/ABI/testing/sysfs-devices-system-timekeeping [new file with mode: 0644]
drivers/base/sys.c
include/linux/sysdev.h
kernel/time/tick-sched.c

diff --git a/Documentation/ABI/testing/sysfs-devices-system-timekeeping b/Documentation/ABI/testing/sysfs-devices-system-timekeeping
new file mode 100644 (file)
index 0000000..a904c6d
--- /dev/null
@@ -0,0 +1,16 @@
+What:          /sys/devices/system/timekeeping/
+Date:          November 2011
+Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
+Description:   Timekeeping attributes
+
+
+What:          /sys/devices/system/timekeeping/timekeeping0/jiffies_cpu
+Date:          November 2011
+Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
+Description:   Show and modify the kernel's tick_do_timer_cpu.  This
+               determines the cpu on which global time (jiffies) updates
+               occur.  This can only be modified on systems running with
+               the nohz mode turned off (nohz=off).
+
+               Possible values are:
+                       0 - <num online cpus>
index 409f5ce78829a7a7624a56f6f19422f783ae7e83..6b04be02ab8148a7300a4629570214e90cbcb04d 100644 (file)
@@ -331,13 +331,11 @@ void sysdev_unregister(struct sys_device *sysdev)
 EXPORT_SYMBOL_GPL(sysdev_register);
 EXPORT_SYMBOL_GPL(sysdev_unregister);
 
-#define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr)
-
 ssize_t sysdev_store_ulong(struct sys_device *sysdev,
                           struct sysdev_attribute *attr,
                           const char *buf, size_t size)
 {
-       struct sysdev_ext_attribute *ea = to_ext_attr(attr);
+       struct sysdev_ext_attribute *ea = SYSDEV_TO_EXT_ATTR(attr);
        char *end;
        unsigned long new = simple_strtoul(buf, &end, 0);
        if (end == buf)
@@ -352,7 +350,7 @@ ssize_t sysdev_show_ulong(struct sys_device *sysdev,
                          struct sysdev_attribute *attr,
                          char *buf)
 {
-       struct sysdev_ext_attribute *ea = to_ext_attr(attr);
+       struct sysdev_ext_attribute *ea = SYSDEV_TO_EXT_ATTR(attr);
        return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var));
 }
 EXPORT_SYMBOL_GPL(sysdev_show_ulong);
@@ -361,7 +359,7 @@ ssize_t sysdev_store_int(struct sys_device *sysdev,
                           struct sysdev_attribute *attr,
                           const char *buf, size_t size)
 {
-       struct sysdev_ext_attribute *ea = to_ext_attr(attr);
+       struct sysdev_ext_attribute *ea = SYSDEV_TO_EXT_ATTR(attr);
        char *end;
        long new = simple_strtol(buf, &end, 0);
        if (end == buf || new > INT_MAX || new < INT_MIN)
@@ -376,7 +374,7 @@ ssize_t sysdev_show_int(struct sys_device *sysdev,
                          struct sysdev_attribute *attr,
                          char *buf)
 {
-       struct sysdev_ext_attribute *ea = to_ext_attr(attr);
+       struct sysdev_ext_attribute *ea = SYSDEV_TO_EXT_ATTR(attr);
        return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var));
 }
 EXPORT_SYMBOL_GPL(sysdev_show_int);
index 20f63d3e6144654f0124170827eab474a1b41faa..7ab0c81cab1d37bf39135d4bda4e2e2b34a6867f 100644 (file)
@@ -132,6 +132,8 @@ struct sysdev_ext_attribute {
        void *var;
 };
 
+#define SYSDEV_TO_EXT_ATTR(x) container_of(x, struct sysdev_ext_attribute, attr)
+
 /*
  * Support for simple variable sysdev attributes.
  * The pointer to the variable is stored in a sysdev_ext_attribute
index 696c997f8784ae1a0a4f9a20cbc1a9d5133fe399..1305a49f20e3c89da506690fd91d313ace629758 100644 (file)
@@ -865,6 +865,73 @@ void tick_cancel_sched_timer(int cpu)
 }
 #endif
 
+#ifdef CONFIG_SYSFS
+/*
+ * Allow modification of tick_do_timer_cpu when nohz mode is off.
+ */
+static ssize_t sysfs_store_do_timer_cpu(struct sys_device *dev,
+                                               struct sysdev_attribute *attr,
+                                               const char *buf, size_t size)
+{
+       struct sysdev_ext_attribute *ea = SYSDEV_TO_EXT_ATTR(attr);
+       unsigned int new;
+       int rv;
+
+#ifdef CONFIG_NO_HZ
+       /* nohz mode not supported */
+       if (tick_nohz_enabled)
+               return -EINVAL;
+#endif
+
+       rv = kstrtouint(buf, 0, &new);
+       if (rv)
+               return rv;
+
+       /* Protect against cpu-hotplug */
+       get_online_cpus();
+
+       if (new >= nr_cpu_ids || !cpu_online(new)) {
+               put_online_cpus();
+               return -ERANGE;
+       }
+
+       *(unsigned int *)(ea->var) = new;
+
+       put_online_cpus();
+
+       return size;
+}
+
+static struct sysdev_ext_attribute attr_jiffies_cpu = {
+                       _SYSDEV_ATTR(jiffies_cpu, 0644, sysdev_show_int,
+                                       sysfs_store_do_timer_cpu),
+                       &tick_do_timer_cpu };
+
+static struct sysdev_class timekeeping_sysclass = {
+       .name = "timekeeping",
+};
+
+static struct sys_device device_timekeeping = {
+       .id     = 0,
+       .cls    = &timekeeping_sysclass,
+};
+
+static int __init init_timekeeping_sysfs(void)
+{
+       int error = sysdev_class_register(&timekeeping_sysclass);
+
+       if (!error)
+               error = sysdev_register(&device_timekeeping);
+       if (!error)
+               error = sysdev_create_file(
+                               &device_timekeeping,
+                               &attr_jiffies_cpu.attr);
+       return error;
+}
+
+device_initcall(init_timekeeping_sysfs);
+#endif /* SYSFS */
+
 /**
  * Async notification about clocksource changes
  */