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
22 #define OVERHEAD_CALC_ITER 10
23
z_impl_timing_timestamp_get(void)24 timing_t z_impl_timing_timestamp_get(void)
25 {
26 return timing_counter_get();
27 }
28
29 #ifdef CONFIG_USERSPACE
z_vrfy_timing_timestamp_get(void)30 timing_t z_vrfy_timing_timestamp_get(void)
31 {
32 return z_impl_timing_timestamp_get();
33 }
34 #include <zephyr/syscalls/timing_timestamp_get_mrsh.c>
35 #endif
36
start_thread_entry(void * p1,void * p2,void * p3)37 static void start_thread_entry(void *p1, void *p2, void *p3)
38 {
39 uint32_t num_iterations = (uint32_t)(uintptr_t)p1;
40 timing_t start;
41 timing_t finish;
42 uint64_t min_cycles = UINT64_MAX;
43
44 ARG_UNUSED(p2);
45 ARG_UNUSED(p3);
46
47 /* Repeat the overhead measurements for a few times to obtain the minimum overhead */
48 for (int n = 0; n < OVERHEAD_CALC_ITER; n++) {
49 start = timing_timestamp_get();
50 for (uint32_t i = 0; i < num_iterations; i++) {
51 timing_timestamp_get();
52 }
53 finish = timing_timestamp_get();
54
55 min_cycles = MIN(min_cycles, timing_cycles_get(&start, &finish));
56 }
57
58 timestamp.cycles = min_cycles;
59 }
60
timestamp_overhead_init(uint32_t num_iterations)61 void timestamp_overhead_init(uint32_t num_iterations)
62 {
63 int priority;
64
65 priority = k_thread_priority_get(k_current_get());
66
67 k_thread_create(&start_thread, start_stack,
68 K_THREAD_STACK_SIZEOF(start_stack),
69 start_thread_entry,
70 (void *)(uintptr_t)num_iterations, NULL, NULL,
71 priority - 1, 0, K_FOREVER);
72
73 k_thread_start(&start_thread);
74
75 k_thread_join(&start_thread, K_FOREVER);
76
77 timestamp_overhead = timestamp.cycles;
78
79 #ifdef CONFIG_USERSPACE
80 k_thread_create(&start_thread, start_stack,
81 K_THREAD_STACK_SIZEOF(start_stack),
82 start_thread_entry,
83 (void *)(uintptr_t)num_iterations, NULL, NULL,
84 priority - 1, K_USER, K_FOREVER);
85
86 k_thread_start(&start_thread);
87
88 k_thread_join(&start_thread, K_FOREVER);
89
90 user_timestamp_overhead = timestamp.cycles;
91 #endif
92 }
93
timestamp_overhead_adjustment(uint32_t options1,uint32_t options2)94 uint64_t timestamp_overhead_adjustment(uint32_t options1, uint32_t options2)
95 {
96 #ifdef CONFIG_USERSPACE
97 if (((options1 | options2) & K_USER) == K_USER) {
98 if (((options1 & options2) & K_USER) == K_USER) {
99 /*
100 * Both start and finish timestamps were obtained
101 * from userspace.
102 */
103 return user_timestamp_overhead;
104 }
105 /*
106 * One timestamp came from userspace, and the other came
107 * from kernel space. Estimate the overhead as the mean
108 * between the two.
109 */
110 return (timestamp_overhead + user_timestamp_overhead) / 2;
111 }
112 #endif
113
114 /*
115 * Both start and finish timestamps were obtained
116 * from kernel space.
117 */
118 return timestamp_overhead;
119 }
120