Skip to content

Commit 60bda03

Browse files
committed
posix-cpu-timers: Utilize timerqueue for storage
Using a linear O(N) search for timer insertion affects execution time and D-cache footprint badly with a larger number of timers. Switch the storage to a timerqueue which is already used for hrtimers and alarmtimers. It does not affect the size of struct k_itimer as it.alarm is still larger. The extra list head for the expiry list will go away later once the expiry is moved into task work context. Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Frederic Weisbecker <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 244d49e commit 60bda03

File tree

3 files changed

+155
-109
lines changed

3 files changed

+155
-109
lines changed

include/linux/posix-timers.h

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,11 @@
55
#include <linux/spinlock.h>
66
#include <linux/list.h>
77
#include <linux/alarmtimer.h>
8+
#include <linux/timerqueue.h>
89

910
struct kernel_siginfo;
1011
struct task_struct;
1112

12-
struct cpu_timer_list {
13-
struct list_head entry;
14-
u64 expires;
15-
struct task_struct *task;
16-
int firing;
17-
};
18-
1913
/*
2014
* Bit fields within a clockid:
2115
*
@@ -64,14 +58,58 @@ static inline int clockid_to_fd(const clockid_t clk)
6458

6559
#ifdef CONFIG_POSIX_TIMERS
6660

61+
/**
62+
* cpu_timer - Posix CPU timer representation for k_itimer
63+
* @node: timerqueue node to queue in the task/sig
64+
* @head: timerqueue head on which this timer is queued
65+
* @task: Pointer to target task
66+
* @elist: List head for the expiry list
67+
* @firing: Timer is currently firing
68+
*/
69+
struct cpu_timer {
70+
struct timerqueue_node node;
71+
struct timerqueue_head *head;
72+
struct task_struct *task;
73+
struct list_head elist;
74+
int firing;
75+
};
76+
77+
static inline bool cpu_timer_requeue(struct cpu_timer *ctmr)
78+
{
79+
return timerqueue_add(ctmr->head, &ctmr->node);
80+
}
81+
82+
static inline bool cpu_timer_enqueue(struct timerqueue_head *head,
83+
struct cpu_timer *ctmr)
84+
{
85+
ctmr->head = head;
86+
return timerqueue_add(head, &ctmr->node);
87+
}
88+
89+
static inline void cpu_timer_dequeue(struct cpu_timer *ctmr)
90+
{
91+
if (!RB_EMPTY_NODE(&ctmr->node.node))
92+
timerqueue_del(ctmr->head, &ctmr->node);
93+
}
94+
95+
static inline u64 cpu_timer_getexpires(struct cpu_timer *ctmr)
96+
{
97+
return ctmr->node.expires;
98+
}
99+
100+
static inline void cpu_timer_setexpires(struct cpu_timer *ctmr, u64 exp)
101+
{
102+
ctmr->node.expires = exp;
103+
}
104+
67105
/**
68106
* posix_cputimer_base - Container per posix CPU clock
69107
* @nextevt: Earliest-expiration cache
70-
* @cpu_timers: List heads to queue posix CPU timers
108+
* @tqhead: timerqueue head for cpu_timers
71109
*/
72110
struct posix_cputimer_base {
73111
u64 nextevt;
74-
struct list_head cpu_timers;
112+
struct timerqueue_head tqhead;
75113
};
76114

77115
/**
@@ -92,14 +130,10 @@ struct posix_cputimers {
92130

93131
static inline void posix_cputimers_init(struct posix_cputimers *pct)
94132
{
95-
pct->timers_active = 0;
96-
pct->expiry_active = 0;
133+
memset(pct, 0, sizeof(*pct));
97134
pct->bases[0].nextevt = U64_MAX;
98135
pct->bases[1].nextevt = U64_MAX;
99136
pct->bases[2].nextevt = U64_MAX;
100-
INIT_LIST_HEAD(&pct->bases[0].cpu_timers);
101-
INIT_LIST_HEAD(&pct->bases[1].cpu_timers);
102-
INIT_LIST_HEAD(&pct->bases[2].cpu_timers);
103137
}
104138

105139
void posix_cputimers_group_init(struct posix_cputimers *pct, u64 cpu_limit);
@@ -113,7 +147,6 @@ static inline void posix_cputimers_rt_watchdog(struct posix_cputimers *pct,
113147
/* Init task static initializer */
114148
#define INIT_CPU_TIMERBASE(b) { \
115149
.nextevt = U64_MAX, \
116-
.cpu_timers = LIST_HEAD_INIT(b.cpu_timers), \
117150
}
118151

119152
#define INIT_CPU_TIMERBASES(b) { \
@@ -182,7 +215,7 @@ struct k_itimer {
182215
struct {
183216
struct hrtimer timer;
184217
} real;
185-
struct cpu_timer_list cpu;
218+
struct cpu_timer cpu;
186219
struct {
187220
struct alarm alarmtimer;
188221
} alarm;

include/linux/timerqueue.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,16 @@ static inline void timerqueue_init(struct timerqueue_node *node)
4343
RB_CLEAR_NODE(&node->node);
4444
}
4545

46+
static inline bool timerqueue_node_queued(struct timerqueue_node *node)
47+
{
48+
return !RB_EMPTY_NODE(&node->node);
49+
}
50+
51+
static inline bool timerqueue_node_expires(struct timerqueue_node *node)
52+
{
53+
return node->expires;
54+
}
55+
4656
static inline void timerqueue_init_head(struct timerqueue_head *head)
4757
{
4858
head->rb_root = RB_ROOT_CACHED;

0 commit comments

Comments
 (0)