dpdk基础教程——定时器学习

一、了解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:取值PERIODICALSINGLE
    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上的定时器

你可能感兴趣的:(DPDK入门教程)