Skip to content

Commit 5df2efa

Browse files
lifeixjren1
authored andcommitted
hv: timer: make the timer list be ordered
make the timer list be ordered to speed up expried timer process and next timer event finding. Add timer would not schedule timer unless it's the next timer event. Signed-off-by: Li, Fei1 <fei1.li@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
1 parent 6fc5116 commit 5df2efa

File tree

2 files changed

+67
-58
lines changed

2 files changed

+67
-58
lines changed

hypervisor/arch/x86/timer.c

Lines changed: 60 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -48,41 +48,6 @@ struct per_cpu_timers {
4848
static DEFINE_CPU_DATA(struct per_cpu_timers, cpu_timers);
4949
static DEFINE_CPU_DATA(struct dev_handler_node *, timer_node);
5050

51-
static struct timer *find_expired_timer(
52-
struct per_cpu_timers *cpu_timer,
53-
uint64_t tsc_now)
54-
{
55-
struct timer *timer = NULL, *tmp;
56-
struct list_head *pos;
57-
58-
list_for_each(pos, &cpu_timer->timer_list) {
59-
tmp = list_entry(pos, struct timer, node);
60-
if (tmp->fire_tsc <= tsc_now) {
61-
timer = tmp;
62-
break;
63-
}
64-
}
65-
66-
return timer;
67-
}
68-
69-
static struct timer *_search_nearest_timer(
70-
struct per_cpu_timers *cpu_timer)
71-
{
72-
struct timer *timer;
73-
struct timer *target = NULL;
74-
struct list_head *pos;
75-
76-
list_for_each(pos, &cpu_timer->timer_list) {
77-
timer = list_entry(pos, struct timer, node);
78-
if (target == NULL)
79-
target = timer;
80-
else if (timer->fire_tsc < target->fire_tsc)
81-
target = timer;
82-
}
83-
84-
return target;
85-
}
8651

8752
static void run_timer(struct timer *timer)
8853
{
@@ -100,30 +65,64 @@ static int tsc_deadline_handler(__unused int irq, __unused void *data)
10065
return 0;
10166
}
10267

103-
static inline void schedule_next_timer(struct per_cpu_timers *cpu_timer)
68+
static inline void update_physical_timer(struct per_cpu_timers *cpu_timer)
10469
{
105-
struct timer *timer;
70+
struct timer *timer = NULL;
71+
72+
/* find the next event timer */
73+
if (!list_empty(&cpu_timer->timer_list)) {
74+
timer = list_entry((&cpu_timer->timer_list)->next,
75+
struct timer, node);
10676

107-
timer = _search_nearest_timer(cpu_timer);
108-
if (timer) {
10977
/* it is okay to program a expired time */
11078
msr_write(MSR_IA32_TSC_DEADLINE, timer->fire_tsc);
11179
}
11280
}
11381

82+
static void __add_timer(struct per_cpu_timers *cpu_timer,
83+
struct timer *timer,
84+
bool *need_update)
85+
{
86+
struct list_head *pos, *prev;
87+
struct timer *tmp;
88+
uint64_t tsc = timer->fire_tsc;
89+
90+
prev = &cpu_timer->timer_list;
91+
list_for_each(pos, &cpu_timer->timer_list) {
92+
tmp = list_entry(pos, struct timer, node);
93+
if (tmp->fire_tsc < tsc)
94+
prev = &tmp->node;
95+
else
96+
break;
97+
}
98+
99+
list_add(&timer->node, prev);
100+
101+
if (need_update)
102+
/* update the physical timer if we're on the timer_list head */
103+
*need_update = (prev == &cpu_timer->timer_list);
104+
}
105+
114106
int add_timer(struct timer *timer)
115107
{
116108
struct per_cpu_timers *cpu_timer;
117109
int pcpu_id;
110+
bool need_update;
118111

119112
if (timer == NULL || timer->func == NULL || timer->fire_tsc == 0)
120113
return -EINVAL;
121114

115+
/* limit minimal periodic timer cycle period */
116+
if (timer->mode == TICK_MODE_PERIODIC)
117+
timer->period_in_cycle = max(timer->period_in_cycle,
118+
US_TO_TICKS(MIN_TIMER_PERIOD_US));
119+
122120
pcpu_id = get_cpu_id();
123121
cpu_timer = &per_cpu(cpu_timers, pcpu_id);
124-
list_add_tail(&timer->node, &cpu_timer->timer_list);
122+
__add_timer(cpu_timer, timer, &need_update);
125123

126-
schedule_next_timer(cpu_timer);
124+
if (need_update)
125+
update_physical_timer(cpu_timer);
127126

128127
TRACE_2L(TRACE_TIMER_ACTION_ADDED, timer->fire_tsc, 0);
129128
return 0;
@@ -212,35 +211,38 @@ int timer_softirq(int pcpu_id)
212211
{
213212
struct per_cpu_timers *cpu_timer;
214213
struct timer *timer;
215-
int max = MAX_TIMER_ACTIONS;
214+
struct list_head *pos, *n;
215+
int tries = MAX_TIMER_ACTIONS;
216+
uint64_t current_tsc = rdtsc();
216217

217218
/* handle passed timer */
218219
cpu_timer = &per_cpu(cpu_timers, pcpu_id);
219220

220221
/* This is to make sure we are not blocked due to delay inside func()
221222
* force to exit irq handler after we serviced >31 timers
222-
* caller used to add_timer() in timer->func(), if there is a delay
223+
* caller used to __add_timer() for periodic timer, if there is a delay
223224
* inside func(), it will infinitely loop here, because new added timer
224225
* already passed due to previously func()'s delay.
225226
*/
226-
timer = find_expired_timer(cpu_timer, rdtsc());
227-
while (timer && --max > 0) {
228-
del_timer(timer);
229-
230-
run_timer(timer);
231-
232-
if (timer->mode == TICK_MODE_PERIODIC) {
233-
timer->fire_tsc += max(timer->period_in_cycle,
234-
US_TO_TICKS(MIN_TIMER_PERIOD_US));
235-
add_timer(timer);
236-
}
237-
238-
/* search next one */
239-
timer = find_expired_timer(cpu_timer, rdtsc());
227+
list_for_each_safe(pos, n, &cpu_timer->timer_list) {
228+
timer = list_entry(pos, struct timer, node);
229+
/* timer expried */
230+
if (timer->fire_tsc <= current_tsc && --tries > 0) {
231+
del_timer(timer);
232+
233+
run_timer(timer);
234+
235+
if (timer->mode == TICK_MODE_PERIODIC) {
236+
/* update periodic timer fire tsc */
237+
timer->fire_tsc += timer->period_in_cycle;
238+
__add_timer(cpu_timer, timer, NULL);
239+
}
240+
} else
241+
break;
240242
}
241243

242244
/* update nearest timer */
243-
schedule_next_timer(cpu_timer);
245+
update_physical_timer(cpu_timer);
244246
return 0;
245247
}
246248

hypervisor/include/arch/x86/timer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ struct timer {
4848
void *priv_data; /* func private data */
4949
};
5050

51+
/*
52+
* Don't initialize a timer twice if it has been add to the timer list
53+
* after call add_timer. If u want, delete the timer from the list first.
54+
*/
5155
static inline void initialize_timer(struct timer *timer,
5256
timer_handle_t func,
5357
void *priv_data,
@@ -65,6 +69,9 @@ static inline void initialize_timer(struct timer *timer,
6569
}
6670
}
6771

72+
/*
73+
* Don't call add_timer/del_timer in the timer callback function.
74+
*/
6875
int add_timer(struct timer *timer);
6976
void del_timer(struct timer *timer);
7077

0 commit comments

Comments
 (0)