Skip to content

Commit 128c434

Browse files
committed
Merge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull scheduler fixes from Thomas Gleixner: "This update provides: - make the scheduler clock switch to unstable mode smooth so the timestamps stay at microseconds granularity instead of switching to tick granularity. - unbreak perf test tsc by taking the new offset into account which was added in order to proveide better sched clock continuity - switching sched clock to unstable mode runs all clock related computations which affect the sched clock output itself from a work queue. In case of preemption sched clock uses half updated data and provides wrong timestamps. Keep the math in the protected context and delegate only the static key switch to workqueue context. - remove a duplicate header include" * 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: sched/headers: Remove duplicate #include <linux/sched/debug.h> line sched/clock: Fix broken stable to unstable transfer sched/clock, x86/perf: Fix "perf test tsc" sched/clock: Fix clear_sched_clock_stable() preempt wobbly
2 parents 0a89b5e + 658b299 commit 128c434

File tree

6 files changed

+44
-31
lines changed

6 files changed

+44
-31
lines changed

arch/x86/events/core.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2256,34 +2256,37 @@ void arch_perf_update_userpage(struct perf_event *event,
22562256
struct perf_event_mmap_page *userpg, u64 now)
22572257
{
22582258
struct cyc2ns_data *data;
2259+
u64 offset;
22592260

22602261
userpg->cap_user_time = 0;
22612262
userpg->cap_user_time_zero = 0;
22622263
userpg->cap_user_rdpmc =
22632264
!!(event->hw.flags & PERF_X86_EVENT_RDPMC_ALLOWED);
22642265
userpg->pmc_width = x86_pmu.cntval_bits;
22652266

2266-
if (!sched_clock_stable())
2267+
if (!using_native_sched_clock() || !sched_clock_stable())
22672268
return;
22682269

22692270
data = cyc2ns_read_begin();
22702271

2272+
offset = data->cyc2ns_offset + __sched_clock_offset;
2273+
22712274
/*
22722275
* Internal timekeeping for enabled/running/stopped times
22732276
* is always in the local_clock domain.
22742277
*/
22752278
userpg->cap_user_time = 1;
22762279
userpg->time_mult = data->cyc2ns_mul;
22772280
userpg->time_shift = data->cyc2ns_shift;
2278-
userpg->time_offset = data->cyc2ns_offset - now;
2281+
userpg->time_offset = offset - now;
22792282

22802283
/*
22812284
* cap_user_time_zero doesn't make sense when we're using a different
22822285
* time base for the records.
22832286
*/
22842287
if (!event->attr.use_clockid) {
22852288
userpg->cap_user_time_zero = 1;
2286-
userpg->time_zero = data->cyc2ns_offset;
2289+
userpg->time_zero = offset;
22872290
}
22882291

22892292
cyc2ns_read_end(data);

arch/x86/include/asm/timer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ extern int recalibrate_cpu_khz(void);
1212

1313
extern int no_timer_check;
1414

15+
extern bool using_native_sched_clock(void);
16+
1517
/*
1618
* We use the full linear equation: f(x) = a + b*x, in order to allow
1719
* a continuous function in the face of dynamic freq changes.

arch/x86/kernel/tsc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,15 +328,15 @@ unsigned long long sched_clock(void)
328328
return paravirt_sched_clock();
329329
}
330330

331-
static inline bool using_native_sched_clock(void)
331+
bool using_native_sched_clock(void)
332332
{
333333
return pv_time_ops.sched_clock == native_sched_clock;
334334
}
335335
#else
336336
unsigned long long
337337
sched_clock(void) __attribute__((alias("native_sched_clock")));
338338

339-
static inline bool using_native_sched_clock(void) { return true; }
339+
bool using_native_sched_clock(void) { return true; }
340340
#endif
341341

342342
int check_tsc_unstable(void)

drivers/tty/vt/keyboard.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
#include <linux/module.h>
2929
#include <linux/sched/signal.h>
3030
#include <linux/sched/debug.h>
31-
#include <linux/sched/debug.h>
3231
#include <linux/tty.h>
3332
#include <linux/tty_flip.h>
3433
#include <linux/mm.h>

include/linux/sched/clock.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,16 @@ static inline u64 local_clock(void)
5454
}
5555
#else
5656
extern void sched_clock_init_late(void);
57-
/*
58-
* Architectures can set this to 1 if they have specified
59-
* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK in their arch Kconfig,
60-
* but then during bootup it turns out that sched_clock()
61-
* is reliable after all:
62-
*/
6357
extern int sched_clock_stable(void);
6458
extern void clear_sched_clock_stable(void);
6559

60+
/*
61+
* When sched_clock_stable(), __sched_clock_offset provides the offset
62+
* between local_clock() and sched_clock().
63+
*/
64+
extern u64 __sched_clock_offset;
65+
66+
6667
extern void sched_clock_tick(void);
6768
extern void sched_clock_idle_sleep_event(void);
6869
extern void sched_clock_idle_wakeup_event(u64 delta_ns);

kernel/sched/clock.c

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,10 @@ static DEFINE_STATIC_KEY_FALSE(__sched_clock_stable);
9696
static int __sched_clock_stable_early = 1;
9797

9898
/*
99-
* We want: ktime_get_ns() + gtod_offset == sched_clock() + raw_offset
99+
* We want: ktime_get_ns() + __gtod_offset == sched_clock() + __sched_clock_offset
100100
*/
101-
static __read_mostly u64 raw_offset;
102-
static __read_mostly u64 gtod_offset;
101+
__read_mostly u64 __sched_clock_offset;
102+
static __read_mostly u64 __gtod_offset;
103103

104104
struct sched_clock_data {
105105
u64 tick_raw;
@@ -131,17 +131,24 @@ static void __set_sched_clock_stable(void)
131131
/*
132132
* Attempt to make the (initial) unstable->stable transition continuous.
133133
*/
134-
raw_offset = (scd->tick_gtod + gtod_offset) - (scd->tick_raw);
134+
__sched_clock_offset = (scd->tick_gtod + __gtod_offset) - (scd->tick_raw);
135135

136136
printk(KERN_INFO "sched_clock: Marking stable (%lld, %lld)->(%lld, %lld)\n",
137-
scd->tick_gtod, gtod_offset,
138-
scd->tick_raw, raw_offset);
137+
scd->tick_gtod, __gtod_offset,
138+
scd->tick_raw, __sched_clock_offset);
139139

140140
static_branch_enable(&__sched_clock_stable);
141141
tick_dep_clear(TICK_DEP_BIT_CLOCK_UNSTABLE);
142142
}
143143

144-
static void __clear_sched_clock_stable(struct work_struct *work)
144+
static void __sched_clock_work(struct work_struct *work)
145+
{
146+
static_branch_disable(&__sched_clock_stable);
147+
}
148+
149+
static DECLARE_WORK(sched_clock_work, __sched_clock_work);
150+
151+
static void __clear_sched_clock_stable(void)
145152
{
146153
struct sched_clock_data *scd = this_scd();
147154

@@ -154,17 +161,17 @@ static void __clear_sched_clock_stable(struct work_struct *work)
154161
*
155162
* Still do what we can.
156163
*/
157-
gtod_offset = (scd->tick_raw + raw_offset) - (scd->tick_gtod);
164+
__gtod_offset = (scd->tick_raw + __sched_clock_offset) - (scd->tick_gtod);
158165

159166
printk(KERN_INFO "sched_clock: Marking unstable (%lld, %lld)<-(%lld, %lld)\n",
160-
scd->tick_gtod, gtod_offset,
161-
scd->tick_raw, raw_offset);
167+
scd->tick_gtod, __gtod_offset,
168+
scd->tick_raw, __sched_clock_offset);
162169

163-
static_branch_disable(&__sched_clock_stable);
164170
tick_dep_set(TICK_DEP_BIT_CLOCK_UNSTABLE);
165-
}
166171

167-
static DECLARE_WORK(sched_clock_work, __clear_sched_clock_stable);
172+
if (sched_clock_stable())
173+
schedule_work(&sched_clock_work);
174+
}
168175

169176
void clear_sched_clock_stable(void)
170177
{
@@ -173,7 +180,7 @@ void clear_sched_clock_stable(void)
173180
smp_mb(); /* matches sched_clock_init_late() */
174181

175182
if (sched_clock_running == 2)
176-
schedule_work(&sched_clock_work);
183+
__clear_sched_clock_stable();
177184
}
178185

179186
void sched_clock_init_late(void)
@@ -214,7 +221,7 @@ static inline u64 wrap_max(u64 x, u64 y)
214221
*/
215222
static u64 sched_clock_local(struct sched_clock_data *scd)
216223
{
217-
u64 now, clock, old_clock, min_clock, max_clock;
224+
u64 now, clock, old_clock, min_clock, max_clock, gtod;
218225
s64 delta;
219226

220227
again:
@@ -231,9 +238,10 @@ static u64 sched_clock_local(struct sched_clock_data *scd)
231238
* scd->tick_gtod + TICK_NSEC);
232239
*/
233240

234-
clock = scd->tick_gtod + gtod_offset + delta;
235-
min_clock = wrap_max(scd->tick_gtod, old_clock);
236-
max_clock = wrap_max(old_clock, scd->tick_gtod + TICK_NSEC);
241+
gtod = scd->tick_gtod + __gtod_offset;
242+
clock = gtod + delta;
243+
min_clock = wrap_max(gtod, old_clock);
244+
max_clock = wrap_max(old_clock, gtod + TICK_NSEC);
237245

238246
clock = wrap_max(clock, min_clock);
239247
clock = wrap_min(clock, max_clock);
@@ -317,7 +325,7 @@ u64 sched_clock_cpu(int cpu)
317325
u64 clock;
318326

319327
if (sched_clock_stable())
320-
return sched_clock() + raw_offset;
328+
return sched_clock() + __sched_clock_offset;
321329

322330
if (unlikely(!sched_clock_running))
323331
return 0ull;

0 commit comments

Comments
 (0)