Messages in this thread | | | Date | Fri, 9 Apr 2010 14:12:35 +0200 | From | Oleg Nesterov <> | Subject | Re: [PATCH 2/2] cpuhotplug: make get_online_cpus() scalability by using percpu counter |
| |
On 04/07, Oleg Nesterov wrote: > > On 04/07, Lai Jiangshan wrote: > > > > Old get_online_cpus() is read-preference, I think the goal of this ability > > is allow get_online_cpus()/put_online_cpus() to be called nested. > > Sure, I understand why you added task_struct->get_online_cpus_nest. > > > and use per-task counter for allowing get_online_cpus()/put_online_cpus() > > to be called nested, I think this deal is absolutely worth. > > As I said, I am not going to argue. I can't justify this tradeoff.
But, I must admit, I'd like to avoid adding the new member to task_struct.
What do you think about the code below?
I didn't even try to compile it, just to explain what I mean.
In short: we have the per-cpu fast counters, plus the slow counter which is only used when cpu_hotplug_begin() is in progress.
Oleg.
static DEFINE_PER_CPU(long, cpuhp_fast_ctr); static struct task_struct *cpuhp_writer; static DEFINE_MUTEX(cpuhp_slow_lock) static long cpuhp_slow_ctr;
static bool update_fast_ctr(int inc) { bool success = true;
preempt_disable(); if (likely(!cpuhp_writer)) __get_cpu_var(cpuhp_fast_ctr) += inc; else if (cpuhp_writer != current) success = false; preempt_enable();
return success; }
void get_online_cpus(void) { if (likely(update_fast_ctr(+1)); return;
mutex_lock(&cpuhp_slow_lock); cpuhp_slow_ctr++; mutex_unlock(&cpuhp_slow_lock); }
void put_online_cpus(void) { if (likely(update_fast_ctr(-1)); return;
mutex_lock(&cpuhp_slow_lock); if (!--cpuhp_slow_ctr && cpuhp_writer) wake_up_process(cpuhp_writer); mutex_unlock(&cpuhp_slow_lock); }
static void clear_fast_ctr(void) { long total = 0; int cpu;
for_each_possible_cpu(cpu) { total += per_cpu(cpuhp_fast_ctr, cpu); per_cpu(cpuhp_fast_ctr, cpu) = 0; }
return total; }
static void cpu_hotplug_begin(void) { cpuhp_writer = current; synchronize_sched();
/* Nobody except us can use can use cpuhp_fast_ctr */
mutex_lock(&cpuhp_slow_lock); cpuhp_slow_ctr += clear_fast_ctr();
while (cpuhp_slow_ctr) { __set_current_state(TASK_UNINTERRUPTIBLE); mutex_unlock(&&cpuhp_slow_lock); schedule(); mutex_lock(&cpuhp_slow_lock); } }
static void cpu_hotplug_done(void) { cpuhp_writer = NULL; mutex_unlock(&cpuhp_slow_lock); }
| |