一、了解dpdk timer api函数
二、通读走读timer例子代码,加深对timer api的理解
三、使用时需要注意的地方
1.1 初始化dpdk定时器库
1.void rte_timer_subsystem_init ( void )
功能:初始化dpdk定时器库,初始化内部变量(链表和锁)
1.2 初始化timer定时器
void rte_timer_init ( struct rte_timer * tim )
参数tim:带初始化的timer
1.3 启动定时器
int rte_timer_reset ( struct rte_timer * tim,
uint64_t ticks,
enum rte_timer_type type,
unsigned tim_lcore,
rte_timer_cb_t fct,
void * arg
)
功能:启动或者重置定时器,当定时器经过一定时间间隔超时后,会在tim_lcore指定的core上调用fct函数,函数参数是arg。
如果timer当前处于运行状态(Running),函数会调用失败,所以应检查函数返回值查看timer是否处于运行状态
如果timer在其他core上被设置,即(CONFIG 状态),函数也返回失败。
参数time:timer句柄
参数ticks:超时时间,参考rte_get_hpet_hz()的使用
参数type:取值PERIODICAL或SINGLE
PERIODICAL:定时器触发,并执行后自动加载
SINGLE:定时器仅仅触发一次。执行后进入STOPPED 状态
参数tim_lcore:指定这个定时器回调函数在哪个core上面运行;,如果tim_lcore 值为LCORE_ID_ANY,则以轮询方式在不同的核上执行回调函数。
参数fct:定时器回调函数
参数arg:回调函数的参数
1.4 定时器调度和管理
rte_timer_manage();
管理定时器链表,执行定时器回调函数
这个函数必须在EAL core的main_loop()函数中调用。它浏览挂起的timer,然后执行已经超时的定时器。
定时器的精度取决于这个函数的调用次序。
1.5 停止定时器
rte_timer_stop停止定时器
2.x timer例子代码分析
/* timer0 callback */
static void
timer0_cb(__attribute__((unused)) struct rte_timer *tim,
__attribute__((unused)) void *arg)
{
static unsigned counter = 0;
unsigned lcore_id = rte_lcore_id();
printf("%s() on lcore %u\n", __func__, lcore_id);
/* this timer is automatically reloaded until we decide to
* stop it, when counter reaches 20. */
if ((counter ++) == 20)
rte_timer_stop(tim);
}
timer1定时器,我们传递了一个参数SINGLE,就是指让这个定时器在某个core上执行一次,然后停止;
当前启动调用的回调函数是timer1_cb()
在timer1_cb函数中再次执行一次rte_timer_reset就可以启动定时器,
/* timer1 callback */
static void
timer1_cb(__attribute__((unused)) struct rte_timer *tim,
__attribute__((unused)) void *arg)
{
unsigned lcore_id = rte_lcore_id();
uint64_t hz;
printf("%s() on lcore %u\n", __func__, lcore_id);
/* reload it on another lcore */
hz = rte_get_timer_hz();
lcore_id = rte_get_next_lcore(lcore_id, 0, 1);
rte_timer_reset(tim, hz/3, SINGLE, lcore_id, timer1_cb, NULL);
}
static __attribute__((noreturn)) int
lcore_mainloop(__attribute__((unused)) void *arg)
{
uint64_t prev_tsc = 0, cur_tsc, diff_tsc;
unsigned lcore_id;
lcore_id = rte_lcore_id();
printf("Starting mainloop on core %u\n", lcore_id);
while (1) {
/*
* Call the timer handler on each core: as we don't
* need a very precise timer, so only call
* rte_timer_manage() every ~10ms (at 2Ghz). In a real
* application, this will enhance performances as
* reading the HPET timer is not efficient.
*/
//函数中会每10ms执行一次调度,让rte_timer_manage()管理当前core上的定时器,rte_timer_manage函数必须调用,否则timer定时器不会运行
cur_tsc = rte_rdtsc();
diff_tsc = cur_tsc - prev_tsc;
if (diff_tsc > TIMER_RESOLUTION_CYCLES) {
rte_timer_manage();
prev_tsc = cur_tsc;
}
}
}
int
main(int argc, char **argv)
{
int ret;
uint64_t hz;
unsigned lcore_id;
/* init EAL */
ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_panic("Cannot init EAL\n");
/* init RTE timer library */
rte_timer_subsystem_init();
/* init timer structures */
rte_timer_init(&timer0);
rte_timer_init(&timer1);
/* load timer0, every second, on master lcore, reloaded automatically */
hz = rte_get_timer_hz();
lcore_id = rte_lcore_id();
rte_timer_reset(&timer0, hz, PERIODICAL, lcore_id, timer0_cb, NULL);
/* load timer1, every second/3, on next lcore, reloaded manually */
//初始化的另一个定时器timer1;这用hz/3 是指定时只有1秒的三分之一;SINGLE是指只执行一次,如想让它再运行就需要从新初始化它;
lcore_id = rte_get_next_lcore(lcore_id, 0, 1);
rte_timer_reset(&timer1, hz/3, SINGLE, lcore_id, timer1_cb, NULL);
/* call lcore_mainloop() on every slave lcore */
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
rte_eal_remote_launch(lcore_mainloop, NULL, lcore_id);
}
/* call it on master lcore too */
(void) lcore_mainloop(NULL);
return 0;
}
注意事项:
1.不管是slave core还是master core,rte_timer_manage函数必须调用,否则timer定时器不会运行
2.一个core上不能同时运行两个以上,PERIODICAL类型的定时器
3.一个core能同时运行两个,SINGLE类型的单次定时器
4.可以在一个core上,启动另一个core上的定时器