1 /*
2 * Copyright (c) 2018 Google, Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 *
6 * A single big task executes. Task placement and upmigration latency is
7 * verified.
8 */
9
10 #define _GNU_SOURCE
11 #include <errno.h>
12 #include <pthread.h>
13 #include <sched.h>
14 #include <time.h>
15
16 #include "tst_test.h"
17 #include "tst_safe_file_ops.h"
18 #include "tst_safe_pthread.h"
19
20 #include "trace_parse.h"
21 #include "util.h"
22
23 #define TRACE_EVENTS "sched_switch"
24
25 static int big_task_tid;
26
27 #define MAX_UPMIGRATE_LATENCY_US 100000
28 #define MIN_CORRECT_CLUSTER_PCT 90
29 #define BURN_SEC 3
task_fn(void * arg LTP_ATTRIBUTE_UNUSED)30 static void *task_fn(void *arg LTP_ATTRIBUTE_UNUSED)
31 {
32 big_task_tid = gettid();
33
34 printf("Big task executing for %ds...\n", BURN_SEC);
35 burn(BURN_SEC * USEC_PER_SEC, 0);
36
37 return NULL;
38 }
39
parse_results(void)40 static int parse_results(void)
41 {
42 int i, pct;
43 unsigned long long exec_start_us = 0;
44 unsigned long long correct_us = 0;
45 unsigned long long total_us = 0;
46 unsigned long long start_ts_usec = 0;
47 unsigned long long upmigration_ts_usec = 0;
48 unsigned long long upmigration_latency_usec = 0;
49 cpu_set_t cpuset;
50
51 if (find_cpus_with_capacity(1, &cpuset)) {
52 printf("Failed to find the CPUs in the big cluster.\n");
53 return -1;
54 }
55
56 for (i = 0; i < num_trace_records; i++) {
57 unsigned long long segment_us;
58 struct trace_sched_switch *t = trace[i].event_data;
59
60 if (trace[i].event_type != TRACE_RECORD_SCHED_SWITCH)
61 continue;
62 if (t->next_pid == big_task_tid) {
63 /* Start of task execution segment. */
64 if (exec_start_us) {
65 printf("Trace parse fail: double exec start\n");
66 return -1;
67 }
68 exec_start_us = TS_TO_USEC(trace[i].ts);
69 if (!start_ts_usec)
70 start_ts_usec = exec_start_us;
71 if (!upmigration_ts_usec &&
72 CPU_ISSET(trace[i].cpu, &cpuset))
73 upmigration_ts_usec = exec_start_us;
74 continue;
75 }
76 if (t->prev_pid != big_task_tid)
77 continue;
78 /* End of task execution segment. */
79 segment_us = TS_TO_USEC(trace[i].ts);
80 segment_us -= exec_start_us;
81 exec_start_us = 0;
82 if (CPU_ISSET(trace[i].cpu, &cpuset))
83 correct_us += segment_us;
84 total_us += segment_us;
85 }
86
87 pct = (correct_us * 100) / total_us;
88 printf("Total time task scheduled: %lld usec\n"
89 "Time scheduled on a big CPU: %lld usec (%d%%)\n",
90 total_us, correct_us, pct);
91
92 if (!upmigration_ts_usec) {
93 printf("Task never upmigrated!\n");
94 return -1;
95 }
96
97 upmigration_latency_usec = upmigration_ts_usec - start_ts_usec;
98 printf("Upmigration latency: %lld usec\n", upmigration_latency_usec);
99
100 return (pct < MIN_CORRECT_CLUSTER_PCT ||
101 upmigration_latency_usec > MAX_UPMIGRATE_LATENCY_US);
102 }
103
run(void)104 static void run(void)
105 {
106 pthread_t task_thread;
107
108 tst_res(TINFO, "Minimum correct cluster time percentage: %d%%",
109 MIN_CORRECT_CLUSTER_PCT);
110 tst_res(TINFO, "Maximum upmigration latency: %d usec",
111 MAX_UPMIGRATE_LATENCY_US);
112
113 /* configure and enable tracing */
114 SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "0");
115 SAFE_FILE_PRINTF(TRACING_DIR "buffer_size_kb", "16384");
116 SAFE_FILE_PRINTF(TRACING_DIR "set_event", TRACE_EVENTS);
117 SAFE_FILE_PRINTF(TRACING_DIR "trace", "\n");
118 SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "1");
119
120 SAFE_PTHREAD_CREATE(&task_thread, NULL, task_fn, NULL);
121 SAFE_PTHREAD_JOIN(task_thread, NULL);
122
123 /* disable tracing */
124 SAFE_FILE_PRINTF(TRACING_DIR "tracing_on", "0");
125 LOAD_TRACE();
126
127 if (parse_results())
128 tst_res(TFAIL, "Task placement/migration latency did not meet "
129 "requirements.");
130 else
131 tst_res(TPASS, "Task placement/migration latency met "
132 "requirements.");
133 }
134
135 static struct tst_test test = {
136 .test_all = run,
137 .cleanup = trace_cleanup,
138 };
139