-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathhrtimers-tester.c
153 lines (117 loc) · 3.61 KB
/
hrtimers-tester.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
* @file hrtimers-tester.c
* @author Antonio Petricca ([email protected])
* @date 20 Jun 2017
* @version 0.0.1
* @brief An implementation of a HR timers tester.
*/
#include <linux/hrtimer.h> // High Resolution Timers
#include <linux/init.h> // Macros used to mark up functions __init __exit
#include <linux/kernel.h> // Contains types, macros, functions for the kernel
#include <linux/ktime.h> // ktime_get, ...
#include <linux/module.h> // Core header for loading LKMs into the kernel
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Antonio Petricca ([email protected])");
MODULE_DESCRIPTION("HR timers tester.");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.1");
#define OUTER_LOOP_START 10 /* 10 uS */
#define OUTER_LOOP_END 1000000 /* 1 s */
#define LOOP_ITEMS 46
struct perf_sample
{
int expected;
ktime_t sampled;
};
static struct completion sem;
static struct hrtimer timer;
static ktime_t timer_incr;
static ktime_t timer_perf;
static int timer_perf_index;
static struct perf_sample timer_perf_samplings[LOOP_ITEMS];
static int inner_loop_index;
static int inner_loop_incr;
static int inner_loop_end;
enum hrtimer_restart hrtimers_test_callback(struct hrtimer *timer)
{
if (inner_loop_index >= inner_loop_end)
{
complete(&sem);
return HRTIMER_NORESTART;
}
timer_perf_samplings[timer_perf_index].expected = inner_loop_index;
timer_perf_samplings[timer_perf_index].sampled =
ktime_sub(ktime_get(), timer_perf);
/*pr_info(
" inner loop = %9d => %9llu\n",
inner_loop_index,
ktime_to_ns(timer_perf_samplings[timer_perf_index].sampled)
);*/
timer_perf_index++;
timer_perf = ktime_get();
inner_loop_index += inner_loop_incr;
timer_incr = ktime_set(0, (inner_loop_index * 1000));
hrtimer_forward_now(timer, timer_incr);
return HRTIMER_RESTART;
}
static void hrtimers_test_collect(void)
{
int outer_loop_index;
int outer_loop_end;
ktime_t perf_time;
pr_info("Collecting...\n");
init_completion(&sem);
hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
timer.function = &hrtimers_test_callback;
outer_loop_index = OUTER_LOOP_START;
outer_loop_end = (OUTER_LOOP_END / 10);
timer_perf_index = 0;
perf_time = ktime_get();
while (outer_loop_index <= outer_loop_end)
{
//pr_info("outer loop = %9d\n", outer_loop_index);
inner_loop_index = outer_loop_index;
inner_loop_incr = outer_loop_index;
timer_incr = ktime_set(0, (inner_loop_incr * 1000));
inner_loop_end =
(outer_loop_index < outer_loop_end)
? (inner_loop_index * 10)
: (inner_loop_index * (10 + 1))
;
timer_perf = ktime_get();
hrtimer_start(&timer, timer_incr, HRTIMER_MODE_REL);
wait_for_completion_killable(&sem);
outer_loop_index *= 10;
}
hrtimer_cancel(&timer);
pr_info(
"Completed in ~ %9llu ns.\n",
ktime_to_ns(ktime_sub(ktime_get(), perf_time))
);
}
static void hrtimers_test_print_samplings(void)
{
int index = 0;
pr_info("Sampled values:\n");
for (index = 0; index < LOOP_ITEMS; index++)
{
pr_info(
" [%2d] %7d = %10llu nS\n",
(index + 1),
timer_perf_samplings[index].expected,
ktime_to_ns(timer_perf_samplings[index].sampled)
);
}
}
static int __init hrtimers_test_init(void)
{
hrtimers_test_collect();
hrtimers_test_print_samplings();
return 0;
}
static void __exit hrtimers_test_exit(void)
{
pr_info("module unloaded.\n");
}
module_init(hrtimers_test_init);
module_exit(hrtimers_test_exit);