Skip to content

Commit 5fa75a4

Browse files
committed
posix-timers: Avoid false cacheline sharing
struct k_itimer has the hlist_node, which is used for lookup in the hash bucket, and the timer lock in the same cache line. That's obviously bad, if one CPU fiddles with a timer and the other is walking the hash bucket on which that timer is queued. Avoid this by restructuring struct k_itimer, so that the read mostly (only modified during setup and teardown) fields are in the first cache line and the lock and the rest of the fields which get written to are in cacheline 2-N. Reduces cacheline contention in a test case of 64 processes creating and accessing 20000 timers each by almost 30% according to perf. Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Frederic Weisbecker <[email protected]> Link: https://lore.kernel.org/all/[email protected]
1 parent 781764e commit 5fa75a4

File tree

2 files changed

+14
-11
lines changed

2 files changed

+14
-11
lines changed

include/linux/posix-timers.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -177,23 +177,26 @@ static inline void posix_cputimers_init_work(void) { }
177177
* @rcu: RCU head for freeing the timer.
178178
*/
179179
struct k_itimer {
180-
struct hlist_node list;
181-
struct hlist_node ignored_list;
180+
/* 1st cacheline contains read-mostly fields */
182181
struct hlist_node t_hash;
183-
spinlock_t it_lock;
184-
const struct k_clock *kclock;
185-
clockid_t it_clock;
182+
struct hlist_node list;
186183
timer_t it_id;
184+
clockid_t it_clock;
185+
int it_sigev_notify;
186+
enum pid_type it_pid_type;
187+
struct signal_struct *it_signal;
188+
const struct k_clock *kclock;
189+
190+
/* 2nd cacheline and above contain fields which are modified regularly */
191+
spinlock_t it_lock;
187192
int it_status;
188193
bool it_sig_periodic;
189194
s64 it_overrun;
190195
s64 it_overrun_last;
191196
unsigned int it_signal_seq;
192197
unsigned int it_sigqueue_seq;
193-
int it_sigev_notify;
194-
enum pid_type it_pid_type;
195198
ktime_t it_interval;
196-
struct signal_struct *it_signal;
199+
struct hlist_node ignored_list;
197200
union {
198201
struct pid *it_pid;
199202
struct task_struct *it_process;
@@ -210,7 +213,7 @@ struct k_itimer {
210213
} alarm;
211214
} it;
212215
struct rcu_head rcu;
213-
};
216+
} ____cacheline_aligned_in_smp;
214217

215218
void run_posix_cpu_timers(void);
216219
void posix_cpu_timers_exit(struct task_struct *task);

kernel/time/posix-timers.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,8 @@ static int posix_get_hrtimer_res(clockid_t which_clock, struct timespec64 *tp)
260260

261261
static __init int init_posix_timers(void)
262262
{
263-
posix_timers_cache = kmem_cache_create("posix_timers_cache", sizeof(struct k_itimer), 0,
264-
SLAB_ACCOUNT, NULL);
263+
posix_timers_cache = kmem_cache_create("posix_timers_cache", sizeof(struct k_itimer),
264+
__alignof__(struct k_itimer), SLAB_ACCOUNT, NULL);
265265
return 0;
266266
}
267267
__initcall(init_posix_timers);

0 commit comments

Comments
 (0)