1 /*
2 * Copyright (c) 2018 Google, Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 *
6 * A CFS task and an RT task are created and affined to the same CPU. The CFS
7 * task is a CPU hog. The latency for the RT task to execute after it has been
8 * woken is measured and verified.
9 */
10
11 #define _GNU_SOURCE
12 #include <errno.h>
13 #include <pthread.h>
14 #include <sched.h>
15 #include <semaphore.h>
16 #include <time.h>
17
18 #include "tst_test.h"
19 #include "tst_safe_file_ops.h"
20 #include "tst_safe_pthread.h"
21
22 #include "trace_parse.h"
23 #include "util.h"
24
25 #define TRACE_EVENTS "sched_wakeup sched_switch"
26
27 #define MAX_EXEC_LATENCY_US 100
28
29 static int rt_task_tid;
30 static sem_t sem;
31
rt_fn(void * arg LTP_ATTRIBUTE_UNUSED)32 static void *rt_fn(void *arg LTP_ATTRIBUTE_UNUSED)
33 {
34 rt_task_tid = gettid();
35 affine(0);
36 sem_wait(&sem);
37 return NULL;
38 }
39
40 #define BURN_MSEC 1000
cfs_fn(void * arg LTP_ATTRIBUTE_UNUSED)41 static void *cfs_fn(void *arg LTP_ATTRIBUTE_UNUSED)
42 {
43 affine(0);
44
45 usleep(5000);
46 SAFE_FILE_PRINTF(TRACING_DIR "trace_marker", "WAKING");
47 sem_post(&sem);
48
49 burn(USEC_PER_SEC, 0);
50 return NULL;
51 }
52
parse_results(void)53 static int parse_results(void)
54 {
55 int i;
56 unsigned long long rt_wakeup_ts_us = 0;
57 unsigned long long rt_exec_ts_us = 0;
58 unsigned long rt_exec_latency_us;
59
60 for (i = 0; i < num_trace_records; i++) {
61 if (trace[i].event_type == TRACE_RECORD_SCHED_WAKEUP) {
62 struct trace_sched_wakeup *t = trace[i].event_data;
63 if (t->pid != rt_task_tid)
64 continue;
65 rt_wakeup_ts_us = TS_TO_USEC(trace[i].ts);
66 continue;
67 }
68 if (rt_wakeup_ts_us &&
69 trace[i].event_type == TRACE_RECORD_SCHED_SWITCH) {
70 struct trace_sched_switch *t = trace[i].event_data;
71 if (t->next_pid != rt_task_tid)
72 continue;
73 if (!rt_wakeup_ts_us) {
74 printf("RT task woke without being woken!\n");
75 return -1;
76 }
77 rt_exec_ts_us = TS_TO_USEC(trace[i].ts);
78 break;
79 }
80 }
81 if (!rt_wakeup_ts_us || !rt_exec_ts_us) {
82 printf("RT task either wasn't woken or didn't wake up.\n");
83 return -1;
84 }
85 rt_exec_latency_us = rt_exec_ts_us - rt_wakeup_ts_us;
86 printf("RT exec latency: %ld usec\n", rt_exec_latency_us);
87 return (rt_exec_latency_us > MAX_EXEC_LATENCY_US);
88 }
89
run(void)90 static void run(void)
91 {
92 pthread_t cfs_thread;
93 pthread_t rt_thread;
94 pthread_attr_t cfs_thread_attrs;
95 pthread_attr_t rt_thread_attrs;
96 struct sched_param cfs_thread_sched_params;
97 struct sched_param rt_thread_sched_params;
98
99 ERROR_CHECK(pthread_attr_init(&cfs_thread_attrs));
100 ERROR_CHECK(pthread_attr_setinheritsched(&cfs_thread_attrs,
101 PTHREAD_EXPLICIT_SCHED));
102 ERROR_CHECK(pthread_attr_setschedpolicy(&cfs_thread_attrs,
103 SCHED_OTHER));
104 cfs_thread_sched_params.sched_priority = 0;
105 ERROR_CHECK(pthread_attr_setschedparam(&cfs_thread_attrs,
106 &cfs_thread_sched_params));
107
108 ERROR_CHECK(pthread_attr_init(&rt_thread_attrs));
109 ERROR_CHECK(pthread_attr_setinheritsched(&rt_thread_attrs,
110 PTHREAD_EXPLICIT_SCHED));
111 ERROR_CHECK(pthread_attr_setschedpolicy(&rt_thread_attrs,
112 SCHED_FIFO));
113 rt_thread_sched_params.sched_priority = 80;
114 ERROR_CHECK(pthread_attr_setschedparam(&rt_thread_attrs,
115 &rt_thread_sched_params));
116
117 sem_init(&sem, 0, 0);
118
119 /* configure and enable tracing */
120 SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "0");
121 SAFE_FILE_PRINTF(TRACING_DIR "buffer_size_kb", "16384");
122 SAFE_FILE_PRINTF(TRACING_DIR "set_event", TRACE_EVENTS);
123 SAFE_FILE_PRINTF(TRACING_DIR "trace", "\n");
124 SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "1");
125
126 SAFE_PTHREAD_CREATE(&cfs_thread, &cfs_thread_attrs, cfs_fn, NULL);
127 SAFE_PTHREAD_CREATE(&rt_thread, &rt_thread_attrs, rt_fn, NULL);
128 SAFE_PTHREAD_JOIN(cfs_thread, NULL);
129 SAFE_PTHREAD_JOIN(rt_thread, NULL);
130
131 /* disable tracing */
132 SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "0");
133 LOAD_TRACE();
134
135 if (parse_results())
136 tst_res(TFAIL, "RT task did not execute within required "
137 "latency of %d usec.\n", MAX_EXEC_LATENCY_US);
138 else
139 tst_res(TPASS, "RT task executed within required latency "
140 "of %d usec..\n", MAX_EXEC_LATENCY_US);
141 }
142
143 static struct tst_test test = {
144 .test_all = run,
145 .cleanup = trace_cleanup,
146 };
147