This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit 34e70e7f0c52162f306f9b64bf17df73afd4e052
Author: ouyangxiangzhen <[email protected]>
AuthorDate: Wed Aug 7 15:02:19 2024 +0800

    testing/ostest: Fix timing assertions in wdog_test
    
    This patch removed timing assertions in wdog_test.
    
    Signed-off-by: ouyangxiangzhen <[email protected]>
---
 testing/ostest/wdog.c | 148 +++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 109 insertions(+), 39 deletions(-)

diff --git a/testing/ostest/wdog.c b/testing/ostest/wdog.c
index 1d5cf4ccd..49478ae49 100644
--- a/testing/ostest/wdog.c
+++ b/testing/ostest/wdog.c
@@ -26,9 +26,10 @@
 #include <nuttx/arch.h>
 #include <nuttx/wdog.h>
 
+#include <assert.h>
 #include <pthread.h>
 #include <stdio.h>
-#include <assert.h>
+#include <syslog.h>
 #include <unistd.h>
 
 /****************************************************************************
@@ -36,12 +37,12 @@
  ****************************************************************************/
 
 #define WDOGTEST_RAND_ITER           1024
-#define WDOGTEST_THREAD_NR           8
-#define WDOGTEST_TOLERENT_LATENCY_US 5000
+#define WDOGTEST_THREAD_NR           (CONFIG_SMP_NCPUS * 4)
+#define WDOGTEST_TOLERENT_TICK       10
 
 #define wdtest_assert(x)             _ASSERT(x, __FILE__, __LINE__)
 
-#define wdtest_printf(...)           printf(__VA_ARGS__)
+#define wdtest_printf(...)           syslog(LOG_WARNING, __VA_ARGS__)
 
 #define wdtest_delay(delay_ns)       usleep(delay_ns / 1000 + 1)
 
@@ -64,63 +65,131 @@ typedef struct wdtest_param_s
 #ifdef CONFIG_BUILD_FLAT
 static void wdtest_callback(wdparm_t param)
 {
-  struct timespec tp;
   FAR wdtest_param_t *wdtest_param = (FAR wdtest_param_t *)param;
 
-  clock_gettime(CLOCK_MONOTONIC, &tp);
+  /* Increment the callback count */
 
   wdtest_param->callback_cnt   += 1;
-  wdtest_param->triggered_tick  = clock_time2ticks(&tp);
+
+  /* Record the system tick at which the callback was triggered */
+
+  wdtest_param->triggered_tick  = clock_systime_ticks();
+}
+
+static void wdtest_checkdelay(sclock_t diff, sclock_t delay_tick)
+{
+  /* Ensure the watchdog trigger time is not earlier than expected. */
+
+  wdtest_assert(diff - delay_tick >= 0);
+
+  /* If the timer latency exceeds the tolerance, print a warning. */
+
+  if (diff - delay_tick > WDOGTEST_TOLERENT_TICK)
+    {
+      wdtest_printf("WARNING: wdog latency ticks %lld "
+                    "(> %u may indicate timing error)\n",
+                    (long long)diff - delay_tick,
+                    WDOGTEST_TOLERENT_TICK);
+    }
 }
 
 static void wdtest_once(FAR struct wdog_s *wdog, FAR wdtest_param_t *param,
                         sclock_t delay_ns)
 {
-  uint64_t        cnt;
-  long long       diff;
-  clock_t         wdset_tick;
-  struct timespec tp;
-  clock_t         delay_ticks = (clock_t)NSEC2TICK((clock_t)delay_ns);
+  uint64_t   cnt;
+  sclock_t   diff;
+  clock_t    wdset_tick;
+  irqstate_t flags;
+  sclock_t   delay_tick = (sclock_t)NSEC2TICK((clock_t)delay_ns);
 
   wdtest_printf("wdtest_once %lld ns\n", (long long)delay_ns);
 
-  clock_gettime(CLOCK_MONOTONIC, &tp);
+  /* Save the current callback count. */
 
-  wdset_tick = clock_time2ticks(&tp);
   cnt        = param->callback_cnt;
 
-  wdtest_assert(wd_start(wdog, delay_ticks, wdtest_callback,
+  /* Enter a critical section to prevent interruptions. */
+
+  flags = enter_critical_section();
+
+  /* Record the current system tick before setting the watchdog. */
+
+  wdset_tick = clock_systime_ticks();
+
+  wdtest_assert(wd_start(wdog, delay_tick, wdtest_callback,
                          (wdparm_t)param) == OK);
 
-  wdtest_delay(delay_ns);
+  leave_critical_section(flags);
 
-  diff = (long long)(param->triggered_tick - wdset_tick);
+  /* Wait until the callback is triggered exactly once. */
 
-  wdtest_assert(cnt + 1 == param->callback_cnt);
+  while (cnt + 1 != param->callback_cnt)
+    {
+      wdtest_delay(delay_ns);
+    }
+
+  /* Check if the delay is within the acceptable tolerance. */
 
-  /* Ensure diff - delay_ticks >= 0. */
+  diff = (sclock_t)(param->triggered_tick - wdset_tick);
 
-  wdtest_assert(diff - (long long)delay_ticks >= 0);
-  wdtest_printf("wdtest_once latency ticks %lld\n", diff - delay_ticks);
+  wdtest_checkdelay(diff, delay_tick);
 }
 
 static void wdtest_rand(FAR struct wdog_s *wdog, FAR wdtest_param_t *param,
                         sclock_t rand_ns)
 {
-  int      idx;
-  sclock_t delay_ns;
+  uint64_t   cnt;
+  int        idx;
+  sclock_t   delay_ns;
+  clock_t    wdset_tick;
+  sclock_t   delay_tick;
+  sclock_t   diff;
+  irqstate_t flags;
+
+  /* Perform multiple iterations with random delays. */
 
   for (idx = 0; idx < WDOGTEST_RAND_ITER; idx++)
     {
+      cnt = param->callback_cnt;
+
+      /* Generate a random delay within the specified range. */
+
       delay_ns = rand() % rand_ns;
-      wdtest_assert(wd_start(wdog, NSEC2TICK(delay_ns), wdtest_callback,
+      delay_tick = NSEC2TICK(delay_ns);
+
+      /* Enter critical section if the callback count is odd. */
+
+      if (cnt % 2)
+        {
+          flags = enter_critical_section();
+        }
+
+      wdset_tick = clock_systime_ticks();
+      wdtest_assert(wd_start(wdog, delay_tick, wdtest_callback,
                              (wdparm_t)param) == 0);
+      if (cnt % 2)
+        {
+          leave_critical_section(flags);
+        }
 
-      /* Wait or Cancel 50/50 */
+      /* Decide to wait for the callback or cancel the watchdog. */
 
       if (delay_ns % 2)
         {
-          wdtest_delay(delay_ns);
+          /* Wait for the callback. */
+
+          while (cnt + 1 != param->callback_cnt)
+            {
+              wdtest_delay(delay_ns);
+            }
+
+          /* Check the delay if the callback count is odd. */
+
+          if (cnt % 2)
+            {
+              diff = (sclock_t)(param->triggered_tick - wdset_tick);
+              wdtest_checkdelay(diff, delay_tick);
+            }
         }
       else
         {
@@ -131,14 +200,11 @@ static void wdtest_rand(FAR struct wdog_s *wdog, FAR 
wdtest_param_t *param,
 
 static void wdtest_callback_recursive(wdparm_t param)
 {
-  struct timespec     tp;
   FAR wdtest_param_t *wdtest_param = (FAR wdtest_param_t *)param;
   sclock_t            interval     = wdtest_param->interval;
 
-  clock_gettime(CLOCK_MONOTONIC, &tp);
-
   wdtest_param->callback_cnt   += 1;
-  wdtest_param->triggered_tick  = clock_time2ticks(&tp);
+  wdtest_param->triggered_tick  = clock_systime_ticks();
 
   wd_start(wdtest_param->wdog, interval,
            wdtest_callback_recursive, param);
@@ -149,24 +215,29 @@ static void wdtest_recursive(FAR struct wdog_s *wdog,
                              sclock_t delay_ns,
                              unsigned int times)
 {
-  uint64_t        cnt;
-  struct timespec tp;
-  clock_t         wdset_tick;
+  uint64_t cnt;
+  clock_t  wdset_tick;
+  irqstate_t flags;
 
   wdtest_printf("wdtest_recursive %lldus\n", (long long)delay_ns);
+
   cnt = param->callback_cnt;
+
   param->wdog = wdog;
   param->interval = (sclock_t)NSEC2TICK((clock_t)delay_ns);
 
   wdtest_assert(param->interval >= 0);
 
-  clock_gettime(CLOCK_MONOTONIC, &tp);
-  wdset_tick = clock_time2ticks(&tp);
+  flags = enter_critical_section();
+
+  wdset_tick = clock_systime_ticks();
 
   wdtest_assert(wd_start(param->wdog, param->interval,
                          wdtest_callback_recursive,
                          (wdparm_t)param) == OK);
 
+  leave_critical_section(flags);
+
   wdtest_delay(times * delay_ns);
 
   wdtest_assert(wd_cancel(param->wdog) == 0);
@@ -208,7 +279,6 @@ static void wdog_test_run(FAR wdtest_param_t *param)
   wdtest_once(&test_wdog, param, 100);
   wdtest_once(&test_wdog, param, 1000);
   wdtest_once(&test_wdog, param, 10000);
-  wdtest_delay(10);
 
   /* Delay > 0, middle 100us */
 
@@ -242,11 +312,11 @@ static void wdog_test_run(FAR wdtest_param_t *param)
 
   wdtest_assert(rest < delay && rest > (delay >> 1));
 
-  wdtest_printf("wd_start with maximum delay, cancel %lld\n",
-                (long long)rest);
-
   wdtest_assert(wd_cancel(&test_wdog) == 0);
 
+  wdtest_printf("wd_start with maximum delay, cancel OK, rest %lld\n",
+                (long long)rest);
+
   /* Delay wraparound (delay < 0) */
 
   delay = (sclock_t)((clock_t)delay + 1);

Reply via email to