xref: /linux/tools/sched_ext/scx_pair.c (revision 4cf44657887b4c41374981d0afb2ca302b189e15)
1f0262b10SEmil Tsalapatis /* SPDX-License-Identifier: GPL-2.0 */
2f0262b10SEmil Tsalapatis /*
3f0262b10SEmil Tsalapatis  * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4f0262b10SEmil Tsalapatis  * Copyright (c) 2022 Tejun Heo <tj@kernel.org>
5f0262b10SEmil Tsalapatis  * Copyright (c) 2022 David Vernet <dvernet@meta.com>
6f0262b10SEmil Tsalapatis  */
7f0262b10SEmil Tsalapatis #include <stdio.h>
8f0262b10SEmil Tsalapatis #include <unistd.h>
9f0262b10SEmil Tsalapatis #include <inttypes.h>
10f0262b10SEmil Tsalapatis #include <signal.h>
11f0262b10SEmil Tsalapatis #include <assert.h>
12f0262b10SEmil Tsalapatis #include <libgen.h>
13f0262b10SEmil Tsalapatis #include <bpf/bpf.h>
14f0262b10SEmil Tsalapatis #include <scx/common.h>
15f0262b10SEmil Tsalapatis #include "scx_pair.h"
16f0262b10SEmil Tsalapatis #include "scx_pair.bpf.skel.h"
17f0262b10SEmil Tsalapatis 
18f0262b10SEmil Tsalapatis const char help_fmt[] =
19f0262b10SEmil Tsalapatis "A demo sched_ext core-scheduler which always makes every sibling CPU pair\n"
20f0262b10SEmil Tsalapatis "execute from the same CPU cgroup.\n"
21f0262b10SEmil Tsalapatis "\n"
22f0262b10SEmil Tsalapatis "See the top-level comment in .bpf.c for more details.\n"
23f0262b10SEmil Tsalapatis "\n"
24f0262b10SEmil Tsalapatis "Usage: %s [-S STRIDE]\n"
25f0262b10SEmil Tsalapatis "\n"
26f0262b10SEmil Tsalapatis "  -S STRIDE     Override CPU pair stride (default: nr_cpus_ids / 2)\n"
27f0262b10SEmil Tsalapatis "  -v            Print libbpf debug messages\n"
28f0262b10SEmil Tsalapatis "  -h            Display this help and exit\n";
29f0262b10SEmil Tsalapatis 
30f0262b10SEmil Tsalapatis static bool verbose;
31f0262b10SEmil Tsalapatis static volatile int exit_req;
32f0262b10SEmil Tsalapatis 
libbpf_print_fn(enum libbpf_print_level level,const char * format,va_list args)33f0262b10SEmil Tsalapatis static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
34f0262b10SEmil Tsalapatis {
35f0262b10SEmil Tsalapatis 	if (level == LIBBPF_DEBUG && !verbose)
36f0262b10SEmil Tsalapatis 		return 0;
37f0262b10SEmil Tsalapatis 	return vfprintf(stderr, format, args);
38f0262b10SEmil Tsalapatis }
39f0262b10SEmil Tsalapatis 
sigint_handler(int dummy)40f0262b10SEmil Tsalapatis static void sigint_handler(int dummy)
41f0262b10SEmil Tsalapatis {
42f0262b10SEmil Tsalapatis 	exit_req = 1;
43f0262b10SEmil Tsalapatis }
44f0262b10SEmil Tsalapatis 
main(int argc,char ** argv)45f0262b10SEmil Tsalapatis int main(int argc, char **argv)
46f0262b10SEmil Tsalapatis {
47f0262b10SEmil Tsalapatis 	struct scx_pair *skel;
48f0262b10SEmil Tsalapatis 	struct bpf_link *link;
49f0262b10SEmil Tsalapatis 	__u64 seq = 0, ecode;
50f0262b10SEmil Tsalapatis 	__s32 stride, i, opt, outer_fd;
51f0262b10SEmil Tsalapatis 
52f0262b10SEmil Tsalapatis 	libbpf_set_print(libbpf_print_fn);
53f0262b10SEmil Tsalapatis 	signal(SIGINT, sigint_handler);
54f0262b10SEmil Tsalapatis 	signal(SIGTERM, sigint_handler);
55f0262b10SEmil Tsalapatis restart:
56*640c9dc7SDavid Carlier 	optind = 1;
57f0262b10SEmil Tsalapatis 	skel = SCX_OPS_OPEN(pair_ops, scx_pair);
58f0262b10SEmil Tsalapatis 
59f0262b10SEmil Tsalapatis 	skel->rodata->nr_cpu_ids = libbpf_num_possible_cpus();
60f0262b10SEmil Tsalapatis 	skel->rodata->pair_batch_dur_ns = __COMPAT_ENUM_OR_ZERO("scx_public_consts", "SCX_SLICE_DFL");
61f0262b10SEmil Tsalapatis 
62f0262b10SEmil Tsalapatis 	/* pair up the earlier half to the latter by default, override with -s */
63f0262b10SEmil Tsalapatis 	stride = skel->rodata->nr_cpu_ids / 2;
64f0262b10SEmil Tsalapatis 
65f0262b10SEmil Tsalapatis 	while ((opt = getopt(argc, argv, "S:vh")) != -1) {
66f0262b10SEmil Tsalapatis 		switch (opt) {
67f0262b10SEmil Tsalapatis 		case 'S':
68f0262b10SEmil Tsalapatis 			stride = strtoul(optarg, NULL, 0);
69f0262b10SEmil Tsalapatis 			break;
70f0262b10SEmil Tsalapatis 		case 'v':
71f0262b10SEmil Tsalapatis 			verbose = true;
72f0262b10SEmil Tsalapatis 			break;
73f0262b10SEmil Tsalapatis 		default:
74f0262b10SEmil Tsalapatis 			fprintf(stderr, help_fmt, basename(argv[0]));
75f0262b10SEmil Tsalapatis 			return opt != 'h';
76f0262b10SEmil Tsalapatis 		}
77f0262b10SEmil Tsalapatis 	}
78f0262b10SEmil Tsalapatis 
79625be345SDavid Carlier 	/* Stride must be positive to pair distinct CPUs. */
80625be345SDavid Carlier 	if (stride <= 0) {
81625be345SDavid Carlier 		fprintf(stderr, "Invalid stride %d, must be positive\n", stride);
82625be345SDavid Carlier 		scx_pair__destroy(skel);
83625be345SDavid Carlier 		return -1;
84625be345SDavid Carlier 	}
85f0262b10SEmil Tsalapatis 	bpf_map__set_max_entries(skel->maps.pair_ctx, skel->rodata->nr_cpu_ids / 2);
86f0262b10SEmil Tsalapatis 
87f0262b10SEmil Tsalapatis 	/* Resize arrays so their element count is equal to cpu count. */
88f0262b10SEmil Tsalapatis 	RESIZE_ARRAY(skel, rodata, pair_cpu, skel->rodata->nr_cpu_ids);
89f0262b10SEmil Tsalapatis 	RESIZE_ARRAY(skel, rodata, pair_id, skel->rodata->nr_cpu_ids);
90f0262b10SEmil Tsalapatis 	RESIZE_ARRAY(skel, rodata, in_pair_idx, skel->rodata->nr_cpu_ids);
91f0262b10SEmil Tsalapatis 
92f0262b10SEmil Tsalapatis 	for (i = 0; i < skel->rodata->nr_cpu_ids; i++)
93f0262b10SEmil Tsalapatis 		skel->rodata_pair_cpu->pair_cpu[i] = -1;
94f0262b10SEmil Tsalapatis 
95f0262b10SEmil Tsalapatis 	printf("Pairs: ");
96f0262b10SEmil Tsalapatis 	for (i = 0; i < skel->rodata->nr_cpu_ids; i++) {
97f0262b10SEmil Tsalapatis 		int j = (i + stride) % skel->rodata->nr_cpu_ids;
98f0262b10SEmil Tsalapatis 
99f0262b10SEmil Tsalapatis 		if (skel->rodata_pair_cpu->pair_cpu[i] >= 0)
100f0262b10SEmil Tsalapatis 			continue;
101f0262b10SEmil Tsalapatis 
102f0262b10SEmil Tsalapatis 		SCX_BUG_ON(i == j,
103f0262b10SEmil Tsalapatis 			   "Invalid stride %d - CPU%d wants to be its own pair",
104f0262b10SEmil Tsalapatis 			   stride, i);
105f0262b10SEmil Tsalapatis 
106f0262b10SEmil Tsalapatis 		SCX_BUG_ON(skel->rodata_pair_cpu->pair_cpu[j] >= 0,
107f0262b10SEmil Tsalapatis 			   "Invalid stride %d - three CPUs (%d, %d, %d) want to be a pair",
108f0262b10SEmil Tsalapatis 			   stride, i, j, skel->rodata_pair_cpu->pair_cpu[j]);
109f0262b10SEmil Tsalapatis 
110f0262b10SEmil Tsalapatis 		skel->rodata_pair_cpu->pair_cpu[i] = j;
111f0262b10SEmil Tsalapatis 		skel->rodata_pair_cpu->pair_cpu[j] = i;
112f0262b10SEmil Tsalapatis 		skel->rodata_pair_id->pair_id[i] = i;
113f0262b10SEmil Tsalapatis 		skel->rodata_pair_id->pair_id[j] = i;
114f0262b10SEmil Tsalapatis 		skel->rodata_in_pair_idx->in_pair_idx[i] = 0;
115f0262b10SEmil Tsalapatis 		skel->rodata_in_pair_idx->in_pair_idx[j] = 1;
116f0262b10SEmil Tsalapatis 
117f0262b10SEmil Tsalapatis 		printf("[%d, %d] ", i, j);
118f0262b10SEmil Tsalapatis 	}
119f0262b10SEmil Tsalapatis 	printf("\n");
120f0262b10SEmil Tsalapatis 
121f0262b10SEmil Tsalapatis 	SCX_OPS_LOAD(skel, pair_ops, scx_pair, uei);
122f0262b10SEmil Tsalapatis 
123f0262b10SEmil Tsalapatis 	/*
124f0262b10SEmil Tsalapatis 	 * Populate the cgrp_q_arr map which is an array containing per-cgroup
125f0262b10SEmil Tsalapatis 	 * queues. It'd probably be better to do this from BPF but there are too
126f0262b10SEmil Tsalapatis 	 * many to initialize statically and there's no way to dynamically
127f0262b10SEmil Tsalapatis 	 * populate from BPF.
128f0262b10SEmil Tsalapatis 	 */
129f0262b10SEmil Tsalapatis 	outer_fd = bpf_map__fd(skel->maps.cgrp_q_arr);
130f0262b10SEmil Tsalapatis 	SCX_BUG_ON(outer_fd < 0, "Failed to get outer_fd: %d", outer_fd);
131f0262b10SEmil Tsalapatis 
132f0262b10SEmil Tsalapatis 	printf("Initializing");
133f0262b10SEmil Tsalapatis         for (i = 0; i < MAX_CGRPS; i++) {
134f0262b10SEmil Tsalapatis 		__s32 inner_fd;
135f0262b10SEmil Tsalapatis 
136f0262b10SEmil Tsalapatis 		if (exit_req)
137f0262b10SEmil Tsalapatis 			break;
138f0262b10SEmil Tsalapatis 
139f0262b10SEmil Tsalapatis 		inner_fd = bpf_map_create(BPF_MAP_TYPE_QUEUE, NULL, 0,
140f0262b10SEmil Tsalapatis 					  sizeof(__u32), MAX_QUEUED, NULL);
141f0262b10SEmil Tsalapatis 		SCX_BUG_ON(inner_fd < 0, "Failed to get inner_fd: %d",
142f0262b10SEmil Tsalapatis 			   inner_fd);
143f0262b10SEmil Tsalapatis 		SCX_BUG_ON(bpf_map_update_elem(outer_fd, &i, &inner_fd, BPF_ANY),
144f0262b10SEmil Tsalapatis 			   "Failed to set inner map");
145f0262b10SEmil Tsalapatis 		close(inner_fd);
146f0262b10SEmil Tsalapatis 
147f0262b10SEmil Tsalapatis 		if (!(i % 10))
148f0262b10SEmil Tsalapatis 			printf(".");
149f0262b10SEmil Tsalapatis 		fflush(stdout);
150f0262b10SEmil Tsalapatis         }
151f0262b10SEmil Tsalapatis 	printf("\n");
152f0262b10SEmil Tsalapatis 
153f0262b10SEmil Tsalapatis 	/*
154f0262b10SEmil Tsalapatis 	 * Fully initialized, attach and run.
155f0262b10SEmil Tsalapatis 	 */
156f0262b10SEmil Tsalapatis 	link = SCX_OPS_ATTACH(skel, pair_ops, scx_pair);
157f0262b10SEmil Tsalapatis 
158f0262b10SEmil Tsalapatis 	while (!exit_req && !UEI_EXITED(skel, uei)) {
159f0262b10SEmil Tsalapatis 		printf("[SEQ %llu]\n", seq++);
160f0262b10SEmil Tsalapatis 		printf(" total:%10" PRIu64 " dispatch:%10" PRIu64 "   missing:%10" PRIu64 "\n",
161f0262b10SEmil Tsalapatis 		       skel->bss->nr_total,
162f0262b10SEmil Tsalapatis 		       skel->bss->nr_dispatched,
163f0262b10SEmil Tsalapatis 		       skel->bss->nr_missing);
164f0262b10SEmil Tsalapatis 		printf(" kicks:%10" PRIu64 " preemptions:%7" PRIu64 "\n",
165f0262b10SEmil Tsalapatis 		       skel->bss->nr_kicks,
166f0262b10SEmil Tsalapatis 		       skel->bss->nr_preemptions);
167f0262b10SEmil Tsalapatis 		printf("   exp:%10" PRIu64 " exp_wait:%10" PRIu64 " exp_empty:%10" PRIu64 "\n",
168f0262b10SEmil Tsalapatis 		       skel->bss->nr_exps,
169f0262b10SEmil Tsalapatis 		       skel->bss->nr_exp_waits,
170f0262b10SEmil Tsalapatis 		       skel->bss->nr_exp_empty);
171f0262b10SEmil Tsalapatis 		printf("cgnext:%10" PRIu64 "   cgcoll:%10" PRIu64 "   cgempty:%10" PRIu64 "\n",
172f0262b10SEmil Tsalapatis 		       skel->bss->nr_cgrp_next,
173f0262b10SEmil Tsalapatis 		       skel->bss->nr_cgrp_coll,
174f0262b10SEmil Tsalapatis 		       skel->bss->nr_cgrp_empty);
175f0262b10SEmil Tsalapatis 		fflush(stdout);
176f0262b10SEmil Tsalapatis 		sleep(1);
177f0262b10SEmil Tsalapatis 	}
178f0262b10SEmil Tsalapatis 
179f0262b10SEmil Tsalapatis 	bpf_link__destroy(link);
180f0262b10SEmil Tsalapatis 	ecode = UEI_REPORT(skel, uei);
181f0262b10SEmil Tsalapatis 	scx_pair__destroy(skel);
182f0262b10SEmil Tsalapatis 
183f0262b10SEmil Tsalapatis 	if (UEI_ECODE_RESTART(ecode))
184f0262b10SEmil Tsalapatis 		goto restart;
185f0262b10SEmil Tsalapatis 	return 0;
186f0262b10SEmil Tsalapatis }
187