DPDK定时器学习笔记

定时器的启动流程

  • 调用rte_timer_subsystem_init初始化定时器子系统
  • 调用rte_timer_init初始化定时器结构体
  • 调用rte_timer_reset设定定时器的类型、周期、回调函数等
  • 调用rte_timer_manage检查已经超时的定时器,并触发相应的回调函数
  • 调用rte_timer_stop定时定时器

rte_timer

rte_timer是dpdk中定时器结构体,用于描述一个定时器。

struct rte_timer
{
    uint64_t expire;       /**定时器到期时间,以HZ来描述,到期后执行call back函数*/
    struct rte_timer *sl_next[MAX_SKIPLIST_DEPTH];
    volatile union rte_timer_status status; /**定时器状态*/
    uint64_t period;       /**定时器触发周期,0表示仅触发一次*/
    rte_timer_cb_t f;      /**call back函数*/
    void *arg;             /**call back函数参数*/
};

rte_timer_subsystem_init

定时器子系统初始化。

void rte_timer_subsystem_init(void)

rte_timer_init

初始化一个定时器。

void rte_timer_init(struct rte_timer *tim)

rte_timer_reset

重置并启动定时器,通过rte_timer_resetrte_timer设置参数。

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 : 定时器指针
- ticks : 定时器执行周期,以CPU HZ描述
- type : 定时器执行类型
- tim_lcore : 指定定时器的call back函数在哪个lcores
- rte_timer_cb_t : call back函数指针
- arg : call back函数参数

enum rte_timer_type

定时器触发方式

  • SINGLE : 仅触发一次,对应将rte_timer->period置0,定时器在触发后状态被置为RTE\_TIMER\_STOP,可通过调用rte\_timer\_reset再次启动。
  • PERIODICAL : 周期性触发,定时器在触发后状态被置为RTE\_TIMER\_PENDING,下一个周期会再次触发。
enum rte_timer_type {
    SINGLE,
    PERIODICAL
};

rte_timer_manage

rte_timer_manager用于查询所有到期的定时器,并执行call back函数。rte_timer_manager需要被周期性调用,调用的周期决定了定时器的精度。函数原型如下:

void rte_timer_manager (void)

rte_timer_stop

停止一个定时器。

int rte_timer_stop(struct rte_timer *tim)

定时器简单实例

/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright(c) 2010-2014 Intel Corporation
 */

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <sys/queue.h>

#include <rte_common.h>
#include <rte_memory.h>
#include <rte_launch.h>
#include <rte_eal.h>
#include <rte_per_lcore.h>
#include <rte_lcore.h>
#include <rte_cycles.h>
#include <rte_timer.h>
#include <rte_debug.h>

#define TIMER_RESOLUTION_CYCLES 20000000ULL /* around 10ms at 2 Ghz */

static struct rte_timer timer0;
static struct rte_timer timer1;

/* 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 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.
		 */
		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);

	/*
	* PERIODICAL : 定时器触发完了之后自动加载
	* SINGLE : 定时器仅触发一次
	*/
	/* load timer0, every second, on master lcore, reloaded automatically */
	hz = rte_get_timer_hz();//CPU的赫兹数,即每秒跳了多少次
	printf("hz : %llu\n", hz);
	lcore_id = rte_lcore_id();
	printf("timer0 reset in core %d\n", lcore_id);
	rte_timer_reset(&timer0, hz, PERIODICAL, lcore_id, timer0_cb, NULL);

	/* load timer1, every second/3, on next lcore, reloaded manually */
	lcore_id = rte_get_next_lcore(lcore_id, 0, 1);
	printf("timer1 reset in core %d\n", lcore_id);
	rte_timer_reset(&timer1, hz/3, SINGLE, lcore_id, timer1_cb, NULL);//可以看出定时器可以在一个核加载,在另一个核执行call back函数

	/* call lcore_mainloop() on every slave lcore */
	//RTE_LCORE_FOREACH_SLAVE只会历遍所有的slave核,不包括master核
	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
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值