tests: latency_measure: Update semaphores
Updates the semaphore benchmarking in the latency_benchmark code to support user threads. Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
This commit is contained in:
parent
13ac14f2bb
commit
4c4453d697
2 changed files with 246 additions and 89 deletions
|
@ -46,9 +46,10 @@ int error_count; /* track number of errors */
|
|||
|
||||
extern void thread_switch_yield(uint32_t num_iterations, bool is_cooperative);
|
||||
extern void int_to_thread(uint32_t num_iterations);
|
||||
extern void sema_test_signal(void);
|
||||
extern void sema_test_signal(uint32_t num_iterations, uint32_t options);
|
||||
extern void mutex_lock_unlock(void);
|
||||
extern int sema_context_switch(void);
|
||||
extern void sema_context_switch(uint32_t num_iterations,
|
||||
uint32_t start_options, uint32_t alt_options);
|
||||
extern int thread_ops(uint32_t num_iterations, uint32_t start_options,
|
||||
uint32_t alt_options);
|
||||
extern void heap_malloc_free(void);
|
||||
|
@ -92,9 +93,17 @@ static void test_thread(void *arg1, void *arg2, void *arg3)
|
|||
thread_ops(NUM_ITERATIONS, K_USER, 0);
|
||||
#endif
|
||||
|
||||
sema_test_signal();
|
||||
sema_test_signal(NUM_ITERATIONS, 0);
|
||||
#ifdef CONFIG_USERSPACE
|
||||
sema_test_signal(NUM_ITERATIONS, K_USER);
|
||||
#endif
|
||||
|
||||
sema_context_switch();
|
||||
sema_context_switch(NUM_ITERATIONS, 0, 0);
|
||||
#ifdef CONFIG_USERSPACE
|
||||
sema_context_switch(NUM_ITERATIONS, 0, K_USER);
|
||||
sema_context_switch(NUM_ITERATIONS, K_USER, 0);
|
||||
sema_context_switch(NUM_ITERATIONS, K_USER, K_USER);
|
||||
#endif
|
||||
|
||||
mutex_lock_unlock();
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2015 Wind River Systems, Inc.
|
||||
* Copyright (c) 2023 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -7,68 +8,215 @@
|
|||
/*
|
||||
* @file measure time for sema lock and release
|
||||
*
|
||||
* This file contains the test that measures semaphore and mutex lock and
|
||||
* release time in the kernel. There is no contention on the sema nor the
|
||||
* mutex being tested.
|
||||
* This file contains the test that measures semaphore give and take time
|
||||
* in the kernel. There is no contention on the semaphore being tested.
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/timing/timing.h>
|
||||
#include "utils.h"
|
||||
|
||||
/* the number of semaphore give/take cycles */
|
||||
#define N_TEST_SEMA 1000
|
||||
static struct k_sem sem;
|
||||
|
||||
#define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACK_SIZE)
|
||||
/* stack used by the threads */
|
||||
static K_THREAD_STACK_DEFINE(thread_one_stack, STACK_SIZE);
|
||||
|
||||
static struct k_thread thread_one_data;
|
||||
|
||||
K_SEM_DEFINE(lock_unlock_sema, 0, N_TEST_SEMA);
|
||||
|
||||
K_SEM_DEFINE(sem_bench, 0, 1);
|
||||
|
||||
timing_t timestamp_start_sema_t_c;
|
||||
timing_t timestamp_end_sema_t_c;
|
||||
timing_t timestamp_start_sema_g_c;
|
||||
timing_t timestamp_end_sema_g_c;
|
||||
|
||||
void thread_sema_test1(void *p1, void *p2, void *p3)
|
||||
static void alt_thread_entry(void *p1, void *p2, void *p3)
|
||||
{
|
||||
timestamp_start_sema_t_c = timing_counter_get();
|
||||
k_sem_take(&sem_bench, K_FOREVER);
|
||||
timestamp_end_sema_g_c = timing_counter_get();
|
||||
uint32_t num_iterations = (uint32_t)(uintptr_t)p1;
|
||||
timing_t mid;
|
||||
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
for (uint32_t i = 0; i < num_iterations; i++) {
|
||||
|
||||
/*
|
||||
* 2. Give the semaphore, thereby forcing a context switch back
|
||||
* to <start_thread>.
|
||||
*/
|
||||
|
||||
mid = timing_counter_get();
|
||||
k_sem_give(&sem);
|
||||
|
||||
/* 5. Share the <mid> timestamp. */
|
||||
|
||||
timestamp.sample = mid;
|
||||
|
||||
/* 6. Give <sem> so <start_thread> resumes execution */
|
||||
|
||||
k_sem_give(&sem);
|
||||
}
|
||||
}
|
||||
|
||||
int sema_context_switch(void)
|
||||
static void start_thread_entry(void *p1, void *p2, void *p3)
|
||||
{
|
||||
uint32_t diff;
|
||||
uint32_t num_iterations = (uint32_t)(uintptr_t)p1;
|
||||
timing_t start;
|
||||
timing_t mid;
|
||||
timing_t finish;
|
||||
uint32_t i;
|
||||
uint64_t take_sum = 0ull;
|
||||
uint64_t give_sum = 0ull;
|
||||
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
k_thread_start(&alt_thread);
|
||||
|
||||
for (i = 0; i < num_iterations; i++) {
|
||||
|
||||
/*
|
||||
* 1. Block on taking the semaphore and force a context switch
|
||||
* to <alt_thread>.
|
||||
*/
|
||||
|
||||
start = timing_counter_get();
|
||||
k_sem_take(&sem, K_FOREVER);
|
||||
|
||||
/* 3. Get the <finish> timestamp. */
|
||||
|
||||
finish = timing_counter_get();
|
||||
|
||||
/*
|
||||
* 4. Let <alt_thread> run so it can share its <mid>
|
||||
* timestamp.
|
||||
*/
|
||||
|
||||
k_sem_take(&sem, K_FOREVER);
|
||||
|
||||
/* 7. Retrieve the <mid> timestamp */
|
||||
|
||||
mid = timestamp.sample;
|
||||
|
||||
take_sum += timing_cycles_get(&start, &mid);
|
||||
give_sum += timing_cycles_get(&mid, &finish);
|
||||
}
|
||||
|
||||
k_thread_join(&alt_thread, K_FOREVER);
|
||||
|
||||
/* Share the totals with the main thread */
|
||||
|
||||
timestamp.cycles = take_sum;
|
||||
|
||||
k_sem_take(&sem, K_FOREVER);
|
||||
|
||||
timestamp.cycles = give_sum;
|
||||
}
|
||||
|
||||
void sema_context_switch(uint32_t num_iterations,
|
||||
uint32_t start_options, uint32_t alt_options)
|
||||
{
|
||||
uint64_t cycles;
|
||||
char description[80];
|
||||
int priority;
|
||||
|
||||
timing_start();
|
||||
|
||||
k_thread_create(&thread_one_data, thread_one_stack,
|
||||
STACK_SIZE, thread_sema_test1,
|
||||
NULL, NULL, NULL,
|
||||
K_PRIO_PREEMPT(3), 0, K_FOREVER);
|
||||
k_thread_name_set(&thread_one_data, "sema_test1");
|
||||
k_thread_start(&thread_one_data);
|
||||
priority = k_thread_priority_get(k_current_get());
|
||||
|
||||
timestamp_end_sema_t_c = timing_counter_get();
|
||||
diff = timing_cycles_get(×tamp_start_sema_t_c, ×tamp_end_sema_t_c);
|
||||
PRINT_STATS("Semaphore take time (context switch)", diff, false, "");
|
||||
k_thread_create(&start_thread, start_stack,
|
||||
K_THREAD_STACK_SIZEOF(start_stack),
|
||||
start_thread_entry,
|
||||
(void *)(uintptr_t)num_iterations, NULL, NULL,
|
||||
priority - 2, start_options, K_FOREVER);
|
||||
|
||||
k_thread_create(&alt_thread, alt_stack,
|
||||
K_THREAD_STACK_SIZEOF(alt_stack),
|
||||
alt_thread_entry,
|
||||
(void *)(uintptr_t)num_iterations, NULL, NULL,
|
||||
priority - 1, alt_options, K_FOREVER);
|
||||
|
||||
timestamp_start_sema_g_c = timing_counter_get();
|
||||
k_sem_give(&sem_bench);
|
||||
diff = timing_cycles_get(×tamp_start_sema_g_c, ×tamp_end_sema_g_c);
|
||||
PRINT_STATS("Semaphore give time (context switch)", diff, false, "");
|
||||
k_thread_access_grant(&start_thread, &sem, &alt_thread);
|
||||
|
||||
k_thread_access_grant(&alt_thread, &sem);
|
||||
|
||||
/* Start the test threads */
|
||||
|
||||
k_thread_start(&start_thread);
|
||||
|
||||
/* Retrieve the number of cycles spent taking the semaphore */
|
||||
|
||||
cycles = timestamp.cycles;
|
||||
|
||||
snprintf(description, sizeof(description),
|
||||
"Take a semaphore (context switch %c -> %c)",
|
||||
((start_options & K_USER) == K_USER) ? 'U' : 'K',
|
||||
((alt_options & K_USER) == K_USER) ? 'U' : 'K');
|
||||
PRINT_STATS_AVG(description, (uint32_t)cycles,
|
||||
num_iterations, false, "");
|
||||
|
||||
/* Unblock <start_thread> */
|
||||
|
||||
k_sem_give(&sem);
|
||||
|
||||
/* Retrieve the number of cycles spent taking the semaphore */
|
||||
|
||||
cycles = timestamp.cycles;
|
||||
|
||||
snprintf(description, sizeof(description),
|
||||
"Give a semaphore (context switch %c -> %c)",
|
||||
((alt_options & K_USER) == K_USER) ? 'U' : 'K',
|
||||
((start_options & K_USER) == K_USER) ? 'U' : 'K');
|
||||
PRINT_STATS_AVG(description, (uint32_t)cycles,
|
||||
num_iterations, false, "");
|
||||
|
||||
k_thread_join(&start_thread, K_FOREVER);
|
||||
|
||||
timing_stop();
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the entry point for the test that performs uncontested operations
|
||||
* on the semaphore. It gives the semaphore many times, takes the semaphore
|
||||
* many times and then sends the results back to the main thread.
|
||||
*/
|
||||
static void immediate_give_take(void *p1, void *p2, void *p3)
|
||||
{
|
||||
uint32_t num_iterations = (uint32_t)(uintptr_t)p1;
|
||||
timing_t start;
|
||||
timing_t finish;
|
||||
uint64_t give_cycles;
|
||||
uint64_t take_cycles;
|
||||
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
/* 1. Give a semaphore. No threads are waiting on it */
|
||||
|
||||
start = timing_counter_get();
|
||||
|
||||
for (uint32_t i = 0; i < num_iterations; i++) {
|
||||
k_sem_give(&sem);
|
||||
}
|
||||
|
||||
finish = timing_counter_get();
|
||||
give_cycles = timing_cycles_get(&start, &finish);
|
||||
|
||||
/* 2. Take a semaphore--no contention */
|
||||
|
||||
start = timing_counter_get();
|
||||
|
||||
for (uint32_t i = 0; i < num_iterations; i++) {
|
||||
k_sem_take(&sem, K_NO_WAIT);
|
||||
}
|
||||
|
||||
finish = timing_counter_get();
|
||||
take_cycles = timing_cycles_get(&start, &finish);
|
||||
|
||||
/* 3. Post the number of cycles spent giving the semaphore */
|
||||
|
||||
timestamp.cycles = give_cycles;
|
||||
|
||||
/* 4. Wait for the main thread to retrieve the data */
|
||||
|
||||
k_sem_take(&sem, K_FOREVER);
|
||||
|
||||
/* 7. Post the number of cycles spent taking the semaphore */
|
||||
|
||||
timestamp.cycles = take_cycles;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief The function tests semaphore test/signal time
|
||||
|
@ -78,58 +226,58 @@ int sema_context_switch(void)
|
|||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int sema_test_signal(void)
|
||||
int sema_test_signal(uint32_t num_iterations, uint32_t options)
|
||||
{
|
||||
int i;
|
||||
uint32_t diff;
|
||||
timing_t timestamp_start;
|
||||
timing_t timestamp_end;
|
||||
const char *notes = "";
|
||||
int end;
|
||||
uint64_t cycles;
|
||||
int priority;
|
||||
char description[80];
|
||||
|
||||
bench_test_start();
|
||||
timing_start();
|
||||
|
||||
timestamp_start = timing_counter_get();
|
||||
k_sem_init(&sem, 0, num_iterations);
|
||||
|
||||
for (i = 0; i < N_TEST_SEMA; i++) {
|
||||
k_sem_give(&lock_unlock_sema);
|
||||
}
|
||||
priority = k_thread_priority_get(k_current_get());
|
||||
|
||||
k_thread_create(&start_thread, start_stack,
|
||||
K_THREAD_STACK_SIZEOF(start_stack),
|
||||
immediate_give_take,
|
||||
(void *)(uintptr_t)num_iterations, NULL, NULL,
|
||||
priority - 1, options, K_FOREVER);
|
||||
|
||||
k_thread_access_grant(&start_thread, &sem);
|
||||
k_thread_start(&start_thread);
|
||||
|
||||
/* 5. Retrieve the number of cycles spent giving the semaphore */
|
||||
|
||||
cycles = timestamp.cycles;
|
||||
|
||||
snprintf(description, sizeof(description),
|
||||
"Give a semaphore (no waiters) from %s thread",
|
||||
(options & K_USER) == K_USER ? "user" : "kernel");
|
||||
|
||||
PRINT_STATS_AVG(description, (uint32_t)cycles,
|
||||
num_iterations, false, "");
|
||||
|
||||
/* 6. Unblock <start_thread> */
|
||||
|
||||
k_sem_give(&sem);
|
||||
|
||||
/* 8. Wait for <start_thread> to finish */
|
||||
|
||||
k_thread_join(&start_thread, K_FOREVER);
|
||||
|
||||
/* 9. Retrieve the number of cycles spent taking the semaphore */
|
||||
|
||||
cycles = timestamp.cycles;
|
||||
|
||||
snprintf(description, sizeof(description),
|
||||
"Take a semaphore (no blocking) from %s thread",
|
||||
(options & K_USER) == K_USER ? "user" : "kernel");
|
||||
|
||||
PRINT_STATS_AVG(description, (uint32_t)cycles,
|
||||
num_iterations, false, "");
|
||||
|
||||
timestamp_end = timing_counter_get();
|
||||
end = bench_test_end();
|
||||
timing_stop();
|
||||
|
||||
if (end != 0) {
|
||||
error_count++;
|
||||
notes = TICK_OCCURRENCE_ERROR;
|
||||
}
|
||||
|
||||
diff = timing_cycles_get(×tamp_start, ×tamp_end);
|
||||
PRINT_STATS_AVG("Average semaphore signal time", diff, N_TEST_SEMA,
|
||||
false, notes);
|
||||
|
||||
bench_test_start();
|
||||
timing_start();
|
||||
|
||||
timestamp_start = timing_counter_get();
|
||||
|
||||
for (i = 0; i < N_TEST_SEMA; i++) {
|
||||
k_sem_take(&lock_unlock_sema, K_FOREVER);
|
||||
}
|
||||
|
||||
timestamp_end = timing_counter_get();
|
||||
end = bench_test_end();
|
||||
timing_stop();
|
||||
|
||||
if (end != 0) {
|
||||
error_count++;
|
||||
notes = TICK_OCCURRENCE_ERROR;
|
||||
}
|
||||
|
||||
diff = timing_cycles_get(×tamp_start, ×tamp_end);
|
||||
PRINT_STATS_AVG("Average semaphore test time", diff, N_TEST_SEMA,
|
||||
false, notes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue