1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (c) 2022 Meta Platforms, Inc. and affiliates. 4 * Copyright (c) 2022 Tejun Heo <tj@kernel.org> 5 * Copyright (c) 2022 David Vernet <dvernet@meta.com> 6 */ 7 #define _GNU_SOURCE 8 #include <stdio.h> 9 #include <unistd.h> 10 #include <inttypes.h> 11 #include <signal.h> 12 #include <assert.h> 13 #include <libgen.h> 14 #include <bpf/bpf.h> 15 #include <scx/common.h> 16 #include "scx_central.bpf.skel.h" 17 18 const char help_fmt[] = 19 "A central FIFO sched_ext scheduler.\n" 20 "\n" 21 "See the top-level comment in .bpf.c for more details.\n" 22 "\n" 23 "Usage: %s [-s SLICE_US] [-c CPU] [-v]\n" 24 "\n" 25 " -s SLICE_US Override slice duration\n" 26 " -c CPU Override the central CPU (default: 0)\n" 27 " -v Print libbpf debug messages\n" 28 " -h Display this help and exit\n"; 29 30 static bool verbose; 31 static volatile int exit_req; 32 33 static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) 34 { 35 if (level == LIBBPF_DEBUG && !verbose) 36 return 0; 37 return vfprintf(stderr, format, args); 38 } 39 40 static void sigint_handler(int dummy) 41 { 42 exit_req = 1; 43 } 44 45 int main(int argc, char **argv) 46 { 47 struct scx_central *skel; 48 struct bpf_link *link; 49 __u64 seq = 0, ecode; 50 __s32 opt; 51 52 libbpf_set_print(libbpf_print_fn); 53 signal(SIGINT, sigint_handler); 54 signal(SIGTERM, sigint_handler); 55 restart: 56 optind = 1; 57 skel = SCX_OPS_OPEN(central_ops, scx_central); 58 59 skel->rodata->central_cpu = 0; 60 skel->rodata->nr_cpu_ids = libbpf_num_possible_cpus(); 61 skel->rodata->slice_ns = __COMPAT_ENUM_OR_ZERO("scx_public_consts", "SCX_SLICE_DFL"); 62 63 assert(skel->rodata->nr_cpu_ids > 0); 64 assert(skel->rodata->nr_cpu_ids <= INT32_MAX); 65 66 while ((opt = getopt(argc, argv, "s:c:vh")) != -1) { 67 switch (opt) { 68 case 's': 69 skel->rodata->slice_ns = strtoull(optarg, NULL, 0) * 1000; 70 break; 71 case 'c': { 72 u32 central_cpu = strtoul(optarg, NULL, 0); 73 if (central_cpu >= skel->rodata->nr_cpu_ids) { 74 fprintf(stderr, "invalid central CPU id value, %u given (%u max)\n", central_cpu, skel->rodata->nr_cpu_ids); 75 scx_central__destroy(skel); 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 link = SCX_OPS_ATTACH(skel, central_ops, scx_central); 97 98 if (!skel->data->timer_pinned) 99 printf("WARNING : BPF_F_TIMER_CPU_PIN not available, timer not pinned to central\n"); 100 101 while (!exit_req && !UEI_EXITED(skel, uei)) { 102 printf("[SEQ %llu]\n", seq++); 103 printf("total :%10" PRIu64 " local:%10" PRIu64 " queued:%10" PRIu64 " lost:%10" PRIu64 "\n", 104 skel->bss->nr_total, 105 skel->bss->nr_locals, 106 skel->bss->nr_queued, 107 skel->bss->nr_lost_pids); 108 printf("timer :%10" PRIu64 " dispatch:%10" PRIu64 " mismatch:%10" PRIu64 " retry:%10" PRIu64 "\n", 109 skel->bss->nr_timers, 110 skel->bss->nr_dispatches, 111 skel->bss->nr_mismatches, 112 skel->bss->nr_retries); 113 printf("overflow:%10" PRIu64 "\n", 114 skel->bss->nr_overflows); 115 fflush(stdout); 116 sleep(1); 117 } 118 119 bpf_link__destroy(link); 120 ecode = UEI_REPORT(skel, uei); 121 scx_central__destroy(skel); 122 123 if (UEI_ECODE_RESTART(ecode)) 124 goto restart; 125 return 0; 126 } 127