hotplug.c 3.7 KB

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