1 // Copyright 2021 (c) Apple Inc. All rights reserved.
2
3 #include <darwintest.h>
4 #include <darwintest_utils.h>
5 #include <libproc.h>
6 #include <mach/mach.h>
7 #include <mach/task.h>
8 #include <mach/task_info.h>
9 #include <mach/thread_info.h>
10 #include <os/base.h>
11 #include <stdint.h>
12 #include <sys/resource.h>
13 #include <sys/resource_private.h>
14 #include <unistd.h>
15
16 #include "test_utils.h"
17 #include "recount_test_utils.h"
18
19 T_GLOBAL_META(
20 T_META_RADAR_COMPONENT_NAME("xnu"),
21 T_META_RADAR_COMPONENT_VERSION("RM"),
22 T_META_OWNER("mwidmann"),
23 T_META_CHECK_LEAKS(false),
24 T_META_TAG_PERF);
25
26 __options_decl(metrics_t, uint32_t, {
27 METRIC_INSNS = 0x01,
28 METRIC_CYCLES = 0x02,
29 METRIC_SYS_TIME = 0x04,
30 METRIC_CPU_TIME = 0x08,
31 });
32 #define METRIC_COUNT (4)
33
34 static const char *metric_units[METRIC_COUNT] = {
35 "instructions",
36 "cycles",
37 "CPUns",
38 "CPUns",
39 };
40
41 static const char *metric_names[METRIC_COUNT] = {
42 "insns",
43 "cycles",
44 "sys_time",
45 "cpu_time",
46 };
47
48 static int
next_bit(uint32_t * bits)49 next_bit(uint32_t *bits)
50 {
51 if (*bits == 0) {
52 return -1;
53 }
54 int bit = __builtin_ctzll(*bits);
55 *bits &= ~(1U << bit);
56 return bit;
57 }
58
59 struct measure {
60 dt_stat_t m_stat;
61 metrics_t m_metric;
62 };
63
64 static bool
measures_stable(struct measure * measures)65 measures_stable(struct measure *measures)
66 {
67 for (int i = 0; i < METRIC_COUNT; i++) {
68 if (measures[i].m_stat && !dt_stat_stable(measures[i].m_stat)) {
69 return false;
70 }
71 }
72 return true;
73 }
74
75 struct usage_scenario {
76 const char *us_stat_name;
77 void (^us_modify_stat)(dt_stat_t);
78 void (*us_call)(void *);
79 double (*us_measure)(metrics_t, void *);
80 void *us_context;
81 metrics_t us_metrics;
82 };
83
84 static void
interface_perf_test(struct usage_scenario * s)85 interface_perf_test(struct usage_scenario *s)
86 {
87 metrics_t metrics = s->us_metrics;
88
89 T_SETUPBEGIN;
90 if (!has_cpi()) {
91 metrics &= ~(METRIC_INSNS | METRIC_CYCLES);
92 }
93
94 struct measure measures[4] = { 0 };
95 for (int metric = next_bit(&metrics); metric >= 0;
96 metric = next_bit(&metrics)) {
97 switch (1U << metric) {
98 case METRIC_CPU_TIME:
99 case METRIC_SYS_TIME:
100 measures[metric].m_stat = (dt_stat_t)dt_stat_time_create("%s_%s",
101 s->us_stat_name, metric_names[metric]);
102 break;
103 case METRIC_INSNS:
104 case METRIC_CYCLES:
105 measures[metric].m_stat = dt_stat_create(metric_units[metric],
106 "%s_%s", s->us_stat_name, metric_names[metric]);
107 break;
108 default:
109 T_ASSERT_FAIL("unexpected metric %d", metric);
110 break;
111 }
112 if (s->us_modify_stat) {
113 s->us_modify_stat(measures[metric].m_stat);
114 }
115 measures[metric].m_metric = 1U << metric;
116 }
117
118 while (!measures_stable(measures)) {
119 s->us_call(s->us_context);
120 for (int i = 0; i < METRIC_COUNT; i++) {
121 if (measures[i].m_stat) {
122 double m = s->us_measure(measures[i].m_metric, s->us_context);
123 dt_stat_add(measures[i].m_stat, m);
124 }
125 }
126 }
127
128 for (int i = 0; i < METRIC_COUNT; i++) {
129 if (measures[i].m_stat) {
130 dt_stat_finalize(measures[i].m_stat);
131 }
132 }
133 }
134
135 static void
interface_scaling_test(struct usage_scenario * s)136 interface_scaling_test(struct usage_scenario *s)
137 {
138 unsigned int thread_counts[] = { 1, 4, 8, 16, 32, 64, 128, 256, };
139
140 for (unsigned int i = 0; i < ARRAY_COUNT(thread_counts); i++) {
141 unsigned int n = thread_counts[i];
142 struct scene *scene = scene_start(n - 1,
143 (role_t []){ ROLE_WAIT, ROLE_NONE, });
144 T_LOG("%u threads", n);
145 s->us_modify_stat = ^(dt_stat_t stat) {
146 dt_stat_set_variable(stat, "threads", n);
147 };
148 interface_perf_test(s);
149 scene_end(scene);
150 }
151 }
152
153 static void
proc_pidtaskinfo_usage(void * ctx)154 proc_pidtaskinfo_usage(void *ctx)
155 {
156 struct proc_taskinfo before = { 0 };
157 struct proc_taskinfo after = { 0 };
158 pid_t pid = getpid();
159 int before_ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &before,
160 sizeof(before));
161 int after_ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &after,
162 sizeof(after));
163
164 T_SETUPBEGIN;
165 T_QUIET;
166 T_ASSERT_POSIX_SUCCESS(before_ret,
167 "proc_pidinfo(..., PROC_PIDTASKINFO, ...)");
168 T_QUIET;
169 T_ASSERT_POSIX_SUCCESS(after_ret,
170 "proc_pidinfo(..., PROC_PIDTASKINFO, ...)");
171 T_SETUPEND;
172
173 struct proc_taskinfo *delta = ctx;
174 delta->pti_total_user = ns_from_mach(after.pti_total_user -
175 before.pti_total_user);
176 delta->pti_total_system = ns_from_mach(after.pti_total_system -
177 before.pti_total_system);
178 }
179
180 static double
proc_pidtaskinfo_measurement(metrics_t metric,void * ctx)181 proc_pidtaskinfo_measurement(metrics_t metric, void *ctx)
182 {
183 struct proc_taskinfo *info = ctx;
184 switch (metric) {
185 case METRIC_CPU_TIME:
186 return (double)(info->pti_total_user + info->pti_total_system) / 1e9;
187 case METRIC_SYS_TIME:
188 return (double)info->pti_total_system / 1e9;
189 default:
190 T_ASSERT_FAIL("unsupported metric %d for proc_pidtaskinfo", metric);
191 }
192 }
193
194 static void
proc_pid_rusage_usage(void * ctx)195 proc_pid_rusage_usage(void *ctx)
196 {
197 struct rusage_info_v5 before = { 0 };
198 struct rusage_info_v5 after = { 0 };
199 pid_t pid = getpid();
200 int before_ret = proc_pid_rusage(pid, RUSAGE_INFO_V5,
201 (rusage_info_t *)&before);
202 int after_ret = proc_pid_rusage(pid, RUSAGE_INFO_V5,
203 (rusage_info_t *)&after);
204
205 T_SETUPBEGIN;
206 T_QUIET;
207 T_ASSERT_POSIX_SUCCESS(before_ret, "proc_pid_rusage()");
208 T_QUIET;
209 T_ASSERT_POSIX_SUCCESS(after_ret, "proc_pid_rusage()");
210 T_SETUPEND;
211
212 struct rusage_info_v5 *delta = ctx;
213 delta->ri_user_time = ns_from_mach(after.ri_user_time -
214 before.ri_user_time);
215 delta->ri_system_time = ns_from_mach(after.ri_system_time -
216 before.ri_system_time);
217 delta->ri_cycles = after.ri_cycles - before.ri_cycles;
218 delta->ri_instructions = after.ri_instructions - before.ri_instructions;
219 }
220
221 static double
proc_pid_rusage_measurement(metrics_t metric,void * ctx)222 proc_pid_rusage_measurement(metrics_t metric, void *ctx)
223 {
224 struct rusage_info_v5 *info = ctx;
225 switch (metric) {
226 case METRIC_CPU_TIME:
227 return (double)(info->ri_user_time + info->ri_system_time) / 1e9;
228 case METRIC_SYS_TIME:
229 return (double)info->ri_system_time / 1e9;
230 case METRIC_INSNS:
231 return (double)info->ri_instructions;
232 case METRIC_CYCLES:
233 return (double)info->ri_cycles;
234 }
235 }
236
237 static const int RUSAGE_ITERS = 10;
238
239 static double
getrusage_measurement(metrics_t metric,void * ctx)240 getrusage_measurement(metrics_t metric, void *ctx)
241 {
242 struct rusage *usage = ctx;
243 switch (metric) {
244 case METRIC_CPU_TIME:
245 return (double)(ns_from_timeval(usage->ru_utime) +
246 ns_from_timeval(usage->ru_stime)) / 1e9 / RUSAGE_ITERS;
247 case METRIC_SYS_TIME:
248 return (double)ns_from_timeval(usage->ru_stime) / 1e9 / RUSAGE_ITERS;
249 default:
250 T_ASSERT_FAIL("unexpected metric %d", metric);
251 }
252 }
253
254 static void
getrusage_usage(void * ctx)255 getrusage_usage(void *ctx)
256 {
257 struct rusage before = { 0 };
258 struct rusage after = { 0 };
259 int before_ret = getrusage(RUSAGE_SELF, &before);
260 for (int i = 0; i < RUSAGE_ITERS; i++) {
261 // getrusage(2) is limited to microsecond precision, so loop around it
262 // to increase its duration.
263 getrusage(RUSAGE_SELF, &after);
264 }
265 int after_ret = getrusage(RUSAGE_SELF, &after);
266 T_SETUPBEGIN;
267 T_QUIET;
268 T_ASSERT_POSIX_SUCCESS(before_ret, "getrusage()");
269 T_QUIET;
270 T_ASSERT_POSIX_SUCCESS(after_ret, "getrusage()");
271 T_SETUPEND;
272
273 struct rusage *delta = ctx;
274 delta->ru_utime = timeval_from_ns(ns_from_timeval(after.ru_utime) -
275 ns_from_timeval(before.ru_utime));
276 delta->ru_stime = timeval_from_ns(ns_from_timeval(after.ru_stime) -
277 ns_from_timeval(before.ru_stime));
278 }
279
280 static void
thread_selfcounts_usage(void * ctx)281 thread_selfcounts_usage(void *ctx)
282 {
283 struct thsc_time_cpi before = { 0 };
284 struct thsc_time_cpi after = { 0 };
285 int before_ret = thread_selfcounts(THSC_TIME_CPI, &before, sizeof(before));
286 int after_ret = thread_selfcounts(THSC_TIME_CPI, &after, sizeof(after));
287
288 T_SETUPBEGIN;
289 T_QUIET;
290 T_ASSERT_POSIX_SUCCESS(before_ret, "thread_selfcounts(THSC_TIME_CPI, ...)");
291 T_QUIET;
292 T_ASSERT_POSIX_SUCCESS(after_ret, "thread_selfcounts(THSC_TIME_CPI, ...)");
293 T_SETUPEND;
294
295 struct thsc_time_cpi *counts = ctx;
296 counts->ttci_user_time_mach = after.ttci_user_time_mach -
297 before.ttci_user_time_mach;
298 counts->ttci_system_time_mach = after.ttci_system_time_mach -
299 before.ttci_system_time_mach;
300 counts->ttci_instructions = after.ttci_instructions -
301 before.ttci_instructions;
302 counts->ttci_cycles = after.ttci_cycles - before.ttci_cycles;
303 }
304
305 static double
thread_selfcounts_measurement(metrics_t metric,void * ctx)306 thread_selfcounts_measurement(metrics_t metric, void *ctx)
307 {
308 struct thsc_time_cpi *counts = ctx;
309 switch (metric) {
310 case METRIC_CPU_TIME:
311 return (double)ns_from_mach(counts->ttci_user_time_mach +
312 counts->ttci_system_time_mach) / 1e9;
313 case METRIC_SYS_TIME:
314 return (double)ns_from_mach(counts->ttci_system_time_mach) / 1e9;
315 case METRIC_INSNS:
316 return (double)counts->ttci_instructions;
317 case METRIC_CYCLES:
318 return (double)counts->ttci_cycles;
319 }
320 }
321
322 static void
thread_selfusage_usage(void * ctx)323 thread_selfusage_usage(void *ctx)
324 {
325 uint64_t before = __thread_selfusage();
326 uint64_t after = __thread_selfusage();
327 uint64_t *delta = ctx;
328 *delta = after - before;
329 }
330
331 static double
thread_selfusage_measurement(metrics_t metric,void * ctx)332 thread_selfusage_measurement(metrics_t metric, void *ctx)
333 {
334 uint64_t *delta = ctx;
335 if (metric != METRIC_CPU_TIME) {
336 T_ASSERT_FAIL("unsupported metric %d for thread_selfusage", metric);
337 }
338 return (double)ns_from_mach(*delta);
339 }
340
341 static void
task_power_info_usage(void * ctx)342 task_power_info_usage(void *ctx)
343 {
344 struct task_power_info before = { 0 };
345 struct task_power_info after = { 0 };
346 mach_msg_type_number_t info_count = TASK_POWER_INFO_COUNT;
347 kern_return_t before_kr = task_info(mach_task_self(), TASK_POWER_INFO,
348 (task_info_t)&before, &info_count);
349 info_count = TASK_POWER_INFO_COUNT;
350 kern_return_t after_kr = task_info(mach_task_self(), TASK_POWER_INFO,
351 (task_info_t)&after, &info_count);
352
353 T_SETUPBEGIN;
354 T_QUIET;
355 T_ASSERT_MACH_SUCCESS(before_kr, "task_info(... TASK_POWER_INFO ...)");
356 T_QUIET;
357 T_ASSERT_MACH_SUCCESS(after_kr, "task_info(... TASK_POWER_INFO ...)");
358 T_SETUPEND;
359
360 struct task_power_info *info = ctx;
361 info->total_user = after.total_user - before.total_user;
362 info->total_system = after.total_system - before.total_system;
363 }
364
365 static double
task_power_info_measurement(metrics_t metric,void * ctx)366 task_power_info_measurement(metrics_t metric, void *ctx)
367 {
368 struct task_power_info *info = ctx;
369 uint64_t ns = 0;
370 switch (metric) {
371 case METRIC_CPU_TIME:
372 ns = ns_from_mach(info->total_user) + ns_from_mach(info->total_system);
373 break;
374 case METRIC_SYS_TIME:
375 ns = ns_from_mach(info->total_system);
376 break;
377 case METRIC_INSNS:
378 case METRIC_CYCLES:
379 default:
380 T_ASSERT_FAIL("unsupported metric %d for task_power_info", metric);
381 }
382 return (double)ns / 1e9;
383 }
384
385 static const int THREAD_BASIC_INFO_ITERS = 1000;
386
387 static void
thread_basic_info_usage(void * ctx)388 thread_basic_info_usage(void *ctx)
389 {
390 struct thread_basic_info before = { 0 };
391 struct thread_basic_info after = { 0 };
392 mach_msg_type_number_t info_count = THREAD_BASIC_INFO_COUNT;
393 kern_return_t before_kr = thread_info(mach_thread_self(), THREAD_BASIC_INFO,
394 (thread_info_t)&before, &info_count);
395 for (int i = 0; i < THREAD_BASIC_INFO_ITERS; i++) {
396 info_count = THREAD_BASIC_INFO_COUNT;
397 thread_info(mach_thread_self(), THREAD_BASIC_INFO,
398 (thread_info_t)&after, &info_count);
399 }
400 info_count = THREAD_BASIC_INFO_COUNT;
401 kern_return_t after_kr = thread_info(mach_thread_self(), THREAD_BASIC_INFO,
402 (thread_info_t)&after, &info_count);
403
404 T_SETUPBEGIN;
405 T_QUIET;
406 T_ASSERT_POSIX_SUCCESS(before_kr, "thread_info(... THREAD_BASIC_INFO ...)");
407 T_QUIET;
408 T_ASSERT_POSIX_SUCCESS(after_kr, "thread_info(... THREAD_BASIC_INFO ...)");
409 T_SETUPEND;
410
411 struct thread_basic_info *info = ctx;
412
413 info->user_time = time_value_from_ns(ns_from_time_value(after.user_time) -
414 ns_from_time_value(before.user_time));
415 info->system_time = time_value_from_ns(
416 ns_from_time_value(after.system_time) -
417 ns_from_time_value(before.system_time));
418 }
419
420 static double
thread_basic_info_measurement(metrics_t metric,void * ctx)421 thread_basic_info_measurement(metrics_t metric, void *ctx)
422 {
423 struct thread_basic_info *info = ctx;
424 uint64_t ns = 0;
425 switch (metric) {
426 case METRIC_CPU_TIME:
427 ns = ns_from_time_value(info->user_time) +
428 ns_from_time_value(info->system_time);
429 break;
430 case METRIC_SYS_TIME:
431 ns = ns_from_time_value(info->system_time);
432 break;
433 case METRIC_INSNS:
434 case METRIC_CYCLES:
435 default:
436 T_ASSERT_FAIL("unsupported metric %d for thread_basic_info", metric);
437 }
438 return (double)ns / 1e9 / THREAD_BASIC_INFO_ITERS;
439 }
440
441 static void
task_inspect_basic_counts_usage(void * ctx)442 task_inspect_basic_counts_usage(void *ctx)
443 {
444 struct task_inspect_basic_counts before = { 0 };
445 struct task_inspect_basic_counts after = { 0 };
446 mach_msg_type_number_t info_count = TASK_INSPECT_BASIC_COUNTS_COUNT;
447 kern_return_t before_kr = task_inspect(mach_task_self(),
448 TASK_INSPECT_BASIC_COUNTS, (task_inspect_info_t)&before,
449 &info_count);
450 info_count = TASK_INSPECT_BASIC_COUNTS_COUNT;
451 kern_return_t after_kr = task_inspect(mach_task_self(),
452 TASK_INSPECT_BASIC_COUNTS, (task_inspect_info_t)&after,
453 &info_count);
454
455 T_SETUPBEGIN;
456 T_QUIET;
457 T_ASSERT_POSIX_SUCCESS(before_kr,
458 "task_inspect(... TASK_INSPECT_BASIC_COUNTS ...)");
459 T_QUIET;
460 T_ASSERT_POSIX_SUCCESS(after_kr,
461 "task_inspect(... TASK_INSPECT_BASIC_COUNTS ...)");
462 T_SETUPEND;
463
464 struct task_inspect_basic_counts *counts = ctx;
465 counts->instructions = after.instructions - before.instructions;
466 counts->cycles = after.cycles - before.cycles;
467 }
468
469 static double
task_inspect_basic_counts_measurement(metrics_t metric,void * ctx)470 task_inspect_basic_counts_measurement(metrics_t metric, void *ctx)
471 {
472 struct task_inspect_basic_counts *counts = ctx;
473 switch (metric) {
474 case METRIC_INSNS:
475 return (double)counts->instructions;
476 case METRIC_CYCLES:
477 return (double)counts->cycles;
478 case METRIC_SYS_TIME:
479 case METRIC_CPU_TIME:
480 default:
481 T_ASSERT_FAIL("unsupported metric %d for task_inspect_basic_counts",
482 metric);
483 }
484 }
485
486 static void
task_absolutetime_info_usage(void * ctx)487 task_absolutetime_info_usage(void *ctx)
488 {
489 task_absolutetime_info_data_t before = { 0 };
490 task_absolutetime_info_data_t after = { 0 };
491 mach_msg_type_number_t info_count = TASK_ABSOLUTETIME_INFO_COUNT;
492 kern_return_t before_kr = task_info(mach_task_self(),
493 TASK_ABSOLUTETIME_INFO, (task_info_t)&before,
494 &info_count);
495 info_count = TASK_ABSOLUTETIME_INFO_COUNT;
496 kern_return_t after_kr = task_info(mach_task_self(),
497 TASK_ABSOLUTETIME_INFO, (task_info_t)&after,
498 &info_count);
499
500 T_SETUPBEGIN;
501 T_QUIET;
502 T_ASSERT_POSIX_SUCCESS(before_kr,
503 "task_info(... TASK_ABSOLUTETIME_INFO ...)");
504 T_QUIET;
505 T_ASSERT_POSIX_SUCCESS(after_kr,
506 "task_info(... TASK_ABSOLUTETIME_INFO ...)");
507 T_SETUPEND;
508
509 task_absolutetime_info_data_t *counts = ctx;
510 counts->total_user = after.total_user - before.total_user;
511 counts->total_system = after.total_system - before.total_system;
512 }
513
514 static double
task_absolutetime_info_measurement(metrics_t metric,void * ctx)515 task_absolutetime_info_measurement(metrics_t metric, void *ctx)
516 {
517 task_absolutetime_info_data_t *counts = ctx;
518 switch (metric) {
519 case METRIC_CPU_TIME:
520 return (double)counts->total_user + counts->total_system;
521 case METRIC_SYS_TIME:
522 return (double)counts->total_system;
523 case METRIC_INSNS:
524 case METRIC_CYCLES:
525 default:
526 T_ASSERT_FAIL("unsupported metric %d for task_absolutetime_info",
527 metric);
528 }
529 }
530
531 T_DECL(task_usage_perf, "measure the performance of task usage interfaces")
532 {
533 struct proc_taskinfo pti = { 0 };
534 struct usage_scenario pti_scenario = {
535 .us_stat_name = "proc_pidtaskinfo",
536 .us_call = proc_pidtaskinfo_usage,
537 .us_measure = proc_pidtaskinfo_measurement,
538 .us_context = &pti,
539 .us_metrics = METRIC_CPU_TIME | METRIC_SYS_TIME,
540 };
541 interface_scaling_test(&pti_scenario);
542
543 struct rusage_info_v5 rui = { 0 };
544 struct usage_scenario ppr_scenario = {
545 .us_stat_name = "proc_pid_rusage",
546 .us_call = proc_pid_rusage_usage,
547 .us_measure = proc_pid_rusage_measurement,
548 .us_context = &rui,
549 .us_metrics = METRIC_INSNS | METRIC_CYCLES | METRIC_CPU_TIME |
550 METRIC_SYS_TIME,
551 };
552 interface_scaling_test(&ppr_scenario);
553
554 struct rusage usage = { 0 };
555 struct usage_scenario gru_scenario = {
556 .us_stat_name = "getrusage",
557 .us_call = getrusage_usage,
558 .us_measure = getrusage_measurement,
559 .us_context = &usage,
560 .us_metrics = METRIC_CPU_TIME | METRIC_SYS_TIME,
561 };
562 interface_scaling_test(&gru_scenario);
563
564 struct task_power_info tpi = { 0 };
565 struct usage_scenario tpi_scenario = {
566 .us_stat_name = "task_power_info",
567 .us_call = task_power_info_usage,
568 .us_measure = task_power_info_measurement,
569 .us_context = &tpi,
570 .us_metrics = METRIC_CPU_TIME | METRIC_SYS_TIME,
571 };
572 interface_scaling_test(&tpi_scenario);
573
574 task_absolutetime_info_data_t tati = { 0 };
575 struct usage_scenario tati_scenario = {
576 .us_stat_name = "task_absolutetime_info",
577 .us_call = task_absolutetime_info_usage,
578 .us_measure = task_absolutetime_info_measurement,
579 .us_context = &tati,
580 .us_metrics = METRIC_CPU_TIME | METRIC_SYS_TIME,
581 };
582 interface_scaling_test(&tati_scenario);
583
584 struct task_inspect_basic_counts counts = { 0 };
585 struct usage_scenario tibc_scenario = {
586 .us_stat_name = "task_inspect_basic_counts",
587 .us_call = task_inspect_basic_counts_usage,
588 .us_measure = task_inspect_basic_counts_measurement,
589 .us_context = &counts,
590 .us_metrics = METRIC_INSNS | METRIC_CYCLES,
591 };
592 interface_scaling_test(&tibc_scenario);
593 }
594
595 T_DECL(thread_usage_perf, "measure the performance of thread usage interfaces")
596 {
597 struct thsc_time_cpi counts = { 0 };
598 struct usage_scenario tsc_scenario = {
599 .us_stat_name = "thread_selfcounts",
600 .us_call = thread_selfcounts_usage,
601 .us_measure = thread_selfcounts_measurement,
602 .us_context = &counts,
603 .us_metrics = METRIC_INSNS | METRIC_CYCLES | METRIC_CPU_TIME |
604 METRIC_SYS_TIME,
605 };
606 interface_perf_test(&tsc_scenario);
607
608 uint64_t usage = 0;
609 struct usage_scenario tsu_scenario = {
610 .us_stat_name = "thread_selfusage",
611 .us_call = thread_selfusage_usage,
612 .us_measure = thread_selfusage_measurement,
613 .us_context = &usage,
614 .us_metrics = METRIC_CPU_TIME,
615 };
616 interface_perf_test(&tsu_scenario);
617
618 struct thread_basic_info info = { 0 };
619 struct usage_scenario tbi_scenario = {
620 .us_stat_name = "thread_basic_info",
621 .us_call = thread_basic_info_usage,
622 .us_measure = thread_basic_info_measurement,
623 .us_context = &info,
624 .us_metrics = METRIC_CPU_TIME | METRIC_SYS_TIME,
625 };
626 interface_perf_test(&tbi_scenario);
627 }
628