1 /*
2  * Copyright (c) 2012-2015 Wind River Systems, Inc.
3  * Copyright (c) 2020,2023 Intel Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /*
9  * @file measure time for mutex lock and unlock
10  *
11  * This file contains the test that measures mutex lock and unlock times
12  * in the kernel. There is no contention on the mutex being tested.
13  */
14 
15 #include <zephyr/kernel.h>
16 #include <zephyr/timing/timing.h>
17 #include "utils.h"
18 #include "timing_sc.h"
19 
20 static K_MUTEX_DEFINE(test_mutex);
21 
start_lock_unlock(void * p1,void * p2,void * p3)22 static void start_lock_unlock(void *p1, void *p2, void *p3)
23 {
24 	uint32_t  i;
25 	uint32_t  num_iterations = (uint32_t)(uintptr_t)p1;
26 	timing_t  start;
27 	timing_t  finish;
28 	uint64_t  lock_cycles;
29 	uint64_t  unlock_cycles;
30 
31 	ARG_UNUSED(p2);
32 	ARG_UNUSED(p3);
33 
34 	start = timing_timestamp_get();
35 
36 	/* Recursively lock take the mutex */
37 
38 	for (i = 0; i < num_iterations; i++) {
39 		k_mutex_lock(&test_mutex, K_NO_WAIT);
40 	}
41 
42 	finish = timing_timestamp_get();
43 
44 	lock_cycles = timing_cycles_get(&start, &finish);
45 
46 	start = timing_timestamp_get();
47 
48 	/* Recursively unlock the mutex */
49 
50 	for (i = 0; i < num_iterations; i++) {
51 		k_mutex_unlock(&test_mutex);
52 	}
53 
54 	finish = timing_timestamp_get();
55 
56 	unlock_cycles = timing_cycles_get(&start, &finish);
57 
58 	timestamp.cycles = lock_cycles;
59 	k_sem_take(&pause_sem, K_FOREVER);
60 
61 	timestamp.cycles = unlock_cycles;
62 }
63 
64 
65 /**
66  *
67  * @brief Test for the multiple mutex lock/unlock time
68  *
69  * The routine performs multiple mutex locks and then multiple mutex
70  * unlocks to measure the necessary time.
71  *
72  * @return 0 on success
73  */
mutex_lock_unlock(uint32_t num_iterations,uint32_t options)74 int mutex_lock_unlock(uint32_t num_iterations, uint32_t options)
75 {
76 	char tag[50];
77 	char description[120];
78 	int  priority;
79 	uint64_t  cycles;
80 
81 	timing_start();
82 
83 	priority = k_thread_priority_get(k_current_get());
84 
85 	k_thread_create(&start_thread, start_stack,
86 			K_THREAD_STACK_SIZEOF(start_stack),
87 			start_lock_unlock,
88 			(void *)(uintptr_t)num_iterations, NULL, NULL,
89 			priority - 1, options, K_FOREVER);
90 
91 	k_thread_access_grant(&start_thread, &test_mutex, &pause_sem);
92 	k_thread_start(&start_thread);
93 
94 	cycles = timestamp.cycles;
95 	k_sem_give(&pause_sem);
96 
97 	snprintf(tag, sizeof(tag),
98 		 "mutex.lock.immediate.recursive.%s",
99 		 (options & K_USER) == K_USER ? "user" : "kernel");
100 	snprintf(description, sizeof(description),
101 		 "%-40s - Lock a mutex", tag);
102 	PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations,
103 			false, "");
104 
105 	cycles = timestamp.cycles;
106 
107 	snprintf(tag, sizeof(tag),
108 		 "mutex.unlock.immediate.recursive.%s",
109 		 (options & K_USER) == K_USER ? "user" : "kernel");
110 	snprintf(description, sizeof(description),
111 		 "%-40s - Unlock a mutex", tag);
112 	PRINT_STATS_AVG(description, (uint32_t)cycles, num_iterations,
113 			false, "");
114 
115 	timing_stop();
116 	return 0;
117 }
118