Disclaimer: This document is only for learning and exchange, do not use for other commercial purposes author: Chaoyang _tony
E-mail:linzhaolover@gmail.com
Create date:2013-7-22 17:36:51 Monday
Last change:2013-7-23 11:04:07 Tuesday
Reprint please indicate the source: Http://blog.csdn.net/linzhaolove
This article in the source code can go to http://dpdk.org/dev web page download; More official documents please visit http://dpdk.org
Module Detailed Introduction
A timer module is provided in the DPDK library, which is responsible for calling some callback functions asynchronously, timing operation and so on.
I explained the example module Dpdk/examples/timer provided by DPDK, 1, Timer initialization 1, initialization Hpet module
The first involves the initialization of the Hpet module, the precise timing of the DPDK is dependent on the Hpet module,
In Main ()->rte_eal_init ()->rte_eal_hpet_init () Invoke Rte_eal_hpet_init () to initialize, for detailed initialization of Hpet in DPDK see the article I wrote earlier http:// blog.csdn.net/linzhaolove/article/details/9302655 2), initialization timer subsystem
Call Rte_timer_subsystem_init to initialize the timer module; The function is in the dpdk/lib/librte_timer/rte_timer.c file;
/* Init RTE Timer Library * *
rte_timer_subsystem_init ();
Let's take a look at Rte_timer_subsystem_init's source code;
for (lcore_id = 0; lcore_id < Rte_max_lcore; lcore_id + +) {
list_init (&priv_timer[lcore_id].pending);
List_init (&priv_timer[lcore_id].expired);
List_init (&priv_timer[lcore_id].done);
Rte_spinlock_init (&priv_timer[lcore_id].list_lock);
Priv_timer[lcore_id].prev_lcore = lcore_id;
}
He initialized three lists on each logical core, respectively, pending, Expired,done, initialized a spin lock list_lock;
/* INIT Timer Structures * *
rte_timer_init (&TIMER0);
Rte_timer_init (&timer1);
Initialization of two structures is Timer0 timer1, we want to use two timers;
Setting the state of the timer in the Rte_timer_init function; timer stop state, no host;
Status.state = Rte_timer_stop;
Status.owner = Rte_timer_no_owner;
Tim->status.u32 = status.u32;
Gets the Hpet clock tick, which is a second value;
Hz = Rte_get_hpet_hz ();
2, start timer 1), the start of the timer
lcore_id = rte_lcore_id ();
Rte_timer_reset (&timer0, Hz, periodical, lcore_id, TIMER0_CB, NULL);
Get the core ID of the current thread through the rte_lcore_id () function, and then start the timer through the Rte_timer_reset function;
Let's take a look at the parameters of the Rte_timer_reset () function,
TIMER0 is the initial structure above us;
Hz is the time fixed to the timer;
Periodical is the meaning of the cycle, and this timer is only initialized once, then cycle;
lcore_id Core ID, is to specify this timer to run on that core;
TIMER0_CB is the address of the callback function that we set the timer to after the call;
Null is the parameter passed to the callback function that we are not using for the time being, so the pass is null.
/* Load timer1, every SECOND/3, on next Lcore, reloaded manually
/lcore_id = Rte_get_next_lcore (lcore_id, 0, 1);
rte_timer_reset (&timer1, HZ/3, single, lcore_id, TIMER1_CB, NULL);
Next is the initialization of another timer timer1, which is HZ/3 with a timer of 1 seconds, and a single is only executed once, and if you want it to run again, you need to initialize it again;
2), scheduling management of the timer
/* 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);
In addition to calling Lcore_mainloop () at the main core, it also requires each of the other core calls; in the inside to manage the clock; Because at the start of initialization, each core initializes three lists and an independent spin lock;
Let's look at a lcore_mainloop () internal source code;
CUR_TSC = RTE_RDTSC ();
DIFF_TSC = CUR_TSC-PREV_TSC;
if (Diff_tsc > Timer_resolution_cycles) {
rte_timer_manage ();
PREV_TSC = CUR_TSC;
}
The function will be scheduled every 10ms, so that rte_timer_manage () to manage the current core timer ';
#define Timer_resolution_cycles 20000000ULL/* around 10ms at 2 Ghz * *
This clock resolution should be your CPU hertz, you can use to/proc/cpuinfo to see, remember to last multiply 10, want 10ms query once;
# Cat/proc/cpuinfo | GREP cpu MHz CPU MHz: 2793.000 cpu MHz: 2793.000 cpu MHz : 2793.000
3. Stop Timer
1), the stop of the periodic timer
At the start of the TIMER0, we are using a periodic timer, the current callback function is TIMER0_CB ();
Let me take a look at the source code of the TIMER0_CB function;
/* This timer are automatically reloaded until we decide
to * stop it, when counter reaches
/if (counter + +) =
Rte_timer_stop (TIM);
The source code annotation writes very clearly, when this callback function is executed 20 times, will be stopped, calls the Rte_timer_stop () function;
A brief introduction is how to stop a timer, see Rte_timer_stop () source;
ret = Timer_set_config_state (Tim, &prev_status);
First, the timer is placed in the configuration state;
Timer_del (Tim, Prev_status.owner, 0);
Second, remove it from the list;
Status.state = Rte_timer_stop;
Status.owner = Rte_timer_no_owner;
Tim->status.u32 = status.u32;
Finally, the state is changed to stop State;
2), a single timer reboot
Once the timer was finished once, I stopped, so I said how it could be restarted;
When we start the timer, we pass a parameter single, which means that the timer executes once on a core and then stops;
The callback function for the current start call is TIMER1_CB ()
Once again in the TIMER1_CB function Rte_timer_reset can start the timer,
/* Reload it on another lcore
/Hz = Rte_get_hpet_hz ();
lcore_id = Rte_get_next_lcore (lcore_id, 0, 1);
Rte_timer_reset (Tim, HZ/3, single, lcore_id, TIMER1_CB, NULL);
But note that this is the passing of the lcore_id, not its own core_id, but through the Rte_get_next_lcore () to obtain another enabling core ID, from this can be explained that DPDK timer, can be from a core On the other core on the start of the timer;
Module test
In the start Timer TIMER0, set is 1 seconds to call once, I want to be the exact or not, the visual certainly not, can only be a rough code test; 1. Add Test Code
I'm using the Clock_gettime () function to get the time to fetch every call TIMER0_CB, but with the Clock_gettime () function, add-LRT to the link library at compile time;
Add header File
#include <unistd.h>
#include <time.h>
Add the following code in TIMER0_CB
struct Timespec clock_time;
Clock_gettime (Clock_realtime, &clock_time);
fprintf (stdout, "clock_time.tv_sec =%lu tv_nsec =%lu\n", clock_time.tv_sec,clock_time.tv_nsec);
Add compilation link
Open the Examples/timer/makefile file and add the compilation link below, "ldlibs + =-LRT" For example:
Cflags +-o3
cflags + = $ (werror_flags)
#add linzh ldlibs
+ =-LRT
2. Compile test
Make-c x86_64-default-linuxapp-gcc/
make-c examples/timer/
Test
./examples/helloworld/build/app/helloworld-c 1f-n 4--proc-type=auto
Production look at the printing information, we mainly look at the value of clock_time.tv_sec, found that basically a second print once;
Clock_time.tv_sec = 1374494900 tv_nsec =514227370
TIMER0_CB () on Lcore 0
clock_time.tv_sec = 1374494901 Tv_nsec = 519700272
TIMER0_CB () on Lcore 0
clock_time.tv_sec = 1374494902 tv_nsec =525173801
TIMER0_CB () on Lcore 0
Technology needs to be improved, if the article has the wrong place to want the reader to correct, mutual exchange, learn from each other; O (∩_∩) o~