All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] Reduce overhead of menu governor
@ 2014-08-06 13:19 Mel Gorman
  2014-08-06 13:19 ` [PATCH 1/4] cpuidle: menu: Use shifts when calculating averages where possible Mel Gorman
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Mel Gorman @ 2014-08-06 13:19 UTC (permalink / raw)
  To: Rafael J Wysocki, Nicolas Pitre; +Cc: Mike Galbraith, LKML, Mel Gorman

The menu_select function is heavy and is very noticable in profiles for
workloads that enter/leave idle state a lot. This primarily happens
for scheduler microbenchmarks. The biggest contibution is the standard
deviation calculations and comparisons but the excessive calls into
the scheduler core do not help.

It would be nice to reduce the number of times nr_iowait is checked to
once per 8 intervals but I was not sure how to measure what the general
impact of such a change could be.

Similiarly I looked at different ways the standard deviation could be
calculated but the standard equivalent calculations potentially overflow.
It could be done as rolling average and rolling deviation but again
it was unclear how that could be evaluated. Tips on how the goodness/badness
of governor changes are evalated would be nice.

In the meantime, here are patches against some  of the obvious stuff.

 drivers/cpuidle/governors/menu.c | 43 +++++++++++++++++++++-------------------
 include/linux/sched.h            |  3 +--
 kernel/sched/core.c              |  7 +++++++
 kernel/sched/proc.c              |  7 -------
 4 files changed, 31 insertions(+), 29 deletions(-)

-- 
1.8.4.5


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/4] cpuidle: menu: Use shifts when calculating averages where possible
  2014-08-06 13:19 [PATCH 0/4] Reduce overhead of menu governor Mel Gorman
@ 2014-08-06 13:19 ` Mel Gorman
  2014-08-06 13:19 ` [PATCH 2/4] cpuidle: menu: Use ktime_to_us instead of reinventing the wheel Mel Gorman
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Mel Gorman @ 2014-08-06 13:19 UTC (permalink / raw)
  To: Rafael J Wysocki, Nicolas Pitre; +Cc: Mike Galbraith, LKML, Mel Gorman

We use do_div even though the divisor will usually be a power-of-two
unless there are unusual outliers. Use shifts where possible

Signed-off-by: Mel Gorman <mgorman@suse.de>
---
 drivers/cpuidle/governors/menu.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index c4f80c1..801b2ee 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -31,7 +31,8 @@
  * The default values do not overflow.
  */
 #define BUCKETS 12
-#define INTERVALS 8
+#define INTERVAL_SHIFT 3
+#define INTERVALS (1UL << INTERVAL_SHIFT)
 #define RESOLUTION 1024
 #define DECAY 8
 #define MAX_INTERESTING 50000
@@ -228,7 +229,10 @@ again:
 				max = value;
 		}
 	}
-	do_div(avg, divisor);
+	if (divisor == INTERVALS)
+		avg >>= INTERVAL_SHIFT;
+	else
+		do_div(avg, divisor);
 
 	/* Then try to determine standard deviation */
 	stddev = 0;
@@ -239,7 +243,11 @@ again:
 			stddev += diff * diff;
 		}
 	}
-	do_div(stddev, divisor);
+	if (divisor == INTERVALS)
+		stddev >>= INTERVAL_SHIFT;
+	else
+		do_div(stddev, divisor);
+
 	/*
 	 * The typical interval is obtained when standard deviation is small
 	 * or standard deviation is small compared to the average interval.
-- 
1.8.4.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/4] cpuidle: menu: Use ktime_to_us instead of reinventing the wheel
  2014-08-06 13:19 [PATCH 0/4] Reduce overhead of menu governor Mel Gorman
  2014-08-06 13:19 ` [PATCH 1/4] cpuidle: menu: Use shifts when calculating averages where possible Mel Gorman
@ 2014-08-06 13:19 ` Mel Gorman
  2014-08-06 14:17   ` Daniel Lezcano
  2014-08-06 13:19 ` [PATCH 3/4] cpuidle: menu: Call nr_iowait_cpu less times Mel Gorman
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 7+ messages in thread
From: Mel Gorman @ 2014-08-06 13:19 UTC (permalink / raw)
  To: Rafael J Wysocki, Nicolas Pitre; +Cc: Mike Galbraith, LKML, Mel Gorman

The ktime_to_us implementation is slightly better than the one implemented
in menu.c. Use it

Signed-off-by: Mel Gorman <mgorman@suse.de>
---
 drivers/cpuidle/governors/menu.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 801b2ee..373278a 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -297,7 +297,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 	int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
 	int i;
 	unsigned int interactivity_req;
-	struct timespec t;
 
 	if (data->needs_update) {
 		menu_update(drv, dev);
@@ -311,9 +310,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 		return 0;
 
 	/* determine the expected residency time, round up */
-	t = ktime_to_timespec(tick_nohz_get_sleep_length());
-	data->next_timer_us =
-		t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC;
+	data->next_timer_us = ktime_to_us(tick_nohz_get_sleep_length());
 
 
 	data->bucket = which_bucket(data->next_timer_us);
-- 
1.8.4.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/4] cpuidle: menu: Call nr_iowait_cpu less times
  2014-08-06 13:19 [PATCH 0/4] Reduce overhead of menu governor Mel Gorman
  2014-08-06 13:19 ` [PATCH 1/4] cpuidle: menu: Use shifts when calculating averages where possible Mel Gorman
  2014-08-06 13:19 ` [PATCH 2/4] cpuidle: menu: Use ktime_to_us instead of reinventing the wheel Mel Gorman
@ 2014-08-06 13:19 ` Mel Gorman
  2014-08-06 13:19 ` [PATCH 4/4] cpuidle: menu: Lookup CPU runqueues less Mel Gorman
  2014-08-06 19:17 ` [PATCH 0/4] Reduce overhead of menu governor Rafael J. Wysocki
  4 siblings, 0 replies; 7+ messages in thread
From: Mel Gorman @ 2014-08-06 13:19 UTC (permalink / raw)
  To: Rafael J Wysocki, Nicolas Pitre; +Cc: Mike Galbraith, LKML, Mel Gorman

menu_select() via inline functions calls nr_iowait_cpu() twice as much
as necessary.

Signed-off-by: Mel Gorman <mgorman@suse.de>
---
 drivers/cpuidle/governors/menu.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 373278a..90d8109 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -143,7 +143,7 @@ static int get_loadavg(void)
 	return LOAD_INT(this) * 10 + LOAD_FRAC(this) / 10;
 }
 
-static inline int which_bucket(unsigned int duration)
+static inline int which_bucket(unsigned int duration, unsigned long nr_iowaiters)
 {
 	int bucket = 0;
 
@@ -153,7 +153,7 @@ static inline int which_bucket(unsigned int duration)
 	 * This allows us to calculate
 	 * E(duration)|iowait
 	 */
-	if (nr_iowait_cpu(smp_processor_id()))
+	if (nr_iowaiters)
 		bucket = BUCKETS/2;
 
 	if (duration < 10)
@@ -176,7 +176,7 @@ static inline int which_bucket(unsigned int duration)
  * to be, the higher this multiplier, and thus the higher
  * the barrier to go to an expensive C state.
  */
-static inline int performance_multiplier(void)
+static inline int performance_multiplier(unsigned long nr_iowaiters)
 {
 	int mult = 1;
 
@@ -185,7 +185,7 @@ static inline int performance_multiplier(void)
 	mult += 2 * get_loadavg();
 
 	/* for IO wait tasks (per cpu!) we add 5x each */
-	mult += 10 * nr_iowait_cpu(smp_processor_id());
+	mult += 10 * nr_iowaiters;
 
 	return mult;
 }
@@ -297,6 +297,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 	int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
 	int i;
 	unsigned int interactivity_req;
+	unsigned long nr_iowaiters;
 
 	if (data->needs_update) {
 		menu_update(drv, dev);
@@ -312,8 +313,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 	/* determine the expected residency time, round up */
 	data->next_timer_us = ktime_to_us(tick_nohz_get_sleep_length());
 
-
-	data->bucket = which_bucket(data->next_timer_us);
+	nr_iowaiters = nr_iowait_cpu(smp_processor_id());
+	data->bucket = which_bucket(data->next_timer_us, nr_iowaiters);
 
 	/*
 	 * Force the result of multiplication to be 64 bits even if both
@@ -331,7 +332,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 	 * duration / latency ratio. Adjust the latency limit if
 	 * necessary.
 	 */
-	interactivity_req = data->predicted_us / performance_multiplier();
+	interactivity_req = data->predicted_us / performance_multiplier(nr_iowaiters);
 	if (latency_req > interactivity_req)
 		latency_req = interactivity_req;
 
-- 
1.8.4.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/4] cpuidle: menu: Lookup CPU runqueues less
  2014-08-06 13:19 [PATCH 0/4] Reduce overhead of menu governor Mel Gorman
                   ` (2 preceding siblings ...)
  2014-08-06 13:19 ` [PATCH 3/4] cpuidle: menu: Call nr_iowait_cpu less times Mel Gorman
@ 2014-08-06 13:19 ` Mel Gorman
  2014-08-06 19:17 ` [PATCH 0/4] Reduce overhead of menu governor Rafael J. Wysocki
  4 siblings, 0 replies; 7+ messages in thread
From: Mel Gorman @ 2014-08-06 13:19 UTC (permalink / raw)
  To: Rafael J Wysocki, Nicolas Pitre; +Cc: Mike Galbraith, LKML, Mel Gorman

The menu governer makes separate lookups of the CPU runqueue to get
load and number of IO waiters but it can be done with a single lookup.

Signed-off-by: Mel Gorman <mgorman@suse.de>
---
 drivers/cpuidle/governors/menu.c | 17 +++++++----------
 include/linux/sched.h            |  3 +--
 kernel/sched/core.c              |  7 +++++++
 kernel/sched/proc.c              |  7 -------
 4 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 90d8109..fef0225 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -135,12 +135,9 @@ struct menu_device {
 #define LOAD_INT(x) ((x) >> FSHIFT)
 #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
 
-static int get_loadavg(void)
+static inline int get_loadavg(unsigned long load)
 {
-	unsigned long this = this_cpu_load();
-
-
-	return LOAD_INT(this) * 10 + LOAD_FRAC(this) / 10;
+	return LOAD_INT(load) * 10 + LOAD_FRAC(load) / 10;
 }
 
 static inline int which_bucket(unsigned int duration, unsigned long nr_iowaiters)
@@ -176,13 +173,13 @@ static inline int which_bucket(unsigned int duration, unsigned long nr_iowaiters
  * to be, the higher this multiplier, and thus the higher
  * the barrier to go to an expensive C state.
  */
-static inline int performance_multiplier(unsigned long nr_iowaiters)
+static inline int performance_multiplier(unsigned long nr_iowaiters, unsigned long load)
 {
 	int mult = 1;
 
 	/* for higher loadavg, we are more reluctant */
 
-	mult += 2 * get_loadavg();
+	mult += 2 * get_loadavg(load);
 
 	/* for IO wait tasks (per cpu!) we add 5x each */
 	mult += 10 * nr_iowaiters;
@@ -297,7 +294,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 	int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
 	int i;
 	unsigned int interactivity_req;
-	unsigned long nr_iowaiters;
+	unsigned long nr_iowaiters, cpu_load;
 
 	if (data->needs_update) {
 		menu_update(drv, dev);
@@ -313,7 +310,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 	/* determine the expected residency time, round up */
 	data->next_timer_us = ktime_to_us(tick_nohz_get_sleep_length());
 
-	nr_iowaiters = nr_iowait_cpu(smp_processor_id());
+	get_iowait_load(&nr_iowaiters, &cpu_load);
 	data->bucket = which_bucket(data->next_timer_us, nr_iowaiters);
 
 	/*
@@ -332,7 +329,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 	 * duration / latency ratio. Adjust the latency limit if
 	 * necessary.
 	 */
-	interactivity_req = data->predicted_us / performance_multiplier(nr_iowaiters);
+	interactivity_req = data->predicted_us / performance_multiplier(nr_iowaiters, cpu_load);
 	if (latency_req > interactivity_req)
 		latency_req = interactivity_req;
 
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 0376b05..a696d48 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -168,8 +168,7 @@ extern int nr_processes(void);
 extern unsigned long nr_running(void);
 extern unsigned long nr_iowait(void);
 extern unsigned long nr_iowait_cpu(int cpu);
-extern unsigned long this_cpu_load(void);
-
+extern void get_iowait_load(unsigned long *nr_waiters, unsigned long *load);
 
 extern void calc_global_load(unsigned long ticks);
 extern void update_cpu_load_nohz(void);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index bc1638b..cfbbbf3 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -2385,6 +2385,13 @@ unsigned long nr_iowait_cpu(int cpu)
 	return atomic_read(&this->nr_iowait);
 }
 
+void get_iowait_load(unsigned long *nr_waiters, unsigned long *load)
+{
+	struct rq *this = this_rq();
+	*nr_waiters = atomic_read(&this->nr_iowait);
+	*load = this->cpu_load[0];
+}
+
 #ifdef CONFIG_SMP
 
 /*
diff --git a/kernel/sched/proc.c b/kernel/sched/proc.c
index 16f5a30..8ecd552 100644
--- a/kernel/sched/proc.c
+++ b/kernel/sched/proc.c
@@ -8,13 +8,6 @@
 
 #include "sched.h"
 
-unsigned long this_cpu_load(void)
-{
-	struct rq *this = this_rq();
-	return this->cpu_load[0];
-}
-
-
 /*
  * Global load-average calculations
  *
-- 
1.8.4.5


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/4] cpuidle: menu: Use ktime_to_us instead of reinventing the wheel
  2014-08-06 13:19 ` [PATCH 2/4] cpuidle: menu: Use ktime_to_us instead of reinventing the wheel Mel Gorman
@ 2014-08-06 14:17   ` Daniel Lezcano
  0 siblings, 0 replies; 7+ messages in thread
From: Daniel Lezcano @ 2014-08-06 14:17 UTC (permalink / raw)
  To: Mel Gorman, Rafael J Wysocki, Nicolas Pitre; +Cc: Mike Galbraith, LKML

On 08/06/2014 03:19 PM, Mel Gorman wrote:
> The ktime_to_us implementation is slightly better than the one implemented
> in menu.c. Use it
>
> Signed-off-by: Mel Gorman <mgorman@suse.de>

Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>

> ---
>   drivers/cpuidle/governors/menu.c | 5 +----
>   1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
> index 801b2ee..373278a 100644
> --- a/drivers/cpuidle/governors/menu.c
> +++ b/drivers/cpuidle/governors/menu.c
> @@ -297,7 +297,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
>   	int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
>   	int i;
>   	unsigned int interactivity_req;
> -	struct timespec t;
>
>   	if (data->needs_update) {
>   		menu_update(drv, dev);
> @@ -311,9 +310,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
>   		return 0;
>
>   	/* determine the expected residency time, round up */
> -	t = ktime_to_timespec(tick_nohz_get_sleep_length());
> -	data->next_timer_us =
> -		t.tv_sec * USEC_PER_SEC + t.tv_nsec / NSEC_PER_USEC;
> +	data->next_timer_us = ktime_to_us(tick_nohz_get_sleep_length());
>
>
>   	data->bucket = which_bucket(data->next_timer_us);
>


-- 
  <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/4] Reduce overhead of menu governor
  2014-08-06 13:19 [PATCH 0/4] Reduce overhead of menu governor Mel Gorman
                   ` (3 preceding siblings ...)
  2014-08-06 13:19 ` [PATCH 4/4] cpuidle: menu: Lookup CPU runqueues less Mel Gorman
@ 2014-08-06 19:17 ` Rafael J. Wysocki
  4 siblings, 0 replies; 7+ messages in thread
From: Rafael J. Wysocki @ 2014-08-06 19:17 UTC (permalink / raw)
  To: Mel Gorman; +Cc: Rafael J Wysocki, Nicolas Pitre, Mike Galbraith, LKML

On Wednesday, August 06, 2014 02:19:17 PM Mel Gorman wrote:
> The menu_select function is heavy and is very noticable in profiles for
> workloads that enter/leave idle state a lot. This primarily happens
> for scheduler microbenchmarks. The biggest contibution is the standard
> deviation calculations and comparisons but the excessive calls into
> the scheduler core do not help.
> 
> It would be nice to reduce the number of times nr_iowait is checked to
> once per 8 intervals but I was not sure how to measure what the general
> impact of such a change could be.
> 
> Similiarly I looked at different ways the standard deviation could be
> calculated but the standard equivalent calculations potentially overflow.
> It could be done as rolling average and rolling deviation but again
> it was unclear how that could be evaluated. Tips on how the goodness/badness
> of governor changes are evalated would be nice.
> 
> In the meantime, here are patches against some  of the obvious stuff.

They look good, I'm going to apply them.

Rafael


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2014-08-06 18:59 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-06 13:19 [PATCH 0/4] Reduce overhead of menu governor Mel Gorman
2014-08-06 13:19 ` [PATCH 1/4] cpuidle: menu: Use shifts when calculating averages where possible Mel Gorman
2014-08-06 13:19 ` [PATCH 2/4] cpuidle: menu: Use ktime_to_us instead of reinventing the wheel Mel Gorman
2014-08-06 14:17   ` Daniel Lezcano
2014-08-06 13:19 ` [PATCH 3/4] cpuidle: menu: Call nr_iowait_cpu less times Mel Gorman
2014-08-06 13:19 ` [PATCH 4/4] cpuidle: menu: Lookup CPU runqueues less Mel Gorman
2014-08-06 19:17 ` [PATCH 0/4] Reduce overhead of menu governor Rafael J. Wysocki

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.