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