在DPDK库中提供了一个timer模块,负责异步调用一些回调函数、定时操作等等,DPDK的精准定时是依靠hpet模块(和DPDK版本也有关系),在main()->rte_eal_init()->rte_eal_hpet_init()初始化。
hpet时钟支持:允许内核使用hpet,hpet是替代8524芯片的新一代定时器,i686及以上级别的主板都支持。
rte_eal_hpet_init()会去打开/dev/hpet设备文件描述符,并映射一块1024大小的内存空间,创建hpet_msb_inc线程(主要更新eal_hpet_msb全局变量)。比如rte_delay_us()会调用rte_get_hpet_cycles()获取全局变量eal_hpet_msb的值,去确定延时是否到达。
fd = open(DEV_HPET, O_RDONLY);
eal_hpet = mmap(NULL, 1024, PROT_READ, MAP_SHARED, fd, 0);
ret = pthread_create(&msb;_inc_thread_id, NULL, hpet_msb_inc, NULL);
static void
hpet_msb_inc(__attribute__((unused)) void *arg)
{
uint32_t t;
while (1) {
t = (eal_hpet->counter_l >> 30);
if (t != (eal_hpet_msb & 3))
eal_hpet_msb ++;
sleep(10);
}
}
返回值 |
操作函数 |
函数功能 |
uint64_t |
rte_get_tsc_hz (void) |
获得TSC的主频(即1s内多少个TSC cycle) |
static uint64_t |
rte_get_tsc_cycles (void) |
获得自从启动以来的TSC cycle数目 |
static uint64_t |
rte_get_timer_cycles (void) |
获得自从启动到现在的cylce次数 |
static uint64_t |
rte_get_timer_hz (void) |
获得CPU主频(1s多少个cycle) |
void |
rte_delay_us (unsigned us) |
等待至少N微秒 |
static void |
rte_delay_ms (unsigned ms) |
等待至少N毫秒 |
#include
#include <rte_debug.h>
#include <rte_atomic.h>
函数功能:等待至少ms毫秒。
函数功能:等待至少us微秒。
函数功能:获得自从启动到现在的cylce次数。
void
rte_delay_us(unsigned us)
{
const uint64_t start = rte_get_timer_cycles();
const uint64_t ticks = (uint64_t)us * rte_get_timer_hz() / 1E6;
while ((rte_get_timer_cycles() - start) < ticks)
rte_pause();
}
函数功能:获得CPU的主频(即1s 有多少个cycle),同系列CPU中,主频越高性能越好。
函数功能:获得自从启动以来的TSC cycle数目。
函数功能:获得TSC的主频(即1s内多少个TSC cycle),经测试和rte_get_timer_hz()结果一样。
TSC是一个64位的时间戳计数器寄存器,汇编指令rdtsc读这个寄存器,Linux在初始化时系统时必须确定时钟信号的频率。
备注:rte_rdtsc()函数用来获取时间戳计数器。
const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US;
= rte_get_tsc_hz()/1000000*100
= 2300*100
while (1) {
cur_tsc = rte_rdtsc();
diff_tsc = cur_tsc - prev_tsc;
//cur_tsc = 57987057930424634,
//prev_tsc = 57987057928124602,
//drain_tsc = 230000
//rte_get_tsc_hz() = 2299999318~2300MHz
if (unlikely(diff_tsc > drain_tsc * 10)) { // rte_get_tsc_hz()/1000~1ms
adns_log_flush();
prev_tsc = cur_tsc;
}
//cur_tsc = 57987769897251014, prev2_tsc = 57987765297251934,
//(cur_tsc-pre_tsc)/ rte_get_tsc_hz()=经历的秒数
//drain_tsc = 230000~2300*100
//rte_get_tsc_hz() = 2299999526~2300MHz
//rte_get_timer_hz = 2299999526~2300MHz
diff_tsc = cur_tsc - prev2_tsc;
if (unlikely(diff_tsc > 2*rte_get_tsc_hz())) { // 2s
cpu_utili_process();
prev2_tsc = cur_tsc;
}
}
#cat /proc/cpuinfo | grep "cpu MHz"
hpet介绍:
http://blog.csdn.net/linzhaolover/article/details/9302655
cycleAPI: