@ -6,61 +6,60 @@
# include <zephyr/ztest.h>
# include <zephyr/ztest.h>
# include <zephyr/timing/timing.h>
# include <zephyr/timing/timing.h>
# include <zephyr/rtio/rtio_spsc.h>
# include <zephyr/sys/spsc_lockfree.h>
# include "rtio_api.h"
/*
/*
* @ brief Produce and Consume a single uint32_t in the same execution context
* @ brief Produce and Consume a single uint32_t in the same execution context
*
*
* @ see rtio_ spsc_acquire( ) , rtio_ spsc_produce( ) , rtio_ spsc_consume( ) , rtio_ spsc_release( )
* @ see spsc_acquire ( ) , spsc_produce ( ) , spsc_consume ( ) , spsc_release ( )
*
*
* @ ingroup rtio_ tests
* @ ingroup tests
*/
*/
ZTEST ( rtio_ spsc, test_produce_consume_size1 )
ZTEST ( spsc , test_produce_consume_size1 )
{
{
RTIO_ SPSC_DEFINE( ezspsc , uint32_t , 1 ) ;
SPSC_DEFINE ( ezspsc , uint32_t , 1 ) ;
const uint32_t magic = 43219876 ;
const uint32_t magic = 43219876 ;
uint32_t * acq = rtio_ spsc_acquire( & ezspsc ) ;
uint32_t * acq = spsc_acquire ( & ezspsc ) ;
zassert_not_null ( acq , " Acquire should succeed " ) ;
zassert_not_null ( acq , " Acquire should succeed " ) ;
* acq = magic ;
* acq = magic ;
uint32_t * acq2 = rtio_ spsc_acquire( & ezspsc ) ;
uint32_t * acq2 = spsc_acquire ( & ezspsc ) ;
zassert_is_null ( acq2 , " Acquire should fail " ) ;
zassert_is_null ( acq2 , " Acquire should fail " ) ;
uint32_t * cons = rtio_ spsc_consume( & ezspsc ) ;
uint32_t * cons = spsc_consume ( & ezspsc ) ;
zassert_is_null ( cons , " Consume should fail " ) ;
zassert_is_null ( cons , " Consume should fail " ) ;
zassert_equal ( rtio_ spsc_consumable( & ezspsc ) , 0 , " Consumables should be 0 " ) ;
zassert_equal ( spsc_consumable ( & ezspsc ) , 0 , " Consumables should be 0 " ) ;
rtio_ spsc_produce( & ezspsc ) ;
spsc_produce ( & ezspsc ) ;
zassert_equal ( rtio_ spsc_consumable( & ezspsc ) , 1 , " Consumables should be 1 " ) ;
zassert_equal ( spsc_consumable ( & ezspsc ) , 1 , " Consumables should be 1 " ) ;
uint32_t * cons2 = rtio_ spsc_consume( & ezspsc ) ;
uint32_t * cons2 = spsc_consume ( & ezspsc ) ;
zassert_equal ( rtio_ spsc_consumable( & ezspsc ) , 0 , " Consumables should be 0 " ) ;
zassert_equal ( spsc_consumable ( & ezspsc ) , 0 , " Consumables should be 0 " ) ;
zassert_not_null ( cons2 , " Consume should not fail " ) ;
zassert_not_null ( cons2 , " Consume should not fail " ) ;
zassert_equal ( * cons2 , magic , " Consume value should equal magic " ) ;
zassert_equal ( * cons2 , magic , " Consume value should equal magic " ) ;
uint32_t * cons3 = rtio_ spsc_consume( & ezspsc ) ;
uint32_t * cons3 = spsc_consume ( & ezspsc ) ;
zassert_is_null ( cons3 , " Consume should fail " ) ;
zassert_is_null ( cons3 , " Consume should fail " ) ;
uint32_t * acq3 = rtio_ spsc_acquire( & ezspsc ) ;
uint32_t * acq3 = spsc_acquire ( & ezspsc ) ;
zassert_is_null ( acq3 , " Acquire should not succeed " ) ;
zassert_is_null ( acq3 , " Acquire should not succeed " ) ;
rtio_ spsc_release( & ezspsc ) ;
spsc_release ( & ezspsc ) ;
uint32_t * acq4 = rtio_ spsc_acquire( & ezspsc ) ;
uint32_t * acq4 = spsc_acquire ( & ezspsc ) ;
zassert_not_null ( acq4 , " Acquire should succeed " ) ;
zassert_not_null ( acq4 , " Acquire should succeed " ) ;
}
}
@ -69,34 +68,34 @@ ZTEST(rtio_spsc, test_produce_consume_size1)
* @ brief Produce and Consume 3 items at a time in a spsc of size 4 to validate masking
* @ brief Produce and Consume 3 items at a time in a spsc of size 4 to validate masking
* and wrap around reads / writes .
* and wrap around reads / writes .
*
*
* @ see rtio_ spsc_acquire( ) , rtio_ spsc_produce( ) , rtio_ spsc_consume( ) , rtio_ spsc_release( )
* @ see spsc_acquire ( ) , spsc_produce ( ) , spsc_consume ( ) , spsc_release ( )
*
*
* @ ingroup rtio_ tests
* @ ingroup tests
*/
*/
ZTEST ( rtio_ spsc, test_produce_consume_wrap_around )
ZTEST ( spsc , test_produce_consume_wrap_around )
{
{
RTIO_ SPSC_DEFINE( ezspsc , uint32_t , 4 ) ;
SPSC_DEFINE ( ezspsc , uint32_t , 4 ) ;
for ( int i = 0 ; i < 10 ; i + + ) {
for ( int i = 0 ; i < 10 ; i + + ) {
zassert_equal ( rtio_ spsc_consumable( & ezspsc ) , 0 , " Consumables should be 0 " ) ;
zassert_equal ( spsc_consumable ( & ezspsc ) , 0 , " Consumables should be 0 " ) ;
for ( int j = 0 ; j < 3 ; j + + ) {
for ( int j = 0 ; j < 3 ; j + + ) {
uint32_t * entry = rtio_ spsc_acquire( & ezspsc ) ;
uint32_t * entry = spsc_acquire ( & ezspsc ) ;
zassert_not_null ( entry , " Acquire should succeed " ) ;
zassert_not_null ( entry , " Acquire should succeed " ) ;
* entry = i * 3 + j ;
* entry = i * 3 + j ;
rtio_ spsc_produce( & ezspsc ) ;
spsc_produce ( & ezspsc ) ;
}
}
zassert_equal ( rtio_ spsc_consumable( & ezspsc ) , 3 , " Consumables should be 3 " ) ;
zassert_equal ( spsc_consumable ( & ezspsc ) , 3 , " Consumables should be 3 " ) ;
for ( int k = 0 ; k < 3 ; k + + ) {
for ( int k = 0 ; k < 3 ; k + + ) {
uint32_t * entry = rtio_ spsc_consume( & ezspsc ) ;
uint32_t * entry = spsc_consume ( & ezspsc ) ;
zassert_not_null ( entry , " Consume should succeed " ) ;
zassert_not_null ( entry , " Consume should succeed " ) ;
zassert_equal ( * entry , i * 3 + k , " Consume value should equal i*3+k " ) ;
zassert_equal ( * entry , i * 3 + k , " Consume value should equal i*3+k " ) ;
rtio_ spsc_release( & ezspsc ) ;
spsc_release ( & ezspsc ) ;
}
}
zassert_equal ( rtio_ spsc_consumable( & ezspsc ) , 0 , " Consumables should be 0 " ) ;
zassert_equal ( spsc_consumable ( & ezspsc ) , 0 , " Consumables should be 0 " ) ;
}
}
}
}
@ -107,28 +106,28 @@ ZTEST(rtio_spsc, test_produce_consume_wrap_around)
* Done by setting all values to UINTPTR_MAX - 2 and writing and reading enough
* Done by setting all values to UINTPTR_MAX - 2 and writing and reading enough
* to ensure integer wraps occur .
* to ensure integer wraps occur .
*/
*/
ZTEST ( rtio_ spsc, test_int_wrap_around )
ZTEST ( spsc , test_int_wrap_around )
{
{
RTIO_ SPSC_DEFINE( ezspsc , uint32_t , 4 ) ;
SPSC_DEFINE ( ezspsc , uint32_t , 4 ) ;
ezspsc . _spsc . in = ATOMIC_INIT ( UINTPTR_MAX - 2 ) ;
ezspsc . _spsc . in = ATOMIC_INIT ( UINTPTR_MAX - 2 ) ;
ezspsc . _spsc . out = ATOMIC_INIT ( UINTPTR_MAX - 2 ) ;
ezspsc . _spsc . out = ATOMIC_INIT ( UINTPTR_MAX - 2 ) ;
for ( int j = 0 ; j < 3 ; j + + ) {
for ( int j = 0 ; j < 3 ; j + + ) {
uint32_t * entry = rtio_ spsc_acquire( & ezspsc ) ;
uint32_t * entry = spsc_acquire ( & ezspsc ) ;
zassert_not_null ( entry , " Acquire should succeed " ) ;
zassert_not_null ( entry , " Acquire should succeed " ) ;
* entry = j ;
* entry = j ;
rtio_ spsc_produce( & ezspsc ) ;
spsc_produce ( & ezspsc ) ;
}
}
zassert_equal ( atomic_get ( & ezspsc . _spsc . in ) , UINTPTR_MAX + 1 , " Spsc in should wrap " ) ;
zassert_equal ( atomic_get ( & ezspsc . _spsc . in ) , UINTPTR_MAX + 1 , " Spsc in should wrap " ) ;
for ( int k = 0 ; k < 3 ; k + + ) {
for ( int k = 0 ; k < 3 ; k + + ) {
uint32_t * entry = rtio_ spsc_consume( & ezspsc ) ;
uint32_t * entry = spsc_consume ( & ezspsc ) ;
zassert_not_null ( entry , " Consume should succeed " ) ;
zassert_not_null ( entry , " Consume should succeed " ) ;
zassert_equal ( * entry , k , " Consume value should equal i*3+k " ) ;
zassert_equal ( * entry , k , " Consume value should equal i*3+k " ) ;
rtio_ spsc_release( & ezspsc ) ;
spsc_release ( & ezspsc ) ;
}
}
zassert_equal ( atomic_get ( & ezspsc . _spsc . out ) , UINTPTR_MAX + 1 , " Spsc out should wrap " ) ;
zassert_equal ( atomic_get ( & ezspsc . _spsc . out ) , UINTPTR_MAX + 1 , " Spsc out should wrap " ) ;
@ -137,14 +136,14 @@ ZTEST(rtio_spsc, test_int_wrap_around)
# define MAX_RETRIES 5
# define MAX_RETRIES 5
# define SMP_ITERATIONS 100
# define SMP_ITERATIONS 100
RTIO_ SPSC_DEFINE( spsc , uint32_t , 4 ) ;
SPSC_DEFINE ( spsc , uint32_t , 4 ) ;
static void t1_consume ( void * p1 , void * p2 , void * p3 )
static void t1_consume ( void * p1 , void * p2 , void * p3 )
{
{
ARG_UNUSED ( p2 ) ;
ARG_UNUSED ( p2 ) ;
ARG_UNUSED ( p3 ) ;
ARG_UNUSED ( p3 ) ;
struct rtio_ spsc_spsc * ezspsc = p1 ;
struct spsc_spsc * ezspsc = p1 ;
uint32_t retries = 0 ;
uint32_t retries = 0 ;
uint32_t * val = NULL ;
uint32_t * val = NULL ;
@ -152,11 +151,11 @@ static void t1_consume(void *p1, void *p2, void *p3)
val = NULL ;
val = NULL ;
retries = 0 ;
retries = 0 ;
while ( val = = NULL & & retries < MAX_RETRIES ) {
while ( val = = NULL & & retries < MAX_RETRIES ) {
val = rtio_ spsc_consume( ezspsc ) ;
val = spsc_consume ( ezspsc ) ;
retries + + ;
retries + + ;
}
}
if ( val ! = NULL ) {
if ( val ! = NULL ) {
rtio_ spsc_release( ezspsc ) ;
spsc_release ( ezspsc ) ;
} else {
} else {
k_yield ( ) ;
k_yield ( ) ;
}
}
@ -168,7 +167,7 @@ static void t2_produce(void *p1, void *p2, void *p3)
ARG_UNUSED ( p2 ) ;
ARG_UNUSED ( p2 ) ;
ARG_UNUSED ( p3 ) ;
ARG_UNUSED ( p3 ) ;
struct rtio_ spsc_spsc * ezspsc = p1 ;
struct spsc_spsc * ezspsc = p1 ;
uint32_t retries = 0 ;
uint32_t retries = 0 ;
uint32_t * val = NULL ;
uint32_t * val = NULL ;
@ -176,12 +175,12 @@ static void t2_produce(void *p1, void *p2, void *p3)
val = NULL ;
val = NULL ;
retries = 0 ;
retries = 0 ;
while ( val = = NULL & & retries < MAX_RETRIES ) {
while ( val = = NULL & & retries < MAX_RETRIES ) {
val = rtio_ spsc_acquire( ezspsc ) ;
val = spsc_acquire ( ezspsc ) ;
retries + + ;
retries + + ;
}
}
if ( val ! = NULL ) {
if ( val ! = NULL ) {
* val = SMP_ITERATIONS ;
* val = SMP_ITERATIONS ;
rtio_ spsc_produce( ezspsc ) ;
spsc_produce ( ezspsc ) ;
} else {
} else {
k_yield ( ) ;
k_yield ( ) ;
}
}
@ -192,6 +191,13 @@ static void t2_produce(void *p1, void *p2, void *p3)
# define STACK_SIZE (384 + CONFIG_TEST_EXTRA_STACK_SIZE)
# define STACK_SIZE (384 + CONFIG_TEST_EXTRA_STACK_SIZE)
# define THREADS_NUM 2
# define THREADS_NUM 2
struct thread_info {
k_tid_t tid ;
int executed ;
int priority ;
int cpu_id ;
} ;
static struct thread_info tinfo [ THREADS_NUM ] ;
static struct thread_info tinfo [ THREADS_NUM ] ;
static struct k_thread tthread [ THREADS_NUM ] ;
static struct k_thread tthread [ THREADS_NUM ] ;
static K_THREAD_STACK_ARRAY_DEFINE ( tstack , THREADS_NUM , STACK_SIZE ) ;
static K_THREAD_STACK_ARRAY_DEFINE ( tstack , THREADS_NUM , STACK_SIZE ) ;
@ -202,7 +208,7 @@ static K_THREAD_STACK_ARRAY_DEFINE(tstack, THREADS_NUM, STACK_SIZE);
* This can and should be validated on SMP machines where incoherent
* This can and should be validated on SMP machines where incoherent
* memory could cause issues .
* memory could cause issues .
*/
*/
ZTEST ( rtio_ spsc, test_spsc_threaded )
ZTEST ( spsc , test_spsc_threaded )
{
{
tinfo [ 0 ] . tid =
tinfo [ 0 ] . tid =
@ -224,7 +230,7 @@ ZTEST(rtio_spsc, test_spsc_threaded)
# define THROUGHPUT_ITERS 100000
# define THROUGHPUT_ITERS 100000
ZTEST ( rtio_ spsc, test_spsc_throughput )
ZTEST ( spsc , test_spsc_throughput )
{
{
timing_t start_time , end_time ;
timing_t start_time , end_time ;
@ -235,15 +241,19 @@ ZTEST(rtio_spsc, test_spsc_throughput)
uint32_t * x , * y ;
uint32_t * x , * y ;
int key = irq_lock ( ) ;
for ( int i = 0 ; i < THROUGHPUT_ITERS ; i + + ) {
for ( int i = 0 ; i < THROUGHPUT_ITERS ; i + + ) {
x = rtio_spsc_acquire ( & spsc ) ;
x = spsc_acquire ( & spsc ) ;
* x = i ;
* x = i ;
rtio_ spsc_produce( & spsc ) ;
spsc_produce ( & spsc ) ;
y = rtio_ spsc_consume( & spsc ) ;
y = spsc_consume ( & spsc ) ;
rtio_ spsc_release( & spsc ) ;
spsc_release ( & spsc ) ;
}
}
irq_unlock ( key ) ;
end_time = timing_counter_get ( ) ;
end_time = timing_counter_get ( ) ;
uint64_t cycles = timing_cycles_get ( & start_time , & end_time ) ;
uint64_t cycles = timing_cycles_get ( & start_time , & end_time ) ;
@ -253,11 +263,11 @@ ZTEST(rtio_spsc, test_spsc_throughput)
THROUGHPUT_ITERS , ns / THROUGHPUT_ITERS ) ;
THROUGHPUT_ITERS , ns / THROUGHPUT_ITERS ) ;
}
}
static void rtio_ spsc_before( void * data )
static void spsc_before ( void * data )
{
{
ARG_UNUSED ( data ) ;
ARG_UNUSED ( data ) ;
rtio_ spsc_reset( & spsc ) ;
spsc_reset ( & spsc ) ;
}
}
ZTEST_SUITE ( rtio_ spsc, NULL , NULL , rtio_ spsc_before, NULL , NULL ) ;
ZTEST_SUITE ( spsc , NULL , NULL , spsc_before , NULL , NULL ) ;