1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/compiler.h> |
3 | #include <linux/time64.h> |
4 | #include <inttypes.h> |
5 | #include <string.h> |
6 | #include "time-utils.h" |
7 | #include "evlist.h" |
8 | #include "session.h" |
9 | #include "debug.h" |
10 | #include "tests.h" |
11 | |
12 | static bool test__parse_nsec_time(const char *str, u64 expected) |
13 | { |
14 | u64 ptime; |
15 | int err; |
16 | |
17 | pr_debug("\nparse_nsec_time(\"%s\")\n" , str); |
18 | |
19 | err = parse_nsec_time(str, &ptime); |
20 | if (err) { |
21 | pr_debug("error %d\n" , err); |
22 | return false; |
23 | } |
24 | |
25 | if (ptime != expected) { |
26 | pr_debug("Failed. ptime %" PRIu64 " expected %" PRIu64 "\n" , |
27 | ptime, expected); |
28 | return false; |
29 | } |
30 | |
31 | pr_debug("%" PRIu64 "\n" , ptime); |
32 | |
33 | return true; |
34 | } |
35 | |
36 | static bool test__perf_time__parse_str(const char *ostr, u64 start, u64 end) |
37 | { |
38 | struct perf_time_interval ptime; |
39 | int err; |
40 | |
41 | pr_debug("\nperf_time__parse_str(\"%s\")\n" , ostr); |
42 | |
43 | err = perf_time__parse_str(&ptime, ostr); |
44 | if (err) { |
45 | pr_debug("Error %d\n" , err); |
46 | return false; |
47 | } |
48 | |
49 | if (ptime.start != start || ptime.end != end) { |
50 | pr_debug("Failed. Expected %" PRIu64 " to %" PRIu64 "\n" , |
51 | start, end); |
52 | return false; |
53 | } |
54 | |
55 | return true; |
56 | } |
57 | |
58 | #define TEST_MAX 64 |
59 | |
60 | struct test_data { |
61 | const char *str; |
62 | u64 first; |
63 | u64 last; |
64 | struct perf_time_interval ptime[TEST_MAX]; |
65 | int num; |
66 | u64 skip[TEST_MAX]; |
67 | u64 noskip[TEST_MAX]; |
68 | }; |
69 | |
70 | static bool test__perf_time__parse_for_ranges(struct test_data *d) |
71 | { |
72 | struct evlist evlist = { |
73 | .first_sample_time = d->first, |
74 | .last_sample_time = d->last, |
75 | }; |
76 | struct perf_session session = { .evlist = &evlist }; |
77 | struct perf_time_interval *ptime = NULL; |
78 | int range_size, range_num; |
79 | bool pass = false; |
80 | int i, err; |
81 | |
82 | pr_debug("\nperf_time__parse_for_ranges(\"%s\")\n" , d->str); |
83 | |
84 | if (strchr(d->str, '%')) |
85 | pr_debug("first_sample_time %" PRIu64 " last_sample_time %" PRIu64 "\n" , |
86 | d->first, d->last); |
87 | |
88 | err = perf_time__parse_for_ranges(d->str, &session, &ptime, &range_size, |
89 | &range_num); |
90 | if (err) { |
91 | pr_debug("error %d\n" , err); |
92 | goto out; |
93 | } |
94 | |
95 | if (range_size < d->num || range_num != d->num) { |
96 | pr_debug("bad size: range_size %d range_num %d expected num %d\n" , |
97 | range_size, range_num, d->num); |
98 | goto out; |
99 | } |
100 | |
101 | for (i = 0; i < d->num; i++) { |
102 | if (ptime[i].start != d->ptime[i].start || |
103 | ptime[i].end != d->ptime[i].end) { |
104 | pr_debug("bad range %d expected %" PRIu64 " to %" PRIu64 "\n" , |
105 | i, d->ptime[i].start, d->ptime[i].end); |
106 | goto out; |
107 | } |
108 | } |
109 | |
110 | if (perf_time__ranges_skip_sample(ptime, d->num, 0)) { |
111 | pr_debug("failed to keep 0\n" ); |
112 | goto out; |
113 | } |
114 | |
115 | for (i = 0; i < TEST_MAX; i++) { |
116 | if (d->skip[i] && |
117 | !perf_time__ranges_skip_sample(ptime, d->num, d->skip[i])) { |
118 | pr_debug("failed to skip %" PRIu64 "\n" , d->skip[i]); |
119 | goto out; |
120 | } |
121 | if (d->noskip[i] && |
122 | perf_time__ranges_skip_sample(ptime, d->num, d->noskip[i])) { |
123 | pr_debug("failed to keep %" PRIu64 "\n" , d->noskip[i]); |
124 | goto out; |
125 | } |
126 | } |
127 | |
128 | pass = true; |
129 | out: |
130 | free(ptime); |
131 | return pass; |
132 | } |
133 | |
134 | static int test__time_utils(struct test_suite *t __maybe_unused, int subtest __maybe_unused) |
135 | { |
136 | bool pass = true; |
137 | |
138 | pass &= test__parse_nsec_time(str: "0" , expected: 0); |
139 | pass &= test__parse_nsec_time(str: "1" , expected: 1000000000ULL); |
140 | pass &= test__parse_nsec_time(str: "0.000000001" , expected: 1); |
141 | pass &= test__parse_nsec_time(str: "1.000000001" , expected: 1000000001ULL); |
142 | pass &= test__parse_nsec_time(str: "123456.123456" , expected: 123456123456000ULL); |
143 | pass &= test__parse_nsec_time(str: "1234567.123456789" , expected: 1234567123456789ULL); |
144 | pass &= test__parse_nsec_time(str: "18446744073.709551615" , |
145 | expected: 0xFFFFFFFFFFFFFFFFULL); |
146 | |
147 | pass &= test__perf_time__parse_str(ostr: "1234567.123456789,1234567.123456789" , |
148 | start: 1234567123456789ULL, end: 1234567123456789ULL); |
149 | pass &= test__perf_time__parse_str(ostr: "1234567.123456789,1234567.123456790" , |
150 | start: 1234567123456789ULL, end: 1234567123456790ULL); |
151 | pass &= test__perf_time__parse_str(ostr: "1234567.123456789," , |
152 | start: 1234567123456789ULL, end: 0); |
153 | pass &= test__perf_time__parse_str(ostr: ",1234567.123456789" , |
154 | start: 0, end: 1234567123456789ULL); |
155 | pass &= test__perf_time__parse_str(ostr: "0,1234567.123456789" , |
156 | start: 0, end: 1234567123456789ULL); |
157 | |
158 | { |
159 | u64 b = 1234567123456789ULL; |
160 | struct test_data d = { |
161 | .str = "1234567.123456789,1234567.123456790" , |
162 | .ptime = { {b, b + 1}, }, |
163 | .num = 1, |
164 | .skip = { b - 1, b + 2, }, |
165 | .noskip = { b, b + 1, }, |
166 | }; |
167 | |
168 | pass &= test__perf_time__parse_for_ranges(d: &d); |
169 | } |
170 | |
171 | { |
172 | u64 b = 1234567123456789ULL; |
173 | u64 c = 7654321987654321ULL; |
174 | u64 e = 8000000000000000ULL; |
175 | struct test_data d = { |
176 | .str = "1234567.123456789,1234567.123456790 " |
177 | "7654321.987654321,7654321.987654444 " |
178 | "8000000,8000000.000000005" , |
179 | .ptime = { {b, b + 1}, {c, c + 123}, {e, e + 5}, }, |
180 | .num = 3, |
181 | .skip = { b - 1, b + 2, c - 1, c + 124, e - 1, e + 6 }, |
182 | .noskip = { b, b + 1, c, c + 123, e, e + 5 }, |
183 | }; |
184 | |
185 | pass &= test__perf_time__parse_for_ranges(d: &d); |
186 | } |
187 | |
188 | { |
189 | u64 b = 7654321ULL * NSEC_PER_SEC; |
190 | struct test_data d = { |
191 | .str = "10%/1" , |
192 | .first = b, |
193 | .last = b + 100, |
194 | .ptime = { {b, b + 9}, }, |
195 | .num = 1, |
196 | .skip = { b - 1, b + 10, }, |
197 | .noskip = { b, b + 9, }, |
198 | }; |
199 | |
200 | pass &= test__perf_time__parse_for_ranges(d: &d); |
201 | } |
202 | |
203 | { |
204 | u64 b = 7654321ULL * NSEC_PER_SEC; |
205 | struct test_data d = { |
206 | .str = "10%/2" , |
207 | .first = b, |
208 | .last = b + 100, |
209 | .ptime = { {b + 10, b + 19}, }, |
210 | .num = 1, |
211 | .skip = { b + 9, b + 20, }, |
212 | .noskip = { b + 10, b + 19, }, |
213 | }; |
214 | |
215 | pass &= test__perf_time__parse_for_ranges(d: &d); |
216 | } |
217 | |
218 | { |
219 | u64 b = 11223344ULL * NSEC_PER_SEC; |
220 | struct test_data d = { |
221 | .str = "10%/1,10%/2" , |
222 | .first = b, |
223 | .last = b + 100, |
224 | .ptime = { {b, b + 9}, {b + 10, b + 19}, }, |
225 | .num = 2, |
226 | .skip = { b - 1, b + 20, }, |
227 | .noskip = { b, b + 8, b + 9, b + 10, b + 11, b + 12, b + 19, }, |
228 | }; |
229 | |
230 | pass &= test__perf_time__parse_for_ranges(d: &d); |
231 | } |
232 | |
233 | { |
234 | u64 b = 11223344ULL * NSEC_PER_SEC; |
235 | struct test_data d = { |
236 | .str = "10%/1,10%/3,10%/10" , |
237 | .first = b, |
238 | .last = b + 100, |
239 | .ptime = { {b, b + 9}, {b + 20, b + 29}, { b + 90, b + 100}, }, |
240 | .num = 3, |
241 | .skip = { b - 1, b + 10, b + 19, b + 30, b + 89, b + 101 }, |
242 | .noskip = { b, b + 9, b + 20, b + 29, b + 90, b + 100}, |
243 | }; |
244 | |
245 | pass &= test__perf_time__parse_for_ranges(d: &d); |
246 | } |
247 | |
248 | pr_debug("\n" ); |
249 | |
250 | return pass ? 0 : TEST_FAIL; |
251 | } |
252 | |
253 | DEFINE_SUITE("time utils" , time_utils); |
254 | |