Browse Source

tests: posix: add posix_clock_selection testsuite

Add a testsuite for the POSIX_CLOCK_SELECTION Option Group which
consists of clock_nanosleep(), pthread_condattr_getclock(), and
pthread_condattr_setclock().

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
pull/89922/head
Chris Friedt 2 months ago committed by Anas Nashif
parent
commit
3c7e43f4e2
  1. 9
      tests/posix/clock_selection/CMakeLists.txt
  2. 9
      tests/posix/clock_selection/prj.conf
  3. 116
      tests/posix/clock_selection/src/main.c
  4. 28
      tests/posix/clock_selection/testcase.yaml
  5. 13
      tests/posix/common/src/cond.c
  6. 153
      tests/posix/timers/src/nanosleep.c
  7. 104
      tests/posix/timers/src/nanosleep_common.c

9
tests/posix/clock_selection/CMakeLists.txt

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(posix_clock_selection)
target_sources(app PRIVATE src/main.c ../timers/src/nanosleep_common.c)
target_compile_options(app PRIVATE -U_POSIX_C_SOURCE -D_POSIX_C_SOURCE=200809L)

9
tests/posix/clock_selection/prj.conf

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
CONFIG_POSIX_API=y
CONFIG_ZTEST=y
CONFIG_POSIX_AEP_CHOICE_BASE=y
CONFIG_POSIX_CLOCK_SELECTION=y
CONFIG_DYNAMIC_THREAD=y
CONFIG_DYNAMIC_THREAD_POOL_SIZE=3
CONFIG_THREAD_STACK_INFO=y

116
tests/posix/clock_selection/src/main.c

@ -0,0 +1,116 @@ @@ -0,0 +1,116 @@
/*
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2025 Tenstorrent AI ULC
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <pthread.h>
#include <time.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/util.h>
#include <zephyr/ztest.h>
#define SELECT_NANOSLEEP 1
#define SELECT_CLOCK_NANOSLEEP 0
void common_lower_bound_check(int selection, clockid_t clock_id, int flags, const uint32_t s,
uint32_t ns);
int select_nanosleep(int selection, clockid_t clock_id, int flags, const struct timespec *rqtp,
struct timespec *rmtp);
ZTEST(posix_clock_selection, test_clock_nanosleep_execution)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
/* absolute sleeps with the monotonic clock and reference time ts */
/* until 1s + 1ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 1, 1);
/* until 1s + 1us past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 1, 1000);
/* until 1s + 500000000ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 1, 500000000);
/* until 2s past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 2, 0);
/* until 2s + 1ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 2, 1);
/* until 2s + 1us + 1ns past reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 2, 1001);
clock_gettime(CLOCK_REALTIME, &ts);
/* absolute sleeps with the real time clock and adjusted reference time ts */
/* until 1s + 1ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 1, 1);
/* until 1s + 1us past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 1, 1000);
/* until 1s + 500000000ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 1, 500000000);
/* until 2s past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 2, 0);
/* until 2s + 1ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 2, 1);
/* until 2s + 1us + 1ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 2, 1001);
}
ZTEST(posix_clock_selection, test_pthread_condattr_getclock)
{
clockid_t clock_id;
pthread_condattr_t att = {0};
zassert_ok(pthread_condattr_init(&att));
zassert_ok(pthread_condattr_getclock(&att, &clock_id), "pthread_condattr_getclock failed");
zassert_equal(clock_id, CLOCK_REALTIME, "clock attribute not set correctly");
zassert_ok(pthread_condattr_destroy(&att));
}
ZTEST(posix_clock_selection, test_pthread_condattr_setclock)
{
clockid_t clock_id;
pthread_condattr_t att = {0};
zassert_ok(pthread_condattr_init(&att));
zassert_ok(pthread_condattr_setclock(&att, CLOCK_MONOTONIC),
"pthread_condattr_setclock failed");
zassert_ok(pthread_condattr_getclock(&att, &clock_id), "pthread_condattr_setclock failed");
zassert_equal(clock_id, CLOCK_MONOTONIC, "clock attribute not set correctly");
zassert_equal(pthread_condattr_setclock(&att, 42), -EINVAL,
"pthread_condattr_setclock did not return EINVAL");
zassert_ok(pthread_condattr_destroy(&att));
}
ZTEST_SUITE(posix_clock_selection, NULL, NULL, NULL, NULL, NULL);

28
tests/posix/clock_selection/testcase.yaml

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
common:
filter: not CONFIG_NATIVE_LIBC
tags:
- posix
- clock_selection
# 1 tier0 platform per supported architecture
platform_key:
- arch
- simulation
integration_platforms:
- qemu_riscv64
min_flash: 64
min_ram: 32
tests:
portability.posix.clock_selection: {}
portability.posix.clock_selection.minimal:
extra_configs:
- CONFIG_MINIMAL_LIBC=y
portability.posix.clock_selection.newlib:
filter: TOOLCHAIN_HAS_NEWLIB == 1
extra_configs:
- CONFIG_NEWLIB_LIBC=y
- CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=8192
portability.posix.clock_selection.picolibc:
tags: picolibc
filter: CONFIG_PICOLIBC_SUPPORTED
extra_configs:
- CONFIG_PICOLIBC=y

13
tests/posix/common/src/cond.c

@ -49,23 +49,10 @@ ZTEST(cond, test_cond_resource_leak) @@ -49,23 +49,10 @@ ZTEST(cond, test_cond_resource_leak)
ZTEST(cond, test_pthread_condattr)
{
clockid_t clock_id;
pthread_condattr_t att = {0};
zassert_ok(pthread_condattr_init(&att));
zassert_ok(pthread_condattr_getclock(&att, &clock_id), "pthread_condattr_getclock failed");
zassert_equal(clock_id, CLOCK_REALTIME, "clock attribute not set correctly");
zassert_ok(pthread_condattr_setclock(&att, CLOCK_REALTIME),
"pthread_condattr_setclock failed");
zassert_ok(pthread_condattr_getclock(&att, &clock_id), "pthread_condattr_setclock failed");
zassert_equal(clock_id, CLOCK_REALTIME, "clock attribute not set correctly");
zassert_equal(pthread_condattr_setclock(&att, 42), -EINVAL,
"pthread_condattr_setclock did not return EINVAL");
zassert_ok(pthread_condattr_destroy(&att));
}

153
tests/posix/timers/src/nanosleep.c

@ -14,23 +14,10 @@ @@ -14,23 +14,10 @@
#define SELECT_NANOSLEEP 1
#define SELECT_CLOCK_NANOSLEEP 0
static inline int select_nanosleep(int selection, clockid_t clock_id, int flags,
const struct timespec *rqtp, struct timespec *rmtp)
{
if (selection == SELECT_NANOSLEEP) {
return nanosleep(rqtp, rmtp);
}
return clock_nanosleep(clock_id, flags, rqtp, rmtp);
}
static inline uint64_t cycle_get_64(void)
{
if (IS_ENABLED(CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER)) {
return k_cycle_get_64();
} else {
return k_cycle_get_32();
}
}
void common_lower_bound_check(int selection, clockid_t clock_id, int flags, const uint32_t s,
uint32_t ns);
int select_nanosleep(int selection, clockid_t clock_id, int flags, const struct timespec *rqtp,
struct timespec *rmtp);
static void common_errors(int selection, clockid_t clock_id, int flags)
{
@ -129,77 +116,6 @@ ZTEST(posix_timers, test_clock_nanosleep_errors_errno) @@ -129,77 +116,6 @@ ZTEST(posix_timers, test_clock_nanosleep_errors_errno)
zassert_equal(rem.tv_nsec, 0, "actual: %d expected: %d", rem.tv_nsec, 0);
}
/**
* @brief Check that a call to nanosleep has yielded execution for some minimum time.
*
* Check that the actual time slept is >= the total time specified by @p s (in seconds) and
* @p ns (in nanoseconds).
*
* @note The time specified by @p s and @p ns is assumed to be absolute (i.e. a time-point)
* when @p selection is set to @ref SELECT_CLOCK_NANOSLEEP. The time is assumed to be relative
* when @p selection is set to @ref SELECT_NANOSLEEP.
*
* @param selection Either @ref SELECT_CLOCK_NANOSLEEP or @ref SELECT_NANOSLEEP
* @param clock_id The clock to test (e.g. @ref CLOCK_MONOTONIC or @ref CLOCK_REALTIME)
* @param flags Flags to pass to @ref clock_nanosleep
* @param s Partial lower bound for yielded time (in seconds)
* @param ns Partial lower bound for yielded time (in nanoseconds)
*/
static void common_lower_bound_check(int selection, clockid_t clock_id, int flags, const uint32_t s,
uint32_t ns)
{
int r;
uint64_t actual_ns = 0;
uint64_t exp_ns;
uint64_t now;
uint64_t then;
struct timespec rem = {0, 0};
struct timespec req = {s, ns};
errno = 0;
then = cycle_get_64();
r = select_nanosleep(selection, clock_id, flags, &req, &rem);
now = cycle_get_64();
zassert_equal(r, 0, "actual: %d expected: %d", r, 0);
zassert_equal(errno, 0, "actual: %d expected: %d", errno, 0);
zassert_equal(req.tv_sec, s, "actual: %d expected: %d", req.tv_sec, s);
zassert_equal(req.tv_nsec, ns, "actual: %d expected: %d", req.tv_nsec, ns);
zassert_equal(rem.tv_sec, 0, "actual: %d expected: %d", rem.tv_sec, 0);
zassert_equal(rem.tv_nsec, 0, "actual: %d expected: %d", rem.tv_nsec, 0);
switch (selection) {
case SELECT_NANOSLEEP:
/* exp_ns and actual_ns are relative (i.e. durations) */
actual_ns = k_cyc_to_ns_ceil64(now + then);
break;
case SELECT_CLOCK_NANOSLEEP:
/* exp_ns and actual_ns are absolute (i.e. time-points) */
actual_ns = k_cyc_to_ns_ceil64(now);
break;
default:
zassert_unreachable();
break;
}
exp_ns = (uint64_t)s * NSEC_PER_SEC + ns;
/* round up to the nearest microsecond for k_busy_wait() */
exp_ns = DIV_ROUND_UP(exp_ns, NSEC_PER_USEC) * NSEC_PER_USEC;
/* The comparison may be incorrect if counter wrap happened. In case of ARC HSDK platforms
* we have high counter clock frequency (500MHz or 1GHz) so counter wrap quite likely to
* happen if we wait long enough. As in some test cases we wait more than 1 second, there
* are significant chances to get false-positive assertion.
* TODO: switch test for k_cycle_get_64 usage where available.
*/
#if !defined(CONFIG_SOC_ARC_HSDK) && !defined(CONFIG_SOC_ARC_HSDK4XD)
/* lower bounds check */
zassert_true(actual_ns >= exp_ns, "actual: %llu expected: %llu", actual_ns, exp_ns);
#endif
/* TODO: Upper bounds check when hr timers are available */
}
ZTEST(posix_timers, test_nanosleep_execution)
{
/* sleep for 1ns */
@ -220,64 +136,3 @@ ZTEST(posix_timers, test_nanosleep_execution) @@ -220,64 +136,3 @@ ZTEST(posix_timers, test_nanosleep_execution)
/* sleep for 1s + 1us + 1ns */
common_lower_bound_check(SELECT_NANOSLEEP, 0, 0, 1, 1001);
}
ZTEST(posix_timers, test_clock_nanosleep_execution)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
/* absolute sleeps with the monotonic clock and reference time ts */
/* until 1s + 1ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 1, 1);
/* until 1s + 1us past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 1, 1000);
/* until 1s + 500000000ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 1, 500000000);
/* until 2s past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 2, 0);
/* until 2s + 1ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 2, 1);
/* until 2s + 1us + 1ns past reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_MONOTONIC, TIMER_ABSTIME,
ts.tv_sec + 2, 1001);
clock_gettime(CLOCK_REALTIME, &ts);
/* absolute sleeps with the real time clock and adjusted reference time ts */
/* until 1s + 1ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 1, 1);
/* until 1s + 1us past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 1, 1000);
/* until 1s + 500000000ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 1, 500000000);
/* until 2s past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 2, 0);
/* until 2s + 1ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 2, 1);
/* until 2s + 1us + 1ns past the reference time */
common_lower_bound_check(SELECT_CLOCK_NANOSLEEP, CLOCK_REALTIME, TIMER_ABSTIME,
ts.tv_sec + 2, 1001);
}

104
tests/posix/timers/src/nanosleep_common.c

@ -0,0 +1,104 @@ @@ -0,0 +1,104 @@
/*
* Copyright (c) 2018 Friedt Professional Engineering Services, Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <stdint.h>
#include <time.h>
#include <zephyr/sys_clock.h>
#include <zephyr/ztest.h>
#define SELECT_NANOSLEEP 1
#define SELECT_CLOCK_NANOSLEEP 0
static inline uint64_t cycle_get_64(void)
{
if (IS_ENABLED(CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER)) {
return k_cycle_get_64();
} else {
return k_cycle_get_32();
}
}
int select_nanosleep(int selection, clockid_t clock_id, int flags, const struct timespec *rqtp,
struct timespec *rmtp)
{
if (selection == SELECT_NANOSLEEP) {
return nanosleep(rqtp, rmtp);
}
return clock_nanosleep(clock_id, flags, rqtp, rmtp);
}
/**
* @brief Check that a call to nanosleep has yielded execution for some minimum time.
*
* Check that the actual time slept is >= the total time specified by @p s (in seconds) and
* @p ns (in nanoseconds).
*
* @note The time specified by @p s and @p ns is assumed to be absolute (i.e. a time-point)
* when @p selection is set to @ref SELECT_CLOCK_NANOSLEEP. The time is assumed to be relative
* when @p selection is set to @ref SELECT_NANOSLEEP.
*
* @param selection Either @ref SELECT_CLOCK_NANOSLEEP or @ref SELECT_NANOSLEEP
* @param clock_id The clock to test (e.g. @ref CLOCK_MONOTONIC or @ref CLOCK_REALTIME)
* @param flags Flags to pass to @ref clock_nanosleep
* @param s Partial lower bound for yielded time (in seconds)
* @param ns Partial lower bound for yielded time (in nanoseconds)
*/
void common_lower_bound_check(int selection, clockid_t clock_id, int flags, const uint32_t s,
uint32_t ns)
{
int r;
uint64_t actual_ns = 0;
uint64_t exp_ns;
uint64_t now;
uint64_t then;
struct timespec rem = {0, 0};
struct timespec req = {s, ns};
errno = 0;
then = cycle_get_64();
r = select_nanosleep(selection, clock_id, flags, &req, &rem);
now = cycle_get_64();
zassert_equal(r, 0, "actual: %d expected: %d", r, 0);
zassert_equal(errno, 0, "actual: %d expected: %d", errno, 0);
zassert_equal(req.tv_sec, s, "actual: %d expected: %d", req.tv_sec, s);
zassert_equal(req.tv_nsec, ns, "actual: %d expected: %d", req.tv_nsec, ns);
zassert_equal(rem.tv_sec, 0, "actual: %d expected: %d", rem.tv_sec, 0);
zassert_equal(rem.tv_nsec, 0, "actual: %d expected: %d", rem.tv_nsec, 0);
switch (selection) {
case SELECT_NANOSLEEP:
/* exp_ns and actual_ns are relative (i.e. durations) */
actual_ns = k_cyc_to_ns_ceil64(now + then);
break;
case SELECT_CLOCK_NANOSLEEP:
/* exp_ns and actual_ns are absolute (i.e. time-points) */
actual_ns = k_cyc_to_ns_ceil64(now);
break;
default:
zassert_unreachable();
break;
}
exp_ns = (uint64_t)s * NSEC_PER_SEC + ns;
/* round up to the nearest microsecond for k_busy_wait() */
exp_ns = DIV_ROUND_UP(exp_ns, NSEC_PER_USEC) * NSEC_PER_USEC;
/* The comparison may be incorrect if counter wrap happened. In case of ARC HSDK platforms
* we have high counter clock frequency (500MHz or 1GHz) so counter wrap quite likely to
* happen if we wait long enough. As in some test cases we wait more than 1 second, there
* are significant chances to get false-positive assertion.
* TODO: switch test for k_cycle_get_64 usage where available.
*/
#if !defined(CONFIG_SOC_ARC_HSDK) && !defined(CONFIG_SOC_ARC_HSDK4XD)
/* lower bounds check */
zassert_true(actual_ns >= exp_ns, "actual: %llu expected: %llu", actual_ns, exp_ns);
#endif
/* TODO: Upper bounds check when hr timers are available */
}
Loading…
Cancel
Save