diff options
Diffstat (limited to 'kernel/sched_clock.c')
-rw-r--r-- | kernel/sched_clock.c | 119 |
1 files changed, 58 insertions, 61 deletions
diff --git a/kernel/sched_clock.c b/kernel/sched_clock.c index 390f33234bd0..479ce5682d7c 100644 --- a/kernel/sched_clock.c +++ b/kernel/sched_clock.c | |||
@@ -25,6 +25,7 @@ | |||
25 | * consistent between cpus (never more than 2 jiffies difference). | 25 | * consistent between cpus (never more than 2 jiffies difference). |
26 | */ | 26 | */ |
27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
28 | #include <linux/hardirq.h> | ||
28 | #include <linux/module.h> | 29 | #include <linux/module.h> |
29 | #include <linux/percpu.h> | 30 | #include <linux/percpu.h> |
30 | #include <linux/ktime.h> | 31 | #include <linux/ktime.h> |
@@ -37,7 +38,8 @@ | |||
37 | */ | 38 | */ |
38 | unsigned long long __attribute__((weak)) sched_clock(void) | 39 | unsigned long long __attribute__((weak)) sched_clock(void) |
39 | { | 40 | { |
40 | return (unsigned long long)jiffies * (NSEC_PER_SEC / HZ); | 41 | return (unsigned long long)(jiffies - INITIAL_JIFFIES) |
42 | * (NSEC_PER_SEC / HZ); | ||
41 | } | 43 | } |
42 | 44 | ||
43 | static __read_mostly int sched_clock_running; | 45 | static __read_mostly int sched_clock_running; |
@@ -46,13 +48,6 @@ static __read_mostly int sched_clock_running; | |||
46 | __read_mostly int sched_clock_stable; | 48 | __read_mostly int sched_clock_stable; |
47 | 49 | ||
48 | struct sched_clock_data { | 50 | struct sched_clock_data { |
49 | /* | ||
50 | * Raw spinlock - this is a special case: this might be called | ||
51 | * from within instrumentation code so we dont want to do any | ||
52 | * instrumentation ourselves. | ||
53 | */ | ||
54 | raw_spinlock_t lock; | ||
55 | |||
56 | u64 tick_raw; | 51 | u64 tick_raw; |
57 | u64 tick_gtod; | 52 | u64 tick_gtod; |
58 | u64 clock; | 53 | u64 clock; |
@@ -78,7 +73,6 @@ void sched_clock_init(void) | |||
78 | for_each_possible_cpu(cpu) { | 73 | for_each_possible_cpu(cpu) { |
79 | struct sched_clock_data *scd = cpu_sdc(cpu); | 74 | struct sched_clock_data *scd = cpu_sdc(cpu); |
80 | 75 | ||
81 | scd->lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED; | ||
82 | scd->tick_raw = 0; | 76 | scd->tick_raw = 0; |
83 | scd->tick_gtod = ktime_now; | 77 | scd->tick_gtod = ktime_now; |
84 | scd->clock = ktime_now; | 78 | scd->clock = ktime_now; |
@@ -107,14 +101,19 @@ static inline u64 wrap_max(u64 x, u64 y) | |||
107 | * - filter out backward motion | 101 | * - filter out backward motion |
108 | * - use the GTOD tick value to create a window to filter crazy TSC values | 102 | * - use the GTOD tick value to create a window to filter crazy TSC values |
109 | */ | 103 | */ |
110 | static u64 __update_sched_clock(struct sched_clock_data *scd, u64 now) | 104 | static u64 sched_clock_local(struct sched_clock_data *scd) |
111 | { | 105 | { |
112 | s64 delta = now - scd->tick_raw; | 106 | u64 now, clock, old_clock, min_clock, max_clock; |
113 | u64 clock, min_clock, max_clock; | 107 | s64 delta; |
114 | 108 | ||
109 | again: | ||
110 | now = sched_clock(); | ||
111 | delta = now - scd->tick_raw; | ||
115 | if (unlikely(delta < 0)) | 112 | if (unlikely(delta < 0)) |
116 | delta = 0; | 113 | delta = 0; |
117 | 114 | ||
115 | old_clock = scd->clock; | ||
116 | |||
118 | /* | 117 | /* |
119 | * scd->clock = clamp(scd->tick_gtod + delta, | 118 | * scd->clock = clamp(scd->tick_gtod + delta, |
120 | * max(scd->tick_gtod, scd->clock), | 119 | * max(scd->tick_gtod, scd->clock), |
@@ -122,73 +121,73 @@ static u64 __update_sched_clock(struct sched_clock_data *scd, u64 now) | |||
122 | */ | 121 | */ |
123 | 122 | ||
124 | clock = scd->tick_gtod + delta; | 123 | clock = scd->tick_gtod + delta; |
125 | min_clock = wrap_max(scd->tick_gtod, scd->clock); | 124 | min_clock = wrap_max(scd->tick_gtod, old_clock); |
126 | max_clock = wrap_max(scd->clock, scd->tick_gtod + TICK_NSEC); | 125 | max_clock = wrap_max(old_clock, scd->tick_gtod + TICK_NSEC); |
127 | 126 | ||
128 | clock = wrap_max(clock, min_clock); | 127 | clock = wrap_max(clock, min_clock); |
129 | clock = wrap_min(clock, max_clock); | 128 | clock = wrap_min(clock, max_clock); |
130 | 129 | ||
131 | scd->clock = clock; | 130 | if (cmpxchg64(&scd->clock, old_clock, clock) != old_clock) |
131 | goto again; | ||
132 | 132 | ||
133 | return scd->clock; | 133 | return clock; |
134 | } | 134 | } |
135 | 135 | ||
136 | static void lock_double_clock(struct sched_clock_data *data1, | 136 | static u64 sched_clock_remote(struct sched_clock_data *scd) |
137 | struct sched_clock_data *data2) | ||
138 | { | 137 | { |
139 | if (data1 < data2) { | 138 | struct sched_clock_data *my_scd = this_scd(); |
140 | __raw_spin_lock(&data1->lock); | 139 | u64 this_clock, remote_clock; |
141 | __raw_spin_lock(&data2->lock); | 140 | u64 *ptr, old_val, val; |
141 | |||
142 | sched_clock_local(my_scd); | ||
143 | again: | ||
144 | this_clock = my_scd->clock; | ||
145 | remote_clock = scd->clock; | ||
146 | |||
147 | /* | ||
148 | * Use the opportunity that we have both locks | ||
149 | * taken to couple the two clocks: we take the | ||
150 | * larger time as the latest time for both | ||
151 | * runqueues. (this creates monotonic movement) | ||
152 | */ | ||
153 | if (likely((s64)(remote_clock - this_clock) < 0)) { | ||
154 | ptr = &scd->clock; | ||
155 | old_val = remote_clock; | ||
156 | val = this_clock; | ||
142 | } else { | 157 | } else { |
143 | __raw_spin_lock(&data2->lock); | 158 | /* |
144 | __raw_spin_lock(&data1->lock); | 159 | * Should be rare, but possible: |
160 | */ | ||
161 | ptr = &my_scd->clock; | ||
162 | old_val = this_clock; | ||
163 | val = remote_clock; | ||
145 | } | 164 | } |
165 | |||
166 | if (cmpxchg64(ptr, old_val, val) != old_val) | ||
167 | goto again; | ||
168 | |||
169 | return val; | ||
146 | } | 170 | } |
147 | 171 | ||
148 | u64 sched_clock_cpu(int cpu) | 172 | u64 sched_clock_cpu(int cpu) |
149 | { | 173 | { |
150 | u64 now, clock, this_clock, remote_clock; | ||
151 | struct sched_clock_data *scd; | 174 | struct sched_clock_data *scd; |
175 | u64 clock; | ||
152 | 176 | ||
153 | if (sched_clock_stable) | ||
154 | return sched_clock(); | ||
155 | |||
156 | scd = cpu_sdc(cpu); | ||
157 | WARN_ON_ONCE(!irqs_disabled()); | 177 | WARN_ON_ONCE(!irqs_disabled()); |
158 | now = sched_clock(); | ||
159 | |||
160 | if (cpu != raw_smp_processor_id()) { | ||
161 | struct sched_clock_data *my_scd = this_scd(); | ||
162 | 178 | ||
163 | lock_double_clock(scd, my_scd); | 179 | if (sched_clock_stable) |
180 | return sched_clock(); | ||
164 | 181 | ||
165 | this_clock = __update_sched_clock(my_scd, now); | 182 | if (unlikely(!sched_clock_running)) |
166 | remote_clock = scd->clock; | 183 | return 0ull; |
167 | 184 | ||
168 | /* | 185 | scd = cpu_sdc(cpu); |
169 | * Use the opportunity that we have both locks | ||
170 | * taken to couple the two clocks: we take the | ||
171 | * larger time as the latest time for both | ||
172 | * runqueues. (this creates monotonic movement) | ||
173 | */ | ||
174 | if (likely((s64)(remote_clock - this_clock) < 0)) { | ||
175 | clock = this_clock; | ||
176 | scd->clock = clock; | ||
177 | } else { | ||
178 | /* | ||
179 | * Should be rare, but possible: | ||
180 | */ | ||
181 | clock = remote_clock; | ||
182 | my_scd->clock = remote_clock; | ||
183 | } | ||
184 | |||
185 | __raw_spin_unlock(&my_scd->lock); | ||
186 | } else { | ||
187 | __raw_spin_lock(&scd->lock); | ||
188 | clock = __update_sched_clock(scd, now); | ||
189 | } | ||
190 | 186 | ||
191 | __raw_spin_unlock(&scd->lock); | 187 | if (cpu != smp_processor_id()) |
188 | clock = sched_clock_remote(scd); | ||
189 | else | ||
190 | clock = sched_clock_local(scd); | ||
192 | 191 | ||
193 | return clock; | 192 | return clock; |
194 | } | 193 | } |
@@ -210,11 +209,9 @@ void sched_clock_tick(void) | |||
210 | now_gtod = ktime_to_ns(ktime_get()); | 209 | now_gtod = ktime_to_ns(ktime_get()); |
211 | now = sched_clock(); | 210 | now = sched_clock(); |
212 | 211 | ||
213 | __raw_spin_lock(&scd->lock); | ||
214 | scd->tick_raw = now; | 212 | scd->tick_raw = now; |
215 | scd->tick_gtod = now_gtod; | 213 | scd->tick_gtod = now_gtod; |
216 | __update_sched_clock(scd, now); | 214 | sched_clock_local(scd); |
217 | __raw_spin_unlock(&scd->lock); | ||
218 | } | 215 | } |
219 | 216 | ||
220 | /* | 217 | /* |