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 <zephyr/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