This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new 0b602b7f4 testing/ostest: Count the time slices in the round-robin
test.
0b602b7f4 is described below
commit 0b602b7f4b2997276c7ff00c9a3685a7d73aa735
Author: Marco Casaroli <[email protected]>
AuthorDate: Sat Oct 17 22:11:21 2026 +0200
testing/ostest: Count the time slices in the round-robin test.
rr_test passed when the first thread did not finish all its runs before
the second thread finished one run. When one run is much shorter than
CONFIG_RR_INTERVAL, the first thread finishes all its runs in its first
time slice, and the test fails although round-robin scheduling works.
This happens on fast targets, and on QEMU when the host is busy.
Count the time slices of each thread instead. Each thread searches for
primes one number at a time, and starts a new time slice when the other
thread ran after its last number. The test ends when each thread had
CONFIG_TESTING_OSTEST_RR_RUNS time slices, and it passes when the two
counts differ by at most one. If the time slices do not come, the
ostest thread, which has a higher priority, stops the two threads after
a time limit and the test fails.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <[email protected]>
---
testing/ostest/Kconfig | 25 ++++-----
testing/ostest/roundrobin.c | 125 +++++++++++++++++++++++++-------------------
2 files changed, 81 insertions(+), 69 deletions(-)
diff --git a/testing/ostest/Kconfig b/testing/ostest/Kconfig
index 357382463..c714d179d 100644
--- a/testing/ostest/Kconfig
+++ b/testing/ostest/Kconfig
@@ -67,26 +67,23 @@ config TESTING_OSTEST_RR_RANGE
range 1 32767
---help---
During round-robin scheduling test two threads are created.
Each of the threads
- searches for prime numbers in the configurable range, doing
that configurable
- number of times.
+ searches for prime numbers below this value, one number at a
time, and starts
+ again at 1 at the end of the range.
- This value specifies the end of search range and together with
number of runs
- allows to configure the length of this test - it should last at
least a few
- tens of seconds. Allowed values [1; 32767], default 30000
+ Each thread checks after each number whether the other thread
ran. The time
+ for one number must be much shorter than CONFIG_RR_INTERVAL.
Allowed values
+ [1; 32767], default 30000
config TESTING_OSTEST_RR_RUNS
- int "Round-robin test - number of runs"
+ int "Round-robin test - number of time slices"
default 10
range 1 32767
---help---
- During round-robin scheduling test two threads are created.
Each of the threads
- searches for prime numbers in the configurable range, doing
that configurable
- number of times.
-
- This value specifies the number of times the thread searches
the range for
- prime numbers and together with end of search range allows to
configure the
- length of this test - it should last at least a few tens of
seconds. Allowed
- values [1; 32767], default 10
+ During round-robin scheduling test two threads are created. The
test ends
+ when each thread had this number of time slices, so it takes
about
+ 2 * TESTING_OSTEST_RR_RUNS * RR_INTERVAL milliseconds. The
test passes
+ when the two threads had the same number of time slices, plus
or minus
+ one. Allowed values [1; 32767], default 10
if ARCH_FPU && SCHED_WAITPID
diff --git a/testing/ostest/roundrobin.c b/testing/ostest/roundrobin.c
index 86af993b8..d7d1c70c9 100644
--- a/testing/ostest/roundrobin.c
+++ b/testing/ostest/roundrobin.c
@@ -30,10 +30,10 @@
#include <pthread.h>
#include <sched.h>
#include <semaphore.h>
-#include <stdio.h>
#include <stdbool.h>
-
-#include <nuttx/atomic.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
#include "ostest.h"
@@ -43,9 +43,9 @@
* Pre-processor Definitions
****************************************************************************/
-/* This numbers should be tuned for different processor speeds
- * via .config file. With default values the test takes about 30s
- * on Cortex-M3 @ 24MHz. With 32767 range and 10 runs it takes ~320s.
+/* Each thread searches for prime numbers below RR_RANGE, one number at a
+ * time, and counts its time slices. The test ends when the two threads
+ * have RR_RUNS time slices each.
*/
#ifndef CONFIG_TESTING_OSTEST_RR_RANGE
@@ -68,8 +68,10 @@
* Private Data
****************************************************************************/
-static uint8_t g_rr_values[CONFIG_TESTING_OSTEST_RR_RUNS * 2];
-static atomic_t g_rr_value_index;
+static volatile int g_rr_last;
+static volatile int g_rr_slices[2];
+static volatile bool g_rr_stop;
+static volatile unsigned int g_rr_primes[2];
static sem_t g_rrsem;
/****************************************************************************
@@ -77,70 +79,67 @@ static sem_t g_rrsem;
****************************************************************************/
/****************************************************************************
- * Name: get_primes
+ * Name: is_prime
*
* Description
- * This function searches for prime numbers in the most primitive
+ * This function tests a number for a prime in the most primitive
* way possible.
****************************************************************************/
-static void get_primes(int *count, int *last)
+static bool is_prime(int number)
{
- int number;
- int local_count = 0;
-
- *last = 0; /* To make the compiler happy */
+ int div;
- for (number = 1; number < CONFIG_TESTING_OSTEST_RR_RANGE; number++)
+ for (div = 2; div <= number / 2; div++)
{
- int div;
- bool is_prime = true;
-
- for (div = 2; div <= number / 2; div++)
if (number % div == 0)
{
- is_prime = false;
- break;
- }
-
- if (is_prime)
- {
- local_count++;
- *last = number;
-#if 0 /* We don't really care what the numbers are */
- printf(" Prime %d: %d\n", local_count, number);
-#endif
+ return false;
}
}
- *count = local_count;
+ return true;
}
/****************************************************************************
* Name: get_primes_thread
+ *
+ * Description
+ * Search for primes until the two threads have RR_RUNS time slices each.
+ * A thread starts a new time slice when the other thread ran after its
+ * last number.
****************************************************************************/
static FAR void *get_primes_thread(FAR void *parameter)
{
int id = (int)((intptr_t)parameter);
- int count;
- int last;
- int i;
+ int number = 1;
while (sem_wait(&g_rrsem) < 0);
printf("get_primes_thread id=%d started, "
- "looking for primes < %d, doing %d run(s)\n",
+ "looking for primes < %d, running %d time slice(s)\n",
id, CONFIG_TESTING_OSTEST_RR_RANGE, CONFIG_TESTING_OSTEST_RR_RUNS);
- for (i = 0; i < CONFIG_TESTING_OSTEST_RR_RUNS; i++)
+ while (!g_rr_stop &&
+ g_rr_slices[0] + g_rr_slices[1] < 2 * CONFIG_TESTING_OSTEST_RR_RUNS)
{
- get_primes(&count, &last);
- g_rr_values[atomic_add(&g_rr_value_index, 1)] = id;
+ if (is_prime(number))
+ {
+ g_rr_primes[id - 1]++;
+ }
+
+ number = number % CONFIG_TESTING_OSTEST_RR_RANGE + 1;
+
+ if (g_rr_last != id)
+ {
+ g_rr_last = id;
+ g_rr_slices[id - 1]++;
+ }
}
- printf("get_primes_thread id=%d finished, found %d primes, "
- "last one was %d\n", id, count, last);
+ printf("get_primes_thread id=%d finished, %d time slice(s), "
+ "found %u primes\n", id, g_rr_slices[id - 1], g_rr_primes[id - 1]);
pthread_exit(NULL);
return NULL; /* To keep some compilers happy */
@@ -159,13 +158,13 @@ void rr_test(void)
pthread_t get_primes1_thread;
pthread_t get_primes2_thread;
struct sched_param sparam;
- bool test_passed = false;
pthread_attr_t attr;
pthread_addr_t result;
#ifdef CONFIG_SMP
cpu_set_t cpuset;
#endif
int status;
+ int diff;
int i;
/* Setup common thread attributes */
@@ -221,8 +220,12 @@ void rr_test(void)
/* This semaphore will prevent anything from running until we are ready */
sched_lock();
- atomic_set(&g_rr_value_index, 0);
- memset(g_rr_values, 0, sizeof(g_rr_values));
+ g_rr_last = 0;
+ g_rr_slices[0] = 0;
+ g_rr_slices[1] = 0;
+ g_rr_primes[0] = 0;
+ g_rr_primes[1] = 0;
+ g_rr_stop = false;
sem_init(&g_rrsem, 0, 0);
/* Start the threads */
@@ -249,29 +252,41 @@ void rr_test(void)
}
printf(" Second get_primes_thread: %d\n", (int)get_primes2_thread);
- printf("rr_test: "
- "Waiting for threads to complete -- this should take awhile\n");
- printf(" "
- "If RR scheduling is working, they should start and complete at\n");
- printf(" about the same time\n");
+ printf("rr_test: Waiting for %d time slices of each thread\n",
+ CONFIG_TESTING_OSTEST_RR_RUNS);
+ printf(" If RR scheduling is working, the threads run the same\n");
+ printf(" number of time slices\n");
sem_post(&g_rrsem);
sem_post(&g_rrsem);
sched_unlock();
- pthread_join(get_primes2_thread, &result);
- pthread_join(get_primes1_thread, &result);
+ /* This thread has a higher priority. Stop the threads if RR scheduling
+ * does not give them their time slices: one thread would run forever.
+ */
- for (i = 1; i < CONFIG_TESTING_OSTEST_RR_RUNS; i++)
+ for (i = 0; i < 20 * CONFIG_TESTING_OSTEST_RR_RUNS; i++)
{
- if (g_rr_values[i - 1] != g_rr_values[i])
+ if (g_rr_slices[0] + g_rr_slices[1] >=
+ 2 * CONFIG_TESTING_OSTEST_RR_RUNS)
{
- test_passed = true;
break;
}
+
+ usleep(CONFIG_RR_INTERVAL * 1000);
}
- if (test_passed)
+ g_rr_stop = true;
+
+ pthread_join(get_primes2_thread, &result);
+ pthread_join(get_primes1_thread, &result);
+
+ diff = g_rr_slices[0] - g_rr_slices[1];
+ printf("rr_test: thread 1 ran %d time slices, thread 2 ran %d\n",
+ g_rr_slices[0], g_rr_slices[1]);
+
+ if (g_rr_slices[0] + g_rr_slices[1] >= 2 * CONFIG_TESTING_OSTEST_RR_RUNS &&
+ diff >= -1 && diff <= 1)
{
printf("rr_test: Done\n");
}