• 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  * A single small task executes. 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 small_task_tid;
25 
26 #define MIN_CORRECT_CLUSTER_PCT 90
27 #define BURN_SEC 5
task_fn(void * arg LTP_ATTRIBUTE_UNUSED)28 static void *task_fn(void *arg LTP_ATTRIBUTE_UNUSED)
29 {
30 	small_task_tid = gettid();
31 
32 	printf("Small task executing for %ds...\n", BURN_SEC);
33 	burn(BURN_SEC * USEC_PER_SEC, 1);
34 
35 	return NULL;
36 }
37 
parse_results(void)38 static int parse_results(void)
39 {
40 	int i, pct;
41 	unsigned long long exec_start_us = 0;
42 	unsigned long long correct_us = 0;
43 	unsigned long long total_us = 0;
44 	cpu_set_t cpuset;
45 
46 	if (find_cpus_with_capacity(0, &cpuset)) {
47 		printf("Failed to find the CPUs in the little cluster.\n");
48 		return -1;
49 	}
50 
51 	for (i = 0; i < num_trace_records; i++) {
52 		struct trace_sched_switch *t = trace[i].event_data;
53 		unsigned long long segment_us;
54 
55 		if (trace[i].event_type != TRACE_RECORD_SCHED_SWITCH)
56 			continue;
57 
58 		if (t->next_pid == small_task_tid) {
59 			if (exec_start_us) {
60 				printf("Trace parse fail: double exec start\n");
61 				return -1;
62 			}
63 			exec_start_us = TS_TO_USEC(trace[i].ts);
64 			continue;
65 		}
66 		if (t->prev_pid != small_task_tid)
67 			continue;
68 		/* End of task execution segment. */
69 		if (!exec_start_us) {
70 			printf("Trace parse fail: double exec end\n");
71 			return -1;
72 		}
73 		segment_us = TS_TO_USEC(trace[i].ts);
74 		segment_us -= exec_start_us;
75 		exec_start_us = 0;
76 		if (CPU_ISSET(trace[i].cpu, &cpuset))
77 			correct_us += segment_us;
78 		total_us += segment_us;
79 	}
80 
81 	pct = (correct_us * 100) / total_us;
82 	printf("Total time task scheduled: %lld usec\n"
83 	       "Time scheduled on a little CPU: %lld usec (%d%%)\n",
84 	       total_us, correct_us, pct);
85 
86 	return (pct < MIN_CORRECT_CLUSTER_PCT);
87 }
88 
run(void)89 static void run(void)
90 {
91 	pthread_t task_thread;
92 
93 	tst_res(TINFO, "Minimum correct cluster time percentage: %d%%\n",
94 		MIN_CORRECT_CLUSTER_PCT);
95 
96 	/* configure and enable tracing */
97 	tracefs_write("tracing_on", "0");
98 	tracefs_write("buffer_size_kb", "16384");
99 	tracefs_write("set_event", TRACE_EVENTS);
100 	tracefs_write("trace", "\n");
101 	tracefs_write("tracing_on", "1");
102 
103 	SAFE_PTHREAD_CREATE(&task_thread, NULL, task_fn, NULL);
104 	SAFE_PTHREAD_JOIN(task_thread, NULL);
105 
106 	/* disable tracing */
107 	tracefs_write("tracing_on", "0");
108 	LOAD_TRACE();
109 
110 	if (parse_results())
111 		tst_res(TFAIL, "Small task ran too much on non-small CPUs.\n");
112 	else
113 		tst_res(TPASS, "Small task ran appropriately on small CPUs.\n");
114 }
115 
116 static struct tst_test test = {
117 	.test_all = run,
118 	.setup = trace_setup,
119 	.cleanup = trace_cleanup,
120 };
121