Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/sched_ext/scx_central.c
29266 views
1
/* SPDX-License-Identifier: GPL-2.0 */
2
/*
3
* Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4
* Copyright (c) 2022 Tejun Heo <[email protected]>
5
* Copyright (c) 2022 David Vernet <[email protected]>
6
*/
7
#define _GNU_SOURCE
8
#include <sched.h>
9
#include <stdio.h>
10
#include <unistd.h>
11
#include <inttypes.h>
12
#include <signal.h>
13
#include <assert.h>
14
#include <libgen.h>
15
#include <bpf/bpf.h>
16
#include <scx/common.h>
17
#include "scx_central.bpf.skel.h"
18
19
const char help_fmt[] =
20
"A central FIFO sched_ext scheduler.\n"
21
"\n"
22
"See the top-level comment in .bpf.c for more details.\n"
23
"\n"
24
"Usage: %s [-s SLICE_US] [-c CPU]\n"
25
"\n"
26
" -s SLICE_US Override slice duration\n"
27
" -c CPU Override the central CPU (default: 0)\n"
28
" -v Print libbpf debug messages\n"
29
" -h Display this help and exit\n";
30
31
static bool verbose;
32
static volatile int exit_req;
33
34
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
35
{
36
if (level == LIBBPF_DEBUG && !verbose)
37
return 0;
38
return vfprintf(stderr, format, args);
39
}
40
41
static void sigint_handler(int dummy)
42
{
43
exit_req = 1;
44
}
45
46
int main(int argc, char **argv)
47
{
48
struct scx_central *skel;
49
struct bpf_link *link;
50
__u64 seq = 0, ecode;
51
__s32 opt;
52
cpu_set_t *cpuset;
53
54
libbpf_set_print(libbpf_print_fn);
55
signal(SIGINT, sigint_handler);
56
signal(SIGTERM, sigint_handler);
57
restart:
58
skel = SCX_OPS_OPEN(central_ops, scx_central);
59
60
skel->rodata->central_cpu = 0;
61
skel->rodata->nr_cpu_ids = libbpf_num_possible_cpus();
62
skel->rodata->slice_ns = __COMPAT_ENUM_OR_ZERO("scx_public_consts", "SCX_SLICE_DFL");
63
64
assert(skel->rodata->nr_cpu_ids > 0);
65
assert(skel->rodata->nr_cpu_ids <= INT32_MAX);
66
67
while ((opt = getopt(argc, argv, "s:c:pvh")) != -1) {
68
switch (opt) {
69
case 's':
70
skel->rodata->slice_ns = strtoull(optarg, NULL, 0) * 1000;
71
break;
72
case 'c': {
73
u32 central_cpu = strtoul(optarg, NULL, 0);
74
if (central_cpu >= skel->rodata->nr_cpu_ids) {
75
fprintf(stderr, "invalid central CPU id value, %u given (%u max)\n", central_cpu, skel->rodata->nr_cpu_ids);
76
return -1;
77
}
78
skel->rodata->central_cpu = (s32)central_cpu;
79
break;
80
}
81
case 'v':
82
verbose = true;
83
break;
84
default:
85
fprintf(stderr, help_fmt, basename(argv[0]));
86
return opt != 'h';
87
}
88
}
89
90
/* Resize arrays so their element count is equal to cpu count. */
91
RESIZE_ARRAY(skel, data, cpu_gimme_task, skel->rodata->nr_cpu_ids);
92
RESIZE_ARRAY(skel, data, cpu_started_at, skel->rodata->nr_cpu_ids);
93
94
SCX_OPS_LOAD(skel, central_ops, scx_central, uei);
95
96
/*
97
* Affinitize the loading thread to the central CPU, as:
98
* - That's where the BPF timer is first invoked in the BPF program.
99
* - We probably don't want this user space component to take up a core
100
* from a task that would benefit from avoiding preemption on one of
101
* the tickless cores.
102
*
103
* Until BPF supports pinning the timer, it's not guaranteed that it
104
* will always be invoked on the central CPU. In practice, this
105
* suffices the majority of the time.
106
*/
107
cpuset = CPU_ALLOC(skel->rodata->nr_cpu_ids);
108
SCX_BUG_ON(!cpuset, "Failed to allocate cpuset");
109
CPU_ZERO_S(CPU_ALLOC_SIZE(skel->rodata->nr_cpu_ids), cpuset);
110
CPU_SET(skel->rodata->central_cpu, cpuset);
111
SCX_BUG_ON(sched_setaffinity(0, sizeof(*cpuset), cpuset),
112
"Failed to affinitize to central CPU %d (max %d)",
113
skel->rodata->central_cpu, skel->rodata->nr_cpu_ids - 1);
114
CPU_FREE(cpuset);
115
116
link = SCX_OPS_ATTACH(skel, central_ops, scx_central);
117
118
if (!skel->data->timer_pinned)
119
printf("WARNING : BPF_F_TIMER_CPU_PIN not available, timer not pinned to central\n");
120
121
while (!exit_req && !UEI_EXITED(skel, uei)) {
122
printf("[SEQ %llu]\n", seq++);
123
printf("total :%10" PRIu64 " local:%10" PRIu64 " queued:%10" PRIu64 " lost:%10" PRIu64 "\n",
124
skel->bss->nr_total,
125
skel->bss->nr_locals,
126
skel->bss->nr_queued,
127
skel->bss->nr_lost_pids);
128
printf("timer :%10" PRIu64 " dispatch:%10" PRIu64 " mismatch:%10" PRIu64 " retry:%10" PRIu64 "\n",
129
skel->bss->nr_timers,
130
skel->bss->nr_dispatches,
131
skel->bss->nr_mismatches,
132
skel->bss->nr_retries);
133
printf("overflow:%10" PRIu64 "\n",
134
skel->bss->nr_overflows);
135
fflush(stdout);
136
sleep(1);
137
}
138
139
bpf_link__destroy(link);
140
ecode = UEI_REPORT(skel, uei);
141
scx_central__destroy(skel);
142
143
if (UEI_ECODE_RESTART(ecode))
144
goto restart;
145
return 0;
146
}
147
148