History

hrtimer: Avoid more SMP function calls in clock_was_set()

By unconditionally updating the offsets there are more indicators whether the SMP function calls on clock_was_set() can be avoided: - When the offset update already happened on the remote CPU then the remote update attempt will yield the same seqeuence number and no IPI is required. - When the remote CPU is currently handling hrtimer_interrupt(). In that case the remote CPU will reevaluate the timer bases before reprogramming anyway, so nothing to do. - After updating it can be checked whether the first expiring timer in the affected clock bases moves before the first expiring (softirq) timer of the CPU. If that's not the case then sending the IPI is not required.

Thomas Gleixner committed 5 years ago

Commit 1e7f7fb1 parent 81d741d1 file · +65 −9Browse files

Unified · Split

kernel/time/hrtimer.c+65−9
@@ -866,6 +866,68 @@ static void hrtimer_reprogram(struct hrtimer *timer, bool reprogram) · 865 unmodified lines
866 __hrtimer_reprogram(cpu_base, true, timer, expires);866 __hrtimer_reprogram(cpu_base, true, timer, expires);
867}867}
868 868
869static bool update_needs_ipi(struct hrtimer_cpu_base *cpu_base,
870 unsigned int active)
871{
872 struct hrtimer_clock_base *base;
873 unsigned int seq;
874 ktime_t expires;
875
876 /*
877 * Update the base offsets unconditionally so the following
878 * checks whether the SMP function call is required works.
879 *
880 * The update is safe even when the remote CPU is in the hrtimer
881 * interrupt or the hrtimer soft interrupt and expiring affected
882 * bases. Either it will see the update before handling a base or
883 * it will see it when it finishes the processing and reevaluates
884 * the next expiring timer.
885 */
886 seq = cpu_base->clock_was_set_seq;
887 hrtimer_update_base(cpu_base);
888
889 /*
890 * If the sequence did not change over the update then the
891 * remote CPU already handled it.
892 */
893 if (seq == cpu_base->clock_was_set_seq)
894 return false;
895
896 /*
897 * If the remote CPU is currently handling an hrtimer interrupt, it
898 * will reevaluate the first expiring timer of all clock bases
899 * before reprogramming. Nothing to do here.
900 */
901 if (cpu_base->in_hrtirq)
902 return false;
903
904 /*
905 * Walk the affected clock bases and check whether the first expiring
906 * timer in a clock base is moving ahead of the first expiring timer of
907 * @cpu_base. If so, the IPI must be invoked because per CPU clock
908 * event devices cannot be remotely reprogrammed.
909 */
910 active &= cpu_base->active_bases;
911
912 for_each_active_base(base, cpu_base, active) {
913 struct timerqueue_node *next;
914
915 next = timerqueue_getnext(&base->active);
916 expires = ktime_sub(next->expires, base->offset);
917 if (expires < cpu_base->expires_next)
918 return true;
919
920 /* Extra check for softirq clock bases */
921 if (base->clockid < HRTIMER_BASE_MONOTONIC_SOFT)
922 continue;
923 if (cpu_base->softirq_activated)
924 continue;
925 if (expires < cpu_base->softirq_expires_next)
926 return true;
927 }
928 return false;
929}
930
869/*931/*
870 * Clock was set. This might affect CLOCK_REALTIME, CLOCK_TAI and932 * Clock was set. This might affect CLOCK_REALTIME, CLOCK_TAI and
871 * CLOCK_BOOTTIME (for late sleep time injection).933 * CLOCK_BOOTTIME (for late sleep time injection).
@@ -900,16 +962,10 @@ void clock_was_set(unsigned int bases) · 28 unmodified lines
900 unsigned long flags;962 unsigned long flags;
901 963
902 raw_spin_lock_irqsave(&cpu_base->lock, flags);964 raw_spin_lock_irqsave(&cpu_base->lock, flags);
903 /*965
904 * Only send the IPI when there are timers queued in one of966 if (update_needs_ipi(cpu_base, bases))
905 * the affected clock bases. Otherwise update the base
906 * remote to ensure that the next enqueue of a timer on
907 * such a clock base will see the correct offsets.
908 */
909 if (cpu_base->active_bases & bases)
910 cpumask_set_cpu(cpu, mask);967 cpumask_set_cpu(cpu, mask);
911 else968
912 hrtimer_update_base(cpu_base);
913 raw_spin_unlock_irqrestore(&cpu_base->lock, flags);969 raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
914 }970 }
915 971

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t