1 /*
2  * Copyright (c) 2023 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * @file
9  * This file contains routines for implementing a timestamp system call
10  * as well as routines for determining the overhead associated with it.
11  */
12 
13 #include <zephyr/kernel.h>
14 #include "utils.h"
15 #include "timing_sc.h"
16 
17 BENCH_BMEM uint64_t timestamp_overhead;
18 #ifdef CONFIG_USERSPACE
19 BENCH_BMEM uint64_t user_timestamp_overhead;
20 #endif
21 
z_impl_timing_timestamp_get(void)22 timing_t z_impl_timing_timestamp_get(void)
23 {
24 	return timing_counter_get();
25 }
26 
27 #ifdef CONFIG_USERSPACE
z_vrfy_timing_timestamp_get(void)28 timing_t z_vrfy_timing_timestamp_get(void)
29 {
30 	return z_impl_timing_timestamp_get();
31 }
32 #include <syscalls/timing_timestamp_get_mrsh.c>
33 #endif
34 
start_thread_entry(void * p1,void * p2,void * p3)35 static void start_thread_entry(void *p1, void *p2, void *p3)
36 {
37 	uint32_t  num_iterations = (uint32_t)(uintptr_t)p1;
38 	timing_t  start;
39 	timing_t  finish;
40 
41 	ARG_UNUSED(p2);
42 	ARG_UNUSED(p3);
43 
44 	start = timing_timestamp_get();
45 	for (uint32_t i = 0; i < num_iterations; i++) {
46 		timing_timestamp_get();
47 	}
48 	finish = timing_timestamp_get();
49 
50 	timestamp.cycles = timing_cycles_get(&start, &finish);
51 }
52 
timestamp_overhead_init(uint32_t num_iterations)53 void timestamp_overhead_init(uint32_t num_iterations)
54 {
55 	int  priority;
56 
57 	priority = k_thread_priority_get(k_current_get());
58 
59 	k_thread_create(&start_thread, start_stack,
60 			K_THREAD_STACK_SIZEOF(start_stack),
61 			start_thread_entry,
62 			(void *)(uintptr_t)num_iterations, NULL, NULL,
63 			priority - 1, 0, K_FOREVER);
64 
65 	k_thread_start(&start_thread);
66 
67 	k_thread_join(&start_thread, K_FOREVER);
68 
69 	timestamp_overhead = timestamp.cycles;
70 
71 #ifdef CONFIG_USERSPACE
72 	k_thread_create(&start_thread, start_stack,
73 			K_THREAD_STACK_SIZEOF(start_stack),
74 			start_thread_entry,
75 			(void *)(uintptr_t)num_iterations, NULL, NULL,
76 			priority - 1, K_USER, K_FOREVER);
77 
78 	k_thread_start(&start_thread);
79 
80 	k_thread_join(&start_thread, K_FOREVER);
81 
82 	user_timestamp_overhead = timestamp.cycles;
83 #endif
84 }
85 
timestamp_overhead_adjustment(uint32_t options1,uint32_t options2)86 uint64_t timestamp_overhead_adjustment(uint32_t options1, uint32_t options2)
87 {
88 #ifdef CONFIG_USERSPACE
89 	if (((options1 | options2) & K_USER) == K_USER) {
90 		if (((options1 & options2) & K_USER) == K_USER) {
91 			/*
92 			 * Both start and finish timestamps were obtained
93 			 * from userspace.
94 			 */
95 			return user_timestamp_overhead;
96 		}
97 		/*
98 		 * One timestamp came from userspace, and the other came
99 		 * from kernel space. Estimate the overhead as the mean
100 		 * between the two.
101 		 */
102 		return (timestamp_overhead + user_timestamp_overhead) / 2;
103 	}
104 #endif
105 
106 	/*
107 	 * Both start and finish timestamps were obtained
108 	 * from kernel space.
109 	 */
110 	return timestamp_overhead;
111 }
112