eal: add nanosleep based delay function

Add a new rte_delay_us_sleep() function that uses nanosleep().
This function can be used by applications to not implement
their own nanosleep() based callback and by internal DPDK
code if CPU non-blocking delay needed.

Signed-off-by: Ilya Maximets <i.maximets@samsung.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
This commit is contained in:
Ilya Maximets 2018-10-10 17:12:19 +03:00 committed by Ferruh Yigit
parent b9788afec5
commit a51639cc72
6 changed files with 81 additions and 15 deletions

View File

@ -7,9 +7,11 @@
#include <unistd.h> #include <unistd.h>
#include <inttypes.h> #include <inttypes.h>
#include <sys/types.h> #include <sys/types.h>
#include <time.h>
#include <errno.h> #include <errno.h>
#include <rte_common.h> #include <rte_common.h>
#include <rte_compat.h>
#include <rte_log.h> #include <rte_log.h>
#include <rte_cycles.h> #include <rte_cycles.h>
#include <rte_pause.h> #include <rte_pause.h>
@ -31,6 +33,28 @@ rte_delay_us_block(unsigned int us)
rte_pause(); rte_pause();
} }
void __rte_experimental
rte_delay_us_sleep(unsigned int us)
{
struct timespec wait[2];
int ind = 0;
wait[0].tv_sec = 0;
if (us >= US_PER_S) {
wait[0].tv_sec = us / US_PER_S;
us -= wait[0].tv_sec * US_PER_S;
}
wait[0].tv_nsec = 1000 * us;
while (nanosleep(&wait[ind], &wait[1 - ind]) && errno == EINTR) {
/*
* Sleep was interrupted. Flip the index, so the 'remainder'
* will become the 'request' for a next call.
*/
ind = 1 - ind;
}
}
uint64_t uint64_t
rte_get_tsc_hz(void) rte_get_tsc_hz(void)
{ {

View File

@ -13,6 +13,7 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <rte_compat.h>
#include <rte_debug.h> #include <rte_debug.h>
#include <rte_atomic.h> #include <rte_atomic.h>
@ -157,6 +158,16 @@ rte_delay_ms(unsigned ms)
*/ */
void rte_delay_us_block(unsigned int us); void rte_delay_us_block(unsigned int us);
/**
* Delay function that uses system sleep.
* Does not block the CPU core.
*
* @param us
* Number of microseconds to wait.
*/
void __rte_experimental
rte_delay_us_sleep(unsigned int us);
/** /**
* Replace rte_delay_us with user defined function. * Replace rte_delay_us with user defined function.
* *

View File

@ -273,6 +273,7 @@ EXPERIMENTAL {
rte_class_register; rte_class_register;
rte_class_unregister; rte_class_unregister;
rte_ctrl_thread_create; rte_ctrl_thread_create;
rte_delay_us_sleep;
rte_dev_event_callback_process; rte_dev_event_callback_process;
rte_dev_event_callback_register; rte_dev_event_callback_register;
rte_dev_event_callback_unregister; rte_dev_event_callback_unregister;

View File

@ -278,6 +278,12 @@
"Func": default_autotest, "Func": default_autotest,
"Report": None, "Report": None,
}, },
{
"Name": "Sleep delay",
"Command": "delay_us_sleep_autotest",
"Func": default_autotest,
"Report": None,
},
{ {
"Name": "Rawdev autotest", "Name": "Rawdev autotest",
"Command": "rawdev_autotest", "Command": "rawdev_autotest",

View File

@ -149,6 +149,7 @@ test_names = [
'cryptodev_octeontx_autotest', 'cryptodev_octeontx_autotest',
'cycles_autotest', 'cycles_autotest',
'debug_autotest', 'debug_autotest',
'delay_us_sleep_autotest',
'devargs_autotest', 'devargs_autotest',
'distributor_autotest', 'distributor_autotest',
'distributor_perf_autotest', 'distributor_perf_autotest',

View File

@ -23,6 +23,30 @@
* of cycles is correct with regard to the frequency of the timer. * of cycles is correct with regard to the frequency of the timer.
*/ */
static int
check_wait_one_second(void)
{
uint64_t cycles, prev_cycles;
uint64_t hz = rte_get_timer_hz();
uint64_t max_inc = (hz / 100); /* 10 ms max between 2 reads */
/* check that waiting 1 second is precise */
prev_cycles = rte_get_timer_cycles();
rte_delay_us(1000000);
cycles = rte_get_timer_cycles();
if ((uint64_t)(cycles - prev_cycles) > (hz + max_inc)) {
printf("delay_us is not accurate: too long\n");
return -1;
}
if ((uint64_t)(cycles - prev_cycles) < (hz - max_inc)) {
printf("delay_us is not accurate: too short\n");
return -1;
}
return 0;
}
static int static int
test_cycles(void) test_cycles(void)
{ {
@ -43,25 +67,24 @@ test_cycles(void)
prev_cycles = cycles; prev_cycles = cycles;
} }
/* check that waiting 1 second is precise */ return check_wait_one_second();
prev_cycles = rte_get_timer_cycles();
rte_delay_us(1000000);
cycles = rte_get_timer_cycles();
if ((uint64_t)(cycles - prev_cycles) > (hz + max_inc)) {
printf("delay_us is not accurate: too long\n");
return -1;
}
if ((uint64_t)(cycles - prev_cycles) < (hz - max_inc)) {
printf("delay_us is not accurate: too short\n");
return -1;
}
return 0;
} }
REGISTER_TEST_COMMAND(cycles_autotest, test_cycles); REGISTER_TEST_COMMAND(cycles_autotest, test_cycles);
/*
* One second precision test with rte_delay_us_sleep.
*/
static int
test_delay_us_sleep(void)
{
rte_delay_us_callback_register(rte_delay_us_sleep);
return check_wait_one_second();
}
REGISTER_TEST_COMMAND(delay_us_sleep_autotest, test_delay_us_sleep);
/* /*
* rte_delay_us_callback test * rte_delay_us_callback test
* *