/* * Catch up with missed period expirations. * * until (c_{j} == c) * x_{j} -= x_{j}/2; * c_{j}++; */ static void prop_norm_percpu(struct prop_global *pg, struct prop_local_percpu *pl) { unsigned long period = 1UL << (pg->shift - 1); unsigned long period_mask = ~(period - 1); unsigned long global_period; unsigned long flags; global_period = percpu_counter_read(&pg->events); global_period &= period_mask; /* * Fast path - check if the local and global period count still match * outside of the lock. */ if (pl->period == global_period) return; raw_spin_lock_irqsave(&pl->lock, flags); prop_adjust_shift(&pl->shift, &pl->period, pg->shift); /* * For each missed period, we half the local counter. * basically: * pl->events >> (global_period - pl->period); */ period = (global_period - pl->period) >> (pg->shift - 1); if (period < BITS_PER_LONG) { s64 val = percpu_counter_read(&pl->events); if (val < (nr_cpu_ids * PROP_BATCH)) val = percpu_counter_sum(&pl->events); __percpu_counter_add(&pl->events, -val + (val >> period), PROP_BATCH); } else
static void prop_norm_percpu(struct prop_global *pg, struct prop_local_percpu *pl) { unsigned long period = 1UL << (pg->shift - 1); unsigned long period_mask = ~(period - 1); unsigned long global_period; unsigned long flags; global_period = percpu_counter_read(&pg->events); global_period &= period_mask; /* */ if (pl->period == global_period) return; raw_spin_lock_irqsave(&pl->lock, flags); prop_adjust_shift(&pl->shift, &pl->period, pg->shift); /* */ period = (global_period - pl->period) >> (pg->shift - 1); if (period < BITS_PER_LONG) { s64 val = percpu_counter_read(&pl->events); if (val < (nr_cpu_ids * PROP_BATCH)) val = percpu_counter_sum(&pl->events); __percpu_counter_add(&pl->events, -val + (val >> period), PROP_BATCH); } else