hotplug.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (c) 2024 Meta Platforms, Inc. and affiliates.
  4. * Copyright (c) 2024 David Vernet <dvernet@meta.com>
  5. */
  6. #include <bpf/bpf.h>
  7. #include <sched.h>
  8. #include <scx/common.h>
  9. #include <sched.h>
  10. #include <sys/wait.h>
  11. #include <unistd.h>
  12. #include "hotplug_test.h"
  13. #include "hotplug.bpf.skel.h"
  14. #include "scx_test.h"
  15. #include "util.h"
  16. const char *online_path = "/sys/devices/system/cpu/cpu1/online";
  17. static bool is_cpu_online(void)
  18. {
  19. return file_read_long(online_path) > 0;
  20. }
  21. static void toggle_online_status(bool online)
  22. {
  23. long val = online ? 1 : 0;
  24. int ret;
  25. ret = file_write_long(online_path, val);
  26. if (ret != 0)
  27. fprintf(stderr, "Failed to bring CPU %s (%s)",
  28. online ? "online" : "offline", strerror(errno));
  29. }
  30. static enum scx_test_status setup(void **ctx)
  31. {
  32. if (!is_cpu_online())
  33. return SCX_TEST_SKIP;
  34. return SCX_TEST_PASS;
  35. }
  36. static enum scx_test_status test_hotplug(bool onlining, bool cbs_defined)
  37. {
  38. struct hotplug *skel;
  39. struct bpf_link *link;
  40. long kind, code;
  41. SCX_ASSERT(is_cpu_online());
  42. skel = hotplug__open_and_load();
  43. SCX_ASSERT(skel);
  44. /* Testing the offline -> online path, so go offline before starting */
  45. if (onlining)
  46. toggle_online_status(0);
  47. if (cbs_defined) {
  48. kind = SCX_KIND_VAL(SCX_EXIT_UNREG_BPF);
  49. code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) | HOTPLUG_EXIT_RSN;
  50. if (onlining)
  51. code |= HOTPLUG_ONLINING;
  52. } else {
  53. kind = SCX_KIND_VAL(SCX_EXIT_UNREG_KERN);
  54. code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) |
  55. SCX_ECODE_VAL(SCX_ECODE_RSN_HOTPLUG);
  56. }
  57. if (cbs_defined)
  58. link = bpf_map__attach_struct_ops(skel->maps.hotplug_cb_ops);
  59. else
  60. link = bpf_map__attach_struct_ops(skel->maps.hotplug_nocb_ops);
  61. if (!link) {
  62. SCX_ERR("Failed to attach scheduler");
  63. hotplug__destroy(skel);
  64. return SCX_TEST_FAIL;
  65. }
  66. toggle_online_status(onlining ? 1 : 0);
  67. while (!UEI_EXITED(skel, uei))
  68. sched_yield();
  69. SCX_EQ(skel->data->uei.kind, kind);
  70. SCX_EQ(UEI_REPORT(skel, uei), code);
  71. if (!onlining)
  72. toggle_online_status(1);
  73. bpf_link__destroy(link);
  74. hotplug__destroy(skel);
  75. return SCX_TEST_PASS;
  76. }
  77. static enum scx_test_status test_hotplug_attach(void)
  78. {
  79. struct hotplug *skel;
  80. struct bpf_link *link;
  81. enum scx_test_status status = SCX_TEST_PASS;
  82. long kind, code;
  83. SCX_ASSERT(is_cpu_online());
  84. SCX_ASSERT(scx_hotplug_seq() > 0);
  85. skel = SCX_OPS_OPEN(hotplug_nocb_ops, hotplug);
  86. SCX_ASSERT(skel);
  87. SCX_OPS_LOAD(skel, hotplug_nocb_ops, hotplug, uei);
  88. /*
  89. * Take the CPU offline to increment the global hotplug seq, which
  90. * should cause attach to fail due to us setting the hotplug seq above
  91. */
  92. toggle_online_status(0);
  93. link = bpf_map__attach_struct_ops(skel->maps.hotplug_nocb_ops);
  94. toggle_online_status(1);
  95. SCX_ASSERT(link);
  96. while (!UEI_EXITED(skel, uei))
  97. sched_yield();
  98. kind = SCX_KIND_VAL(SCX_EXIT_UNREG_KERN);
  99. code = SCX_ECODE_VAL(SCX_ECODE_ACT_RESTART) |
  100. SCX_ECODE_VAL(SCX_ECODE_RSN_HOTPLUG);
  101. SCX_EQ(skel->data->uei.kind, kind);
  102. SCX_EQ(UEI_REPORT(skel, uei), code);
  103. bpf_link__destroy(link);
  104. hotplug__destroy(skel);
  105. return status;
  106. }
  107. static enum scx_test_status run(void *ctx)
  108. {
  109. #define HP_TEST(__onlining, __cbs_defined) ({ \
  110. if (test_hotplug(__onlining, __cbs_defined) != SCX_TEST_PASS) \
  111. return SCX_TEST_FAIL; \
  112. })
  113. HP_TEST(true, true);
  114. HP_TEST(false, true);
  115. HP_TEST(true, false);
  116. HP_TEST(false, false);
  117. #undef HP_TEST
  118. return test_hotplug_attach();
  119. }
  120. static void cleanup(void *ctx)
  121. {
  122. toggle_online_status(1);
  123. }
  124. struct scx_test hotplug_test = {
  125. .name = "hotplug",
  126. .description = "Verify hotplug behavior",
  127. .setup = setup,
  128. .run = run,
  129. .cleanup = cleanup,
  130. };
  131. REGISTER_SCX_TEST(&hotplug_test)