diff options
author | Frederic Weisbecker <frederic@kernel.org> | 2024-02-16 16:28:30 +0100 |
---|---|---|
committer | Frederic Weisbecker <frederic@kernel.org> | 2024-02-19 13:11:30 +0100 |
commit | 7e5666358c1b4b38fe229e1f75fa2a211d60f3f0 (patch) | |
tree | 32621d45d65266f1318767ba0cd534288ff42dee | |
parent | 35562ef99e4c3453ffe2a2215d1fac40891e0412 (diff) | |
download | linux-dynticks-timers/anna-experimental.tar.gz |
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
-rw-r--r-- | include/linux/sched.h | 6 | ||||
-rw-r--r-- | kernel/rcu/rcutorture.c | 12 | ||||
-rw-r--r-- | kernel/time/timer.c | 53 | ||||
-rw-r--r-- | kernel/time/timer_migration.c | 4 | ||||
-rwxr-xr-x | tools/testing/selftests/rcutorture/bin/kvm.sh | 2 |
5 files changed, 57 insertions, 20 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index ffe8f618ab8697..47c83cdedbbd45 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -745,6 +745,11 @@ struct kmap_ctrl { #endif }; +struct process_timer { + struct timer_list timer; + struct task_struct *task; +}; + struct task_struct { #ifdef CONFIG_THREAD_INFO_IN_TASK /* @@ -1546,6 +1551,7 @@ struct task_struct { #ifdef CONFIG_USER_EVENTS struct user_event_mm *user_event_mm; #endif + struct process_timer process_timer; /* * New fields for task_struct should be added above here, so that diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 7567ca8e743ca6..e14bf78c42a55f 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -335,6 +335,8 @@ rcu_torture_free(struct rcu_torture *p) spin_unlock_bh(&rcu_torture_lock); } +void timers_dump_cpu(unsigned int cpu); + /* * Operations vector for selecting different types of tests. */ @@ -1361,7 +1363,7 @@ rcu_torture_writer(void *arg) unsigned long gp_snap1; struct rcu_gp_oldstate gp_snap_full; struct rcu_gp_oldstate gp_snap1_full; - int i; + int i, j; int idx; int oldnice = task_nice(current); struct rcu_gp_oldstate rgo[NUM_ACTIVE_RCU_POLL_FULL_OLDSTATE]; @@ -1584,6 +1586,9 @@ rcu_torture_writer(void *arg) tracing_off(); show_rcu_gp_kthreads(); WARN(1, "%s: rtort_pipe_count: %d\n", __func__, rcu_tortures[i].rtort_pipe_count); + for_each_online_cpu(j) { + timers_dump_cpu(j); + } rcu_ftrace_dump(DUMP_ALL); } if (stutter_waited) @@ -2168,7 +2173,7 @@ static void rcu_torture_stats_print(void) { int cpu; - int i; + int i, j; long pipesummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 }; long batchsummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 }; struct rcu_torture *rtcp; @@ -2271,6 +2276,9 @@ rcu_torture_stats_print(void) } if (cur_ops->gp_kthread_dbg) cur_ops->gp_kthread_dbg(); + for_each_online_cpu(j) { + timers_dump_cpu(j); + } rcu_ftrace_dump(DUMP_ALL); } rtcv_snap = rcu_torture_current_version; diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 320eb4ceafa2b5..64ce9a7760f595 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -616,7 +616,8 @@ static void enqueue_timer(struct timer_base *base, struct timer_list *timer, __set_bit(idx, base->pending_map); timer_set_idx(timer, idx); - trace_timer_start(timer, bucket_expiry); + if (!(timer->flags & TIMER_PINNED)) + trace_timer_start(timer, bucket_expiry); /* * Check whether this is the new first expiring timer. The @@ -838,8 +839,9 @@ static inline void debug_init(struct timer_list *timer) static inline void debug_deactivate(struct timer_list *timer) { - debug_timer_deactivate(timer); - trace_timer_cancel(timer); + debug_timer_deactivate(timer); + if (!(timer->flags & TIMER_PINNED)) + trace_timer_cancel(timer); } static inline void debug_assert_init(struct timer_list *timer) @@ -1744,7 +1746,8 @@ static void call_timer_fn(struct timer_list *timer, */ lock_map_acquire(&lockdep_map); - trace_timer_expire_entry(timer, baseclk); + if (!(timer->flags & TIMER_PINNED)) + trace_timer_expire_entry(timer, baseclk); fn(timer); trace_timer_expire_exit(timer); @@ -2004,6 +2007,8 @@ static unsigned long fetch_next_timer_interrupt(unsigned long basej, u64 basem, if (time_before(nextevt, basej)) nextevt = basej; tevt->local = basem + (u64)(nextevt - basej) * TICK_NSEC; + if (!local_first) + tevt->global = tevt->local; return nextevt; } @@ -2428,10 +2433,6 @@ void update_process_times(int user_tick) * Since schedule_timeout()'s timer is defined on the stack, it must store * the target task on the stack as well. */ -struct process_timer { - struct timer_list timer; - struct task_struct *task; -}; static void process_timeout(struct timer_list *t) { @@ -2473,7 +2474,7 @@ static void process_timeout(struct timer_list *t) */ signed long __sched schedule_timeout(signed long timeout) { - struct process_timer timer; + struct process_timer *timer = ¤t->process_timer; unsigned long expire; switch (timeout) @@ -2507,14 +2508,11 @@ signed long __sched schedule_timeout(signed long timeout) expire = timeout + jiffies; - timer.task = current; - timer_setup_on_stack(&timer.timer, process_timeout, 0); - __mod_timer(&timer.timer, expire, MOD_TIMER_NOTPENDING); + timer->task = current; + timer_setup(&timer->timer, process_timeout, 0); + __mod_timer(&timer->timer, expire, MOD_TIMER_NOTPENDING); schedule(); - del_timer_sync(&timer.timer); - - /* Remove the timer from the object tracker */ - destroy_timer_on_stack(&timer.timer); + del_timer_sync(&timer->timer); timeout = expire - jiffies; @@ -2624,6 +2622,29 @@ int timers_dead_cpu(unsigned int cpu) return 0; } +void timers_dump_cpu(unsigned int cpu); + +void timers_dump_cpu(unsigned int cpu) +{ + struct timer_base *base = per_cpu_ptr(&timer_bases[BASE_GLOBAL], cpu); + unsigned long flags; + int i; + + printk("Dumping CPU timers for %d\n", cpu); + raw_spin_lock_irqsave(&base->lock, flags); + for (i = 0; i < WHEEL_SIZE; i++) { + struct timer_list *t; + + hlist_for_each_entry(t, base->vectors + i, entry) { + if (t->expires < jiffies) + printk("CPU: %d timer:%p func=%ps expires=%lu now=%lu diff=%lu\n", cpu, t, t->function, t->expires, jiffies, jiffies - t->expires); + } + } + raw_spin_unlock_irqrestore(&base->lock, flags); +} +EXPORT_SYMBOL(timers_dump_cpu); + + #endif /* CONFIG_HOTPLUG_CPU */ static void __init init_timer_cpu(int cpu) diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c index b1a27e9a6db4b2..437db316aa3219 100644 --- a/kernel/time/timer_migration.c +++ b/kernel/time/timer_migration.c @@ -977,7 +977,7 @@ static void tmigr_handle_remote_cpu(unsigned int cpu, u64 now, * after a remote expiry" in the documentation at the top) */ walk_groups(&tmigr_new_timer_up, &data, tmc); - + trace_tmigr_cpu_new_timer_idle(tmc, tevt.global); unlock: tmc->remote = false; raw_spin_unlock_irq(&tmc->lock); @@ -1017,6 +1017,8 @@ again: if (evt) { unsigned int remote_cpu = evt->cpu; +// if (now > evt->nextevt.expires + 1) +// trace_printk("Handle late CPU=%u now=%llu expires=%llu delta=%llu\n", remote_cpu, now, evt->nextevt.expires, now - evt->nextevt.expires); raw_spin_unlock_irq(&group->lock); tmigr_handle_remote_cpu(remote_cpu, now, jif); diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 7af73ddc148d1d..b8e41ed4673c57 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -42,7 +42,7 @@ TORTURE_JITTER_STOP="" TORTURE_KCONFIG_KASAN_ARG="" TORTURE_KCONFIG_KCSAN_ARG="" TORTURE_KMAKE_ARG="" -TORTURE_QEMU_MEM=512 +TORTURE_QEMU_MEM=1024 torture_qemu_mem_default=1 TORTURE_REMOTE= TORTURE_SHUTDOWN_GRACE=180 |