* [PATCH] [RFC] ondemand governor: dynamic cpufreq scaling with different CPUs
@ 2011-07-26 17:22 Yung, Winson W
2011-07-29 16:52 ` Venkatesh Pallipadi
0 siblings, 1 reply; 6+ messages in thread
From: Yung, Winson W @ 2011-07-26 17:22 UTC (permalink / raw)
To: linux-kernel; +Cc: venki, Van De Ven, Arjan
with using delayed work queue inside ondemand governor, I came to
realize that there are certain scenarios the governor may not
re-adjust cpu frequency swiftly for some duration. Here is a
brief description of the problem:
Currently when ondemand governor starts, it will create kthreads
for each CPU, something like kondemand/0, kondemand/1 and so on.
I found from ftrace that kondemand/0 is the only kthread that
handles all the CPU frequency dynamic cpu frequency scaling, other
kthread such as kondemand/1 is never used. I also confirmed this
by debugging through the kernel code.
So if there is no timer fired on CPU-0 (i.e. CPU-0 in C6), hence
no deferrable timers will ever fired by kondemand/0 to sample all
CPU workload. Since it is the only kthread doing the CPU freqency
scaling for all CPUs, it is possible to enter in the situation
where CPU frequency scaling will stop working for some duration
until CPU-0 becomes not idle again.
Signed-off-by: Hari K Kanigeri <hari.kkanigeri@intel.com>
---
drivers/cpufreq/cpufreq_ondemand.c | 93 +++++++++++++++++++++++++++++++----
include/linux/cpufreq.h | 3 +
2 files changed, 85 insertions(+), 11 deletions(-)
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 891360e..b4f4f9d 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -541,6 +541,9 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
static void do_dbs_timer(struct work_struct *work)
{
+ u64 old_time, new_do_dbs_time;
+ u64 saved_last_time;
+
struct cpu_dbs_info_s *dbs_info =
container_of(work, struct cpu_dbs_info_s, work.work);
unsigned int cpu = dbs_info->cpu;
@@ -548,6 +551,41 @@ static void do_dbs_timer(struct work_struct *work)
int delay;
+ new_do_dbs_time = get_jiffies_64();
+
+ /* Save a copy of last_do_dbs_time do_dbs_timer */
+
+ saved_last_time = atomic64_read(
+ &dbs_info->cur_policy->last_do_dbs_time);
+
+ /* If the last time do_dbs_timer ran is less than */
+ /* 'delay' delta from current time, one of other */
+ /* CPUs is still handling cpufreq governoring for */
+ /* for all CPUs. */
+
+ if ((new_do_dbs_time - saved_last_time) <
+ dbs_info->cur_policy->last_delay) {
+
+ /* If do_dbs_time ran not long ago */
+ /* (delta is less than last_delay) */
+ /* then bail out because there is */
+ /* no need to run so frequently. */
+ goto do_exit;
+ }
+
+ old_time = atomic64_cmpxchg(&dbs_info->cur_policy->last_do_dbs_time,
+ saved_last_time, new_do_dbs_time);
+
+ /* If old_time is not equal to saved_last_time, */
+ /* it means another CPU is calling do_dbs_time. */
+
+ if (old_time != saved_last_time)
+ goto do_exit;
+
+ /* Switch cpu saved in the policy */
+ if (dbs_info->cur_policy->cpu != cpu)
+ dbs_info->cur_policy->cpu = cpu;
+
mutex_lock(&dbs_info->timer_mutex);
/* Common NORMAL_SAMPLE setup */
@@ -559,6 +597,7 @@ static void do_dbs_timer(struct work_struct *work)
/* Setup timer for SUB_SAMPLE */
dbs_info->sample_type = DBS_SUB_SAMPLE;
delay = dbs_info->freq_hi_jiffies;
+ dbs_info->cur_policy->last_delay = delay;
} else {
/* We want all CPUs to do sampling nearly on
* same jiffy
@@ -566,14 +605,18 @@ static void do_dbs_timer(struct work_struct *work)
delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate
* dbs_info->rate_mult);
- if (num_online_cpus() > 1)
+ if (num_online_cpus() > 1) {
delay -= jiffies % delay;
+ dbs_info->cur_policy->last_delay = delay;
+ }
}
} else {
__cpufreq_driver_target(dbs_info->cur_policy,
dbs_info->freq_lo, CPUFREQ_RELATION_H);
delay = dbs_info->freq_lo_jiffies;
+ dbs_info->cur_policy->last_delay = delay;
}
+do_exit:
schedule_delayed_work_on(cpu, &dbs_info->work, delay);
mutex_unlock(&dbs_info->timer_mutex);
}
@@ -648,10 +691,12 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
j_dbs_info->prev_cpu_nice =
kstat_cpu(j).cpustat.nice;
}
+
+ j_dbs_info->cpu = j;
+ j_dbs_info->rate_mult = 1;
+ ondemand_powersave_bias_init_cpu(j);
}
- this_dbs_info->cpu = cpu;
- this_dbs_info->rate_mult = 1;
- ondemand_powersave_bias_init_cpu(cpu);
+
/*
* Start the timerschedule work, when this governor
* is used for first time
@@ -680,32 +725,58 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
}
mutex_unlock(&dbs_mutex);
- mutex_init(&this_dbs_info->timer_mutex);
- dbs_timer_init(this_dbs_info);
+ for_each_cpu(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
+ mutex_init(&j_dbs_info->timer_mutex);
+ dbs_timer_init(j_dbs_info);
+ }
break;
case CPUFREQ_GOV_STOP:
- dbs_timer_exit(this_dbs_info);
+ for_each_cpu(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
+ dbs_timer_exit(j_dbs_info);
+ }
mutex_lock(&dbs_mutex);
- mutex_destroy(&this_dbs_info->timer_mutex);
+
+ for_each_cpu(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
+ mutex_destroy(&j_dbs_info->timer_mutex);
+ }
+
dbs_enable--;
mutex_unlock(&dbs_mutex);
if (!dbs_enable)
sysfs_remove_group(cpufreq_global_kobject,
&dbs_attr_group);
-
break;
case CPUFREQ_GOV_LIMITS:
- mutex_lock(&this_dbs_info->timer_mutex);
+ /* Since ondemand governor is no longer running on the */
+ /* same CPU anymore,need to mutex_lock all timer_mutex */
+ /* before calling __cpufreq_driver_target. */
+ for_each_cpu(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
+ mutex_lock(&j_dbs_info->timer_mutex);
+ }
+
if (policy->max < this_dbs_info->cur_policy->cur)
__cpufreq_driver_target(this_dbs_info->cur_policy,
policy->max, CPUFREQ_RELATION_H);
else if (policy->min > this_dbs_info->cur_policy->cur)
__cpufreq_driver_target(this_dbs_info->cur_policy,
policy->min, CPUFREQ_RELATION_L);
- mutex_unlock(&this_dbs_info->timer_mutex);
+
+ for_each_cpu(j, policy->cpus) {
+ struct cpu_dbs_info_s *j_dbs_info;
+ j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
+ mutex_unlock(&j_dbs_info->timer_mutex);
+ }
break;
}
return 0;
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 11be48e..2295a35 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -106,6 +106,9 @@ struct cpufreq_policy {
struct kobject kobj;
struct completion kobj_unregister;
+
+ atomic64_t last_do_dbs_tim;
+ int last_delay;
};
#define CPUFREQ_ADJUST (0)
--
1.7.1
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] [RFC] ondemand governor: dynamic cpufreq scaling with different CPUs
2011-07-26 17:22 [PATCH] [RFC] ondemand governor: dynamic cpufreq scaling with different CPUs Yung, Winson W
@ 2011-07-29 16:52 ` Venkatesh Pallipadi
2011-08-01 1:08 ` Yung, Winson W
0 siblings, 1 reply; 6+ messages in thread
From: Venkatesh Pallipadi @ 2011-07-29 16:52 UTC (permalink / raw)
To: Yung, Winson W; +Cc: linux-kernel, Van De Ven, Arjan
On Tue, Jul 26, 2011 at 10:22 AM, Yung, Winson W
<winson.w.yung@intel.com> wrote:
>
> with using delayed work queue inside ondemand governor, I came to
> realize that there are certain scenarios the governor may not
> re-adjust cpu frequency swiftly for some duration. Here is a
> brief description of the problem:
>
> Currently when ondemand governor starts, it will create kthreads
> for each CPU, something like kondemand/0, kondemand/1 and so on.
> I found from ftrace that kondemand/0 is the only kthread that
> handles all the CPU frequency dynamic cpu frequency scaling, other
> kthread such as kondemand/1 is never used. I also confirmed this
> by debugging through the kernel code.
This is not universally true. You are seeing this because the platform
is using SOFTWARE_COORDINATION mode for P-states. Most optimal in
terms of overhead is HARDWARE_COORDINATION mode, and this used to be
the recommended mode for platforms. And HW coordination is the
(atleast used to be) the more common mode across platforms.
Not sure whether this platform has SW coordination as a feature or bug?
>
> So if there is no timer fired on CPU-0 (i.e. CPU-0 in C6), hence
> no deferrable timers will ever fired by kondemand/0 to sample all
> CPU workload. Since it is the only kthread doing the CPU freqency
> scaling for all CPUs, it is possible to enter in the situation
> where CPU frequency scaling will stop working for some duration
> until CPU-0 becomes not idle again.
Yes. This will be a problem.
But, I am not sure whether the added complexity with the change below
to support the sub-optimal mode here. But, if we have a huge number of
platforms that are using software coordination, then there may not be
much of a choice here :(
>
> Signed-off-by: Hari K Kanigeri <hari.kkanigeri@intel.com>
> ---
> drivers/cpufreq/cpufreq_ondemand.c | 93 +++++++++++++++++++++++++++++++----
> include/linux/cpufreq.h | 3 +
> 2 files changed, 85 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
> index 891360e..b4f4f9d 100644
> --- a/drivers/cpufreq/cpufreq_ondemand.c
> +++ b/drivers/cpufreq/cpufreq_ondemand.c
> @@ -541,6 +541,9 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
>
> static void do_dbs_timer(struct work_struct *work)
> {
> + u64 old_time, new_do_dbs_time;
> + u64 saved_last_time;
> +
> struct cpu_dbs_info_s *dbs_info =
> container_of(work, struct cpu_dbs_info_s, work.work);
> unsigned int cpu = dbs_info->cpu;
> @@ -548,6 +551,41 @@ static void do_dbs_timer(struct work_struct *work)
>
> int delay;
>
> + new_do_dbs_time = get_jiffies_64();
> +
> + /* Save a copy of last_do_dbs_time do_dbs_timer */
> +
> + saved_last_time = atomic64_read(
> + &dbs_info->cur_policy->last_do_dbs_time);
> +
> + /* If the last time do_dbs_timer ran is less than */
> + /* 'delay' delta from current time, one of other */
> + /* CPUs is still handling cpufreq governoring for */
> + /* for all CPUs. */
> +
> + if ((new_do_dbs_time - saved_last_time) <
> + dbs_info->cur_policy->last_delay) {
> +
> + /* If do_dbs_time ran not long ago */
> + /* (delta is less than last_delay) */
> + /* then bail out because there is */
> + /* no need to run so frequently. */
> + goto do_exit;
> + }
> +
> + old_time = atomic64_cmpxchg(&dbs_info->cur_policy->last_do_dbs_time,
> + saved_last_time, new_do_dbs_time);
> +
> + /* If old_time is not equal to saved_last_time, */
> + /* it means another CPU is calling do_dbs_time. */
> +
> + if (old_time != saved_last_time)
> + goto do_exit;
> +
> + /* Switch cpu saved in the policy */
> + if (dbs_info->cur_policy->cpu != cpu)
> + dbs_info->cur_policy->cpu = cpu;
> +
This seems somewhat complicated way to do this.. One simpler way could
be to have a new atomic element in dbs_info that stores the current
CPU among policy->cpus doing dbs_timers. By default it will be
policy->cpu and when it goes idle it changes the variable to -1, so
that any other CPU can nominate itself (using atomic cmpxchg). If it
is still -1, then policy->cpu does the check anyway.
> mutex_lock(&dbs_info->timer_mutex);
>
> /* Common NORMAL_SAMPLE setup */
> @@ -559,6 +597,7 @@ static void do_dbs_timer(struct work_struct *work)
> /* Setup timer for SUB_SAMPLE */
> dbs_info->sample_type = DBS_SUB_SAMPLE;
> delay = dbs_info->freq_hi_jiffies;
> + dbs_info->cur_policy->last_delay = delay;
> } else {
> /* We want all CPUs to do sampling nearly on
> * same jiffy
> @@ -566,14 +605,18 @@ static void do_dbs_timer(struct work_struct *work)
> delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate
> * dbs_info->rate_mult);
>
> - if (num_online_cpus() > 1)
> + if (num_online_cpus() > 1) {
> delay -= jiffies % delay;
> + dbs_info->cur_policy->last_delay = delay;
> + }
> }
> } else {
> __cpufreq_driver_target(dbs_info->cur_policy,
> dbs_info->freq_lo, CPUFREQ_RELATION_H);
> delay = dbs_info->freq_lo_jiffies;
> + dbs_info->cur_policy->last_delay = delay;
> }
> +do_exit:
> schedule_delayed_work_on(cpu, &dbs_info->work, delay);
> mutex_unlock(&dbs_info->timer_mutex);
> }
> @@ -648,10 +691,12 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
> j_dbs_info->prev_cpu_nice =
> kstat_cpu(j).cpustat.nice;
> }
> +
> + j_dbs_info->cpu = j;
> + j_dbs_info->rate_mult = 1;
> + ondemand_powersave_bias_init_cpu(j);
> }
> - this_dbs_info->cpu = cpu;
> - this_dbs_info->rate_mult = 1;
> - ondemand_powersave_bias_init_cpu(cpu);
> +
> /*
> * Start the timerschedule work, when this governor
> * is used for first time
> @@ -680,32 +725,58 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
> }
> mutex_unlock(&dbs_mutex);
>
> - mutex_init(&this_dbs_info->timer_mutex);
> - dbs_timer_init(this_dbs_info);
> + for_each_cpu(j, policy->cpus) {
> + struct cpu_dbs_info_s *j_dbs_info;
> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
> + mutex_init(&j_dbs_info->timer_mutex);
> + dbs_timer_init(j_dbs_info);
> + }
> break;
>
> case CPUFREQ_GOV_STOP:
> - dbs_timer_exit(this_dbs_info);
> + for_each_cpu(j, policy->cpus) {
> + struct cpu_dbs_info_s *j_dbs_info;
> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
> + dbs_timer_exit(j_dbs_info);
> + }
>
> mutex_lock(&dbs_mutex);
> - mutex_destroy(&this_dbs_info->timer_mutex);
> +
> + for_each_cpu(j, policy->cpus) {
> + struct cpu_dbs_info_s *j_dbs_info;
> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
> + mutex_destroy(&j_dbs_info->timer_mutex);
> + }
> +
> dbs_enable--;
> mutex_unlock(&dbs_mutex);
> if (!dbs_enable)
> sysfs_remove_group(cpufreq_global_kobject,
> &dbs_attr_group);
> -
> break;
>
> case CPUFREQ_GOV_LIMITS:
> - mutex_lock(&this_dbs_info->timer_mutex);
> + /* Since ondemand governor is no longer running on the */
> + /* same CPU anymore,need to mutex_lock all timer_mutex */
> + /* before calling __cpufreq_driver_target. */
> + for_each_cpu(j, policy->cpus) {
> + struct cpu_dbs_info_s *j_dbs_info;
> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
> + mutex_lock(&j_dbs_info->timer_mutex);
Not sure why we need a lock on all policy->cpus mutexes here. Could as
well be all policy->cpus use policy->cpu's mutex. No?
> + }
> +
> if (policy->max < this_dbs_info->cur_policy->cur)
> __cpufreq_driver_target(this_dbs_info->cur_policy,
> policy->max, CPUFREQ_RELATION_H);
> else if (policy->min > this_dbs_info->cur_policy->cur)
> __cpufreq_driver_target(this_dbs_info->cur_policy,
> policy->min, CPUFREQ_RELATION_L);
> - mutex_unlock(&this_dbs_info->timer_mutex);
> +
> + for_each_cpu(j, policy->cpus) {
> + struct cpu_dbs_info_s *j_dbs_info;
> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
> + mutex_unlock(&j_dbs_info->timer_mutex);
> + }
> break;
> }
> return 0;
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index 11be48e..2295a35 100644
> --- a/include/linux/cpufreq.h
> +++ b/include/linux/cpufreq.h
> @@ -106,6 +106,9 @@ struct cpufreq_policy {
>
> struct kobject kobj;
> struct completion kobj_unregister;
> +
> + atomic64_t last_do_dbs_tim;
> + int last_delay;
> };
>
> #define CPUFREQ_ADJUST (0)
> --
> 1.7.1
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* RE: [PATCH] [RFC] ondemand governor: dynamic cpufreq scaling with different CPUs
2011-07-29 16:52 ` Venkatesh Pallipadi
@ 2011-08-01 1:08 ` Yung, Winson W
2011-08-01 14:51 ` Len Brown
2011-08-10 17:05 ` Venki Pallipadi
0 siblings, 2 replies; 6+ messages in thread
From: Yung, Winson W @ 2011-08-01 1:08 UTC (permalink / raw)
To: Venkatesh Pallipadi; +Cc: linux-kernel, Van De Ven, Arjan, Kanigeri, Hari K
Thanks Venki for the comment, here is my thoughts on the change:
Correct me if I am wrong, it is probably true on PC that hw (bios) coordination mode for p-state is better over sw coordination mode, however on smartphone/tablet devices, there is no BIOS, so sw coordination mode is the only choice.
I am not sure I can simplify the change inside do_dbs_timer per your comment, dbs_info is per cpu, how are other CPUs suppose to see cpu change without getting that CPU's dbs_info? That's why I store the cpu and dbs_timer interval info inside policy which shared by all CPUs.
Having said that, how to handle cpu hotplug is something that my patch didn't do. If I offline one cpu and then online it again, it will no longer participate do_dbs_timer call. The code to add it back to dbs_timer cpus list and use the same shared policy is somewhat complicated. I am hoping to get some better idea on this from the community.
BTW, this delayed work queue problem should exist in both ondemand and conservative governors.
/Winson
>-----Original Message-----
>From: Venkatesh Pallipadi [mailto:venki@google.com]
>Sent: Friday, July 29, 2011 9:53 AM
>To: Yung, Winson W
>Cc: linux-kernel@vger.kernel.org; Van De Ven, Arjan
>Subject: Re: [PATCH] [RFC] ondemand governor: dynamic cpufreq scaling
>with different CPUs
>
>On Tue, Jul 26, 2011 at 10:22 AM, Yung, Winson W
><winson.w.yung@intel.com> wrote:
>>
>> with using delayed work queue inside ondemand governor, I came to
>> realize that there are certain scenarios the governor may not
>> re-adjust cpu frequency swiftly for some duration. Here is a
>> brief description of the problem:
>>
>> Currently when ondemand governor starts, it will create kthreads
>> for each CPU, something like kondemand/0, kondemand/1 and so on.
>> I found from ftrace that kondemand/0 is the only kthread that
>> handles all the CPU frequency dynamic cpu frequency scaling, other
>> kthread such as kondemand/1 is never used. I also confirmed this
>> by debugging through the kernel code.
>
>This is not universally true. You are seeing this because the platform
>is using SOFTWARE_COORDINATION mode for P-states. Most optimal in
>terms of overhead is HARDWARE_COORDINATION mode, and this used to be
>the recommended mode for platforms. And HW coordination is the
>(atleast used to be) the more common mode across platforms.
>Not sure whether this platform has SW coordination as a feature or bug?
>
>>
>> So if there is no timer fired on CPU-0 (i.e. CPU-0 in C6), hence
>> no deferrable timers will ever fired by kondemand/0 to sample all
>> CPU workload. Since it is the only kthread doing the CPU freqency
>> scaling for all CPUs, it is possible to enter in the situation
>> where CPU frequency scaling will stop working for some duration
>> until CPU-0 becomes not idle again.
>
>Yes. This will be a problem.
>But, I am not sure whether the added complexity with the change below
>to support the sub-optimal mode here. But, if we have a huge number of
>platforms that are using software coordination, then there may not be
>much of a choice here :(
>
>>
>> Signed-off-by: Hari K Kanigeri <hari.kkanigeri@intel.com>
>> ---
>> drivers/cpufreq/cpufreq_ondemand.c | 93
>+++++++++++++++++++++++++++++++----
>> include/linux/cpufreq.h | 3 +
>> 2 files changed, 85 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/cpufreq/cpufreq_ondemand.c
>b/drivers/cpufreq/cpufreq_ondemand.c
>> index 891360e..b4f4f9d 100644
>> --- a/drivers/cpufreq/cpufreq_ondemand.c
>> +++ b/drivers/cpufreq/cpufreq_ondemand.c
>> @@ -541,6 +541,9 @@ static void dbs_check_cpu(struct cpu_dbs_info_s
>*this_dbs_info)
>>
>> static void do_dbs_timer(struct work_struct *work)
>> {
>> + u64 old_time, new_do_dbs_time;
>> + u64 saved_last_time;
>> +
>> struct cpu_dbs_info_s *dbs_info =
>> container_of(work, struct cpu_dbs_info_s, work.work);
>> unsigned int cpu = dbs_info->cpu;
>> @@ -548,6 +551,41 @@ static void do_dbs_timer(struct work_struct *work)
>>
>> int delay;
>>
>> + new_do_dbs_time = get_jiffies_64();
>> +
>> + /* Save a copy of last_do_dbs_time do_dbs_timer */
>> +
>> + saved_last_time = atomic64_read(
>> + &dbs_info->cur_policy->last_do_dbs_time);
>> +
>> + /* If the last time do_dbs_timer ran is less than */
>> + /* 'delay' delta from current time, one of other */
>> + /* CPUs is still handling cpufreq governoring for */
>> + /* for all CPUs. */
>> +
>> + if ((new_do_dbs_time - saved_last_time) <
>> + dbs_info->cur_policy->last_delay) {
>> +
>> + /* If do_dbs_time ran not long ago */
>> + /* (delta is less than last_delay) */
>> + /* then bail out because there is */
>> + /* no need to run so frequently. */
>> + goto do_exit;
>> + }
>> +
>> + old_time = atomic64_cmpxchg(&dbs_info->cur_policy-
>>last_do_dbs_time,
>> + saved_last_time,
>new_do_dbs_time);
>> +
>> + /* If old_time is not equal to saved_last_time, */
>> + /* it means another CPU is calling do_dbs_time. */
>> +
>> + if (old_time != saved_last_time)
>> + goto do_exit;
>> +
>> + /* Switch cpu saved in the policy */
>> + if (dbs_info->cur_policy->cpu != cpu)
>> + dbs_info->cur_policy->cpu = cpu;
>> +
>
>
>This seems somewhat complicated way to do this.. One simpler way could
>be to have a new atomic element in dbs_info that stores the current
>CPU among policy->cpus doing dbs_timers. By default it will be
>policy->cpu and when it goes idle it changes the variable to -1, so
>that any other CPU can nominate itself (using atomic cmpxchg). If it
>is still -1, then policy->cpu does the check anyway.
>
>> mutex_lock(&dbs_info->timer_mutex);
>>
>> /* Common NORMAL_SAMPLE setup */
>> @@ -559,6 +597,7 @@ static void do_dbs_timer(struct work_struct *work)
>> /* Setup timer for SUB_SAMPLE */
>> dbs_info->sample_type = DBS_SUB_SAMPLE;
>> delay = dbs_info->freq_hi_jiffies;
>> + dbs_info->cur_policy->last_delay = delay;
>> } else {
>> /* We want all CPUs to do sampling nearly on
>> * same jiffy
>> @@ -566,14 +605,18 @@ static void do_dbs_timer(struct work_struct
>*work)
>> delay =
>usecs_to_jiffies(dbs_tuners_ins.sampling_rate
>> * dbs_info->rate_mult);
>>
>> - if (num_online_cpus() > 1)
>> + if (num_online_cpus() > 1) {
>> delay -= jiffies % delay;
>> + dbs_info->cur_policy->last_delay =
>delay;
>> + }
>> }
>> } else {
>> __cpufreq_driver_target(dbs_info->cur_policy,
>> dbs_info->freq_lo, CPUFREQ_RELATION_H);
>> delay = dbs_info->freq_lo_jiffies;
>> + dbs_info->cur_policy->last_delay = delay;
>> }
>> +do_exit:
>> schedule_delayed_work_on(cpu, &dbs_info->work, delay);
>> mutex_unlock(&dbs_info->timer_mutex);
>> }
>> @@ -648,10 +691,12 @@ static int cpufreq_governor_dbs(struct
>cpufreq_policy *policy,
>> j_dbs_info->prev_cpu_nice =
>> kstat_cpu(j).cpustat.ni
>ce;
>> }
>> +
>> + j_dbs_info->cpu = j;
>> + j_dbs_info->rate_mult = 1;
>> + ondemand_powersave_bias_init_cpu(j);
>> }
>> - this_dbs_info->cpu = cpu;
>> - this_dbs_info->rate_mult = 1;
>> - ondemand_powersave_bias_init_cpu(cpu);
>> +
>> /*
>> * Start the timerschedule work, when this governor
>> * is used for first time
>> @@ -680,32 +725,58 @@ static int cpufreq_governor_dbs(struct
>cpufreq_policy *policy,
>> }
>> mutex_unlock(&dbs_mutex);
>>
>> - mutex_init(&this_dbs_info->timer_mutex);
>> - dbs_timer_init(this_dbs_info);
>> + for_each_cpu(j, policy->cpus) {
>> + struct cpu_dbs_info_s *j_dbs_info;
>> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
>> + mutex_init(&j_dbs_info->timer_mutex);
>> + dbs_timer_init(j_dbs_info);
>> + }
>> break;
>>
>> case CPUFREQ_GOV_STOP:
>> - dbs_timer_exit(this_dbs_info);
>> + for_each_cpu(j, policy->cpus) {
>> + struct cpu_dbs_info_s *j_dbs_info;
>> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
>> + dbs_timer_exit(j_dbs_info);
>> + }
>>
>> mutex_lock(&dbs_mutex);
>> - mutex_destroy(&this_dbs_info->timer_mutex);
>> +
>> + for_each_cpu(j, policy->cpus) {
>> + struct cpu_dbs_info_s *j_dbs_info;
>> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
>> + mutex_destroy(&j_dbs_info->timer_mutex);
>> + }
>> +
>> dbs_enable--;
>> mutex_unlock(&dbs_mutex);
>> if (!dbs_enable)
>> sysfs_remove_group(cpufreq_global_kobject,
>> &dbs_attr_group);
>> -
>> break;
>>
>> case CPUFREQ_GOV_LIMITS:
>> - mutex_lock(&this_dbs_info->timer_mutex);
>> + /* Since ondemand governor is no longer running on the
>*/
>> + /* same CPU anymore,need to mutex_lock all timer_mutex
>*/
>> + /* before calling __cpufreq_driver_target. */
>> + for_each_cpu(j, policy->cpus) {
>> + struct cpu_dbs_info_s *j_dbs_info;
>> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
>> + mutex_lock(&j_dbs_info->timer_mutex);
>
>Not sure why we need a lock on all policy->cpus mutexes here. Could as
>well be all policy->cpus use policy->cpu's mutex. No?
>
>
>> + }
>> +
>> if (policy->max < this_dbs_info->cur_policy->cur)
>> __cpufreq_driver_target(this_dbs_info-
>>cur_policy,
>> policy->max, CPUFREQ_RELATION_H);
>> else if (policy->min > this_dbs_info->cur_policy->cur)
>> __cpufreq_driver_target(this_dbs_info-
>>cur_policy,
>> policy->min, CPUFREQ_RELATION_L);
>> - mutex_unlock(&this_dbs_info->timer_mutex);
>> +
>> + for_each_cpu(j, policy->cpus) {
>> + struct cpu_dbs_info_s *j_dbs_info;
>> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
>> + mutex_unlock(&j_dbs_info->timer_mutex);
>> + }
>> break;
>> }
>> return 0;
>> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
>> index 11be48e..2295a35 100644
>> --- a/include/linux/cpufreq.h
>> +++ b/include/linux/cpufreq.h
>> @@ -106,6 +106,9 @@ struct cpufreq_policy {
>>
>> struct kobject kobj;
>> struct completion kobj_unregister;
>> +
>> + atomic64_t last_do_dbs_tim;
>> + int last_delay;
>> };
>>
>> #define CPUFREQ_ADJUST (0)
>> --
>> 1.7.1
>>
^ permalink raw reply [flat|nested] 6+ messages in thread
* RE: [PATCH] [RFC] ondemand governor: dynamic cpufreq scaling with different CPUs
2011-08-01 1:08 ` Yung, Winson W
@ 2011-08-01 14:51 ` Len Brown
2011-08-10 16:59 ` Venki Pallipadi
2011-08-10 17:05 ` Venki Pallipadi
1 sibling, 1 reply; 6+ messages in thread
From: Len Brown @ 2011-08-01 14:51 UTC (permalink / raw)
To: Yung, Winson W
Cc: Venkatesh Pallipadi, linux-kernel, Van De Ven, Arjan, Kanigeri, Hari K
Re: software vs hardware coordination
Speaking for Intel, everything we make, from hand-sets to supercomputers
supports hardware coorination.
Think about it -- if we did not, then we would not be able
to support a legacy OS that doesn't know how to do SW coordination.
HW coordiation is the simplest thing for the SW because
SW doesn't have to know anything at all about topology constraints.
It is also the simplest thing for the BIOS, which doesn't have
to correctly describe topology.
Yes, there is an MSR bit that the BIOS can flip to disable
HW coordination. 90% of the time that bit is set it is a BIOS bug.
eg. the bit is set, but the BIOS fails to properly set up the
ACPI tables to properly enable SW coordination, resulting
in a system with really strange performance issues.
Indeed, I proposed before, and I will propose again that
the underlying ACPI _PSD support behind SW coordination
be completely removed from Linux.
Venki,
I recall that you mentioned one platform that depends on it --
and I'd like to understand that issue and address it with a quirk
rather than expose all systems to BIOS bugs due to bogus _PSD support.
Winston,
Your system is running in SW coordination mode?
What do you see if you run with the patch below?
I'd be intersted to see the output from adpidump for your system.
thanks,
-Len Brown
Intel Open Source Technology Center
---
diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h
index 552637b..d081595 100644
--- a/include/acpi/pdc_intel.h
+++ b/include/acpi/pdc_intel.h
@@ -22,7 +22,6 @@
#define ACPI_PDC_EST_CAPABILITY_SWSMP (ACPI_PDC_SMP_C1PT | \
ACPI_PDC_C_C1_HALT | \
- ACPI_PDC_SMP_P_SWCOORD | \
ACPI_PDC_SMP_P_HWCOORD | \
ACPI_PDC_P_FFH)
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] [RFC] ondemand governor: dynamic cpufreq scaling with different CPUs
2011-08-01 14:51 ` Len Brown
@ 2011-08-10 16:59 ` Venki Pallipadi
0 siblings, 0 replies; 6+ messages in thread
From: Venki Pallipadi @ 2011-08-10 16:59 UTC (permalink / raw)
To: Len Brown
Cc: Yung, Winson W, linux-kernel, Van De Ven, Arjan, Kanigeri, Hari K
On Mon, Aug 1, 2011 at 7:51 AM, Len Brown <lenb@kernel.org> wrote:
> Re: software vs hardware coordination
>
> Speaking for Intel, everything we make, from hand-sets to supercomputers
> supports hardware coorination.
>
> Think about it -- if we did not, then we would not be able
> to support a legacy OS that doesn't know how to do SW coordination.
>
> HW coordiation is the simplest thing for the SW because
> SW doesn't have to know anything at all about topology constraints.
> It is also the simplest thing for the BIOS, which doesn't have
> to correctly describe topology.
>
> Yes, there is an MSR bit that the BIOS can flip to disable
> HW coordination. 90% of the time that bit is set it is a BIOS bug.
> eg. the bit is set, but the BIOS fails to properly set up the
> ACPI tables to properly enable SW coordination, resulting
> in a system with really strange performance issues.
>
> Indeed, I proposed before, and I will propose again that
> the underlying ACPI _PSD support behind SW coordination
> be completely removed from Linux.
>
> Venki,
> I recall that you mentioned one platform that depends on it --
> and I'd like to understand that issue and address it with a quirk
> rather than expose all systems to BIOS bugs due to bogus _PSD support.
>
Agree. Addressing this as a quirk would be fine. The processor that
needs it is E74xx series, IIRC.
Thanks,
Venki
> Winston,
> Your system is running in SW coordination mode?
> What do you see if you run with the patch below?
> I'd be intersted to see the output from adpidump for your system.
>
> thanks,
> -Len Brown
> Intel Open Source Technology Center
>
> ---
> diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h
> index 552637b..d081595 100644
> --- a/include/acpi/pdc_intel.h
> +++ b/include/acpi/pdc_intel.h
> @@ -22,7 +22,6 @@
>
> #define ACPI_PDC_EST_CAPABILITY_SWSMP (ACPI_PDC_SMP_C1PT | \
> ACPI_PDC_C_C1_HALT | \
> - ACPI_PDC_SMP_P_SWCOORD | \
> ACPI_PDC_SMP_P_HWCOORD | \
> ACPI_PDC_P_FFH)
>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] [RFC] ondemand governor: dynamic cpufreq scaling with different CPUs
2011-08-01 1:08 ` Yung, Winson W
2011-08-01 14:51 ` Len Brown
@ 2011-08-10 17:05 ` Venki Pallipadi
1 sibling, 0 replies; 6+ messages in thread
From: Venki Pallipadi @ 2011-08-10 17:05 UTC (permalink / raw)
To: Yung, Winson W; +Cc: linux-kernel, Van De Ven, Arjan, Kanigeri, Hari K
On Sun, Jul 31, 2011 at 6:08 PM, Yung, Winson W <winson.w.yung@intel.com> wrote:
> Thanks Venki for the comment, here is my thoughts on the change:
>
> Correct me if I am wrong, it is probably true on PC that hw (bios) coordination mode for p-state is better over sw coordination mode, however on smartphone/tablet devices, there is no BIOS, so sw coordination mode is the only choice.
Hi Winson,
On all chips supporting hardware coordination that I know of, it is
done in hardware and not in BIOS. And there is a toggle switch that
lets BIOS/software choose either hardware or software coordination.
> I am not sure I can simplify the change inside do_dbs_timer per your comment, dbs_info is per cpu, how are other CPUs suppose to see cpu change without getting that CPU's dbs_info? That's why I store the cpu and dbs_timer interval info inside policy which shared by all CPUs.
They know about the leader (policy->cpu) and they can access that cpus
percpu data to find out. You can even store the variable in policy
itself.
Thanks,
Venki
>
> Having said that, how to handle cpu hotplug is something that my patch didn't do. If I offline one cpu and then online it again, it will no longer participate do_dbs_timer call. The code to add it back to dbs_timer cpus list and use the same shared policy is somewhat complicated. I am hoping to get some better idea on this from the community.
>
> BTW, this delayed work queue problem should exist in both ondemand and conservative governors.
>
> /Winson
>
>>-----Original Message-----
>>From: Venkatesh Pallipadi [mailto:venki@google.com]
>>Sent: Friday, July 29, 2011 9:53 AM
>>To: Yung, Winson W
>>Cc: linux-kernel@vger.kernel.org; Van De Ven, Arjan
>>Subject: Re: [PATCH] [RFC] ondemand governor: dynamic cpufreq scaling
>>with different CPUs
>>
>>On Tue, Jul 26, 2011 at 10:22 AM, Yung, Winson W
>><winson.w.yung@intel.com> wrote:
>>>
>>> with using delayed work queue inside ondemand governor, I came to
>>> realize that there are certain scenarios the governor may not
>>> re-adjust cpu frequency swiftly for some duration. Here is a
>>> brief description of the problem:
>>>
>>> Currently when ondemand governor starts, it will create kthreads
>>> for each CPU, something like kondemand/0, kondemand/1 and so on.
>>> I found from ftrace that kondemand/0 is the only kthread that
>>> handles all the CPU frequency dynamic cpu frequency scaling, other
>>> kthread such as kondemand/1 is never used. I also confirmed this
>>> by debugging through the kernel code.
>>
>>This is not universally true. You are seeing this because the platform
>>is using SOFTWARE_COORDINATION mode for P-states. Most optimal in
>>terms of overhead is HARDWARE_COORDINATION mode, and this used to be
>>the recommended mode for platforms. And HW coordination is the
>>(atleast used to be) the more common mode across platforms.
>>Not sure whether this platform has SW coordination as a feature or bug?
>>
>>>
>>> So if there is no timer fired on CPU-0 (i.e. CPU-0 in C6), hence
>>> no deferrable timers will ever fired by kondemand/0 to sample all
>>> CPU workload. Since it is the only kthread doing the CPU freqency
>>> scaling for all CPUs, it is possible to enter in the situation
>>> where CPU frequency scaling will stop working for some duration
>>> until CPU-0 becomes not idle again.
>>
>>Yes. This will be a problem.
>>But, I am not sure whether the added complexity with the change below
>>to support the sub-optimal mode here. But, if we have a huge number of
>>platforms that are using software coordination, then there may not be
>>much of a choice here :(
>>
>>>
>>> Signed-off-by: Hari K Kanigeri <hari.kkanigeri@intel.com>
>>> ---
>>> drivers/cpufreq/cpufreq_ondemand.c | 93
>>+++++++++++++++++++++++++++++++----
>>> include/linux/cpufreq.h | 3 +
>>> 2 files changed, 85 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/drivers/cpufreq/cpufreq_ondemand.c
>>b/drivers/cpufreq/cpufreq_ondemand.c
>>> index 891360e..b4f4f9d 100644
>>> --- a/drivers/cpufreq/cpufreq_ondemand.c
>>> +++ b/drivers/cpufreq/cpufreq_ondemand.c
>>> @@ -541,6 +541,9 @@ static void dbs_check_cpu(struct cpu_dbs_info_s
>>*this_dbs_info)
>>>
>>> static void do_dbs_timer(struct work_struct *work)
>>> {
>>> + u64 old_time, new_do_dbs_time;
>>> + u64 saved_last_time;
>>> +
>>> struct cpu_dbs_info_s *dbs_info =
>>> container_of(work, struct cpu_dbs_info_s, work.work);
>>> unsigned int cpu = dbs_info->cpu;
>>> @@ -548,6 +551,41 @@ static void do_dbs_timer(struct work_struct *work)
>>>
>>> int delay;
>>>
>>> + new_do_dbs_time = get_jiffies_64();
>>> +
>>> + /* Save a copy of last_do_dbs_time do_dbs_timer */
>>> +
>>> + saved_last_time = atomic64_read(
>>> + &dbs_info->cur_policy->last_do_dbs_time);
>>> +
>>> + /* If the last time do_dbs_timer ran is less than */
>>> + /* 'delay' delta from current time, one of other */
>>> + /* CPUs is still handling cpufreq governoring for */
>>> + /* for all CPUs. */
>>> +
>>> + if ((new_do_dbs_time - saved_last_time) <
>>> + dbs_info->cur_policy->last_delay) {
>>> +
>>> + /* If do_dbs_time ran not long ago */
>>> + /* (delta is less than last_delay) */
>>> + /* then bail out because there is */
>>> + /* no need to run so frequently. */
>>> + goto do_exit;
>>> + }
>>> +
>>> + old_time = atomic64_cmpxchg(&dbs_info->cur_policy-
>>>last_do_dbs_time,
>>> + saved_last_time,
>>new_do_dbs_time);
>>> +
>>> + /* If old_time is not equal to saved_last_time, */
>>> + /* it means another CPU is calling do_dbs_time. */
>>> +
>>> + if (old_time != saved_last_time)
>>> + goto do_exit;
>>> +
>>> + /* Switch cpu saved in the policy */
>>> + if (dbs_info->cur_policy->cpu != cpu)
>>> + dbs_info->cur_policy->cpu = cpu;
>>> +
>>
>>
>>This seems somewhat complicated way to do this.. One simpler way could
>>be to have a new atomic element in dbs_info that stores the current
>>CPU among policy->cpus doing dbs_timers. By default it will be
>>policy->cpu and when it goes idle it changes the variable to -1, so
>>that any other CPU can nominate itself (using atomic cmpxchg). If it
>>is still -1, then policy->cpu does the check anyway.
>>
>>> mutex_lock(&dbs_info->timer_mutex);
>>>
>>> /* Common NORMAL_SAMPLE setup */
>>> @@ -559,6 +597,7 @@ static void do_dbs_timer(struct work_struct *work)
>>> /* Setup timer for SUB_SAMPLE */
>>> dbs_info->sample_type = DBS_SUB_SAMPLE;
>>> delay = dbs_info->freq_hi_jiffies;
>>> + dbs_info->cur_policy->last_delay = delay;
>>> } else {
>>> /* We want all CPUs to do sampling nearly on
>>> * same jiffy
>>> @@ -566,14 +605,18 @@ static void do_dbs_timer(struct work_struct
>>*work)
>>> delay =
>>usecs_to_jiffies(dbs_tuners_ins.sampling_rate
>>> * dbs_info->rate_mult);
>>>
>>> - if (num_online_cpus() > 1)
>>> + if (num_online_cpus() > 1) {
>>> delay -= jiffies % delay;
>>> + dbs_info->cur_policy->last_delay =
>>delay;
>>> + }
>>> }
>>> } else {
>>> __cpufreq_driver_target(dbs_info->cur_policy,
>>> dbs_info->freq_lo, CPUFREQ_RELATION_H);
>>> delay = dbs_info->freq_lo_jiffies;
>>> + dbs_info->cur_policy->last_delay = delay;
>>> }
>>> +do_exit:
>>> schedule_delayed_work_on(cpu, &dbs_info->work, delay);
>>> mutex_unlock(&dbs_info->timer_mutex);
>>> }
>>> @@ -648,10 +691,12 @@ static int cpufreq_governor_dbs(struct
>>cpufreq_policy *policy,
>>> j_dbs_info->prev_cpu_nice =
>>> kstat_cpu(j).cpustat.ni
>>ce;
>>> }
>>> +
>>> + j_dbs_info->cpu = j;
>>> + j_dbs_info->rate_mult = 1;
>>> + ondemand_powersave_bias_init_cpu(j);
>>> }
>>> - this_dbs_info->cpu = cpu;
>>> - this_dbs_info->rate_mult = 1;
>>> - ondemand_powersave_bias_init_cpu(cpu);
>>> +
>>> /*
>>> * Start the timerschedule work, when this governor
>>> * is used for first time
>>> @@ -680,32 +725,58 @@ static int cpufreq_governor_dbs(struct
>>cpufreq_policy *policy,
>>> }
>>> mutex_unlock(&dbs_mutex);
>>>
>>> - mutex_init(&this_dbs_info->timer_mutex);
>>> - dbs_timer_init(this_dbs_info);
>>> + for_each_cpu(j, policy->cpus) {
>>> + struct cpu_dbs_info_s *j_dbs_info;
>>> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
>>> + mutex_init(&j_dbs_info->timer_mutex);
>>> + dbs_timer_init(j_dbs_info);
>>> + }
>>> break;
>>>
>>> case CPUFREQ_GOV_STOP:
>>> - dbs_timer_exit(this_dbs_info);
>>> + for_each_cpu(j, policy->cpus) {
>>> + struct cpu_dbs_info_s *j_dbs_info;
>>> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
>>> + dbs_timer_exit(j_dbs_info);
>>> + }
>>>
>>> mutex_lock(&dbs_mutex);
>>> - mutex_destroy(&this_dbs_info->timer_mutex);
>>> +
>>> + for_each_cpu(j, policy->cpus) {
>>> + struct cpu_dbs_info_s *j_dbs_info;
>>> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
>>> + mutex_destroy(&j_dbs_info->timer_mutex);
>>> + }
>>> +
>>> dbs_enable--;
>>> mutex_unlock(&dbs_mutex);
>>> if (!dbs_enable)
>>> sysfs_remove_group(cpufreq_global_kobject,
>>> &dbs_attr_group);
>>> -
>>> break;
>>>
>>> case CPUFREQ_GOV_LIMITS:
>>> - mutex_lock(&this_dbs_info->timer_mutex);
>>> + /* Since ondemand governor is no longer running on the
>>*/
>>> + /* same CPU anymore,need to mutex_lock all timer_mutex
>>*/
>>> + /* before calling __cpufreq_driver_target. */
>>> + for_each_cpu(j, policy->cpus) {
>>> + struct cpu_dbs_info_s *j_dbs_info;
>>> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
>>> + mutex_lock(&j_dbs_info->timer_mutex);
>>
>>Not sure why we need a lock on all policy->cpus mutexes here. Could as
>>well be all policy->cpus use policy->cpu's mutex. No?
>>
>>
>>> + }
>>> +
>>> if (policy->max < this_dbs_info->cur_policy->cur)
>>> __cpufreq_driver_target(this_dbs_info-
>>>cur_policy,
>>> policy->max, CPUFREQ_RELATION_H);
>>> else if (policy->min > this_dbs_info->cur_policy->cur)
>>> __cpufreq_driver_target(this_dbs_info-
>>>cur_policy,
>>> policy->min, CPUFREQ_RELATION_L);
>>> - mutex_unlock(&this_dbs_info->timer_mutex);
>>> +
>>> + for_each_cpu(j, policy->cpus) {
>>> + struct cpu_dbs_info_s *j_dbs_info;
>>> + j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
>>> + mutex_unlock(&j_dbs_info->timer_mutex);
>>> + }
>>> break;
>>> }
>>> return 0;
>>> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
>>> index 11be48e..2295a35 100644
>>> --- a/include/linux/cpufreq.h
>>> +++ b/include/linux/cpufreq.h
>>> @@ -106,6 +106,9 @@ struct cpufreq_policy {
>>>
>>> struct kobject kobj;
>>> struct completion kobj_unregister;
>>> +
>>> + atomic64_t last_do_dbs_tim;
>>> + int last_delay;
>>> };
>>>
>>> #define CPUFREQ_ADJUST (0)
>>> --
>>> 1.7.1
>>>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-08-10 17:06 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-26 17:22 [PATCH] [RFC] ondemand governor: dynamic cpufreq scaling with different CPUs Yung, Winson W
2011-07-29 16:52 ` Venkatesh Pallipadi
2011-08-01 1:08 ` Yung, Winson W
2011-08-01 14:51 ` Len Brown
2011-08-10 16:59 ` Venki Pallipadi
2011-08-10 17:05 ` Venki Pallipadi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®