scx_central.c 3.8 KB

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