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