aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched_clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sched_clock.c')
-rw-r--r--kernel/sched_clock.c119
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 */
38unsigned long long __attribute__((weak)) sched_clock(void) 39unsigned 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
43static __read_mostly int sched_clock_running; 45static __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
48struct sched_clock_data { 50struct 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 */
110static u64 __update_sched_clock(struct sched_clock_data *scd, u64 now) 104static 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
109again:
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
136static void lock_double_clock(struct sched_clock_data *data1, 136static 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);
143again:
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
148u64 sched_clock_cpu(int cpu) 172u64 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/*