| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Test for DSQ operations including create, destroy, and peek operations.
- *
- * Copyright (c) 2025 Meta Platforms, Inc. and affiliates.
- * Copyright (c) 2025 Ryan Newton <ryan.newton@alum.mit.edu>
- */
- #include <bpf/bpf.h>
- #include <scx/common.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include <pthread.h>
- #include <string.h>
- #include <sched.h>
- #include "peek_dsq.bpf.skel.h"
- #include "scx_test.h"
- #define NUM_WORKERS 4
- static bool workload_running = true;
- static pthread_t workload_threads[NUM_WORKERS];
- /**
- * Background workload thread that sleeps and wakes rapidly to exercise
- * the scheduler's enqueue operations and ensure DSQ operations get tested.
- */
- static void *workload_thread_fn(void *arg)
- {
- while (workload_running) {
- /* Sleep for a very short time to trigger scheduler activity */
- usleep(1000); /* 1ms sleep */
- /* Yield to ensure we go through the scheduler */
- sched_yield();
- }
- return NULL;
- }
- static enum scx_test_status setup(void **ctx)
- {
- struct peek_dsq *skel;
- skel = peek_dsq__open();
- SCX_FAIL_IF(!skel, "Failed to open");
- SCX_ENUM_INIT(skel);
- SCX_FAIL_IF(peek_dsq__load(skel), "Failed to load skel");
- *ctx = skel;
- return SCX_TEST_PASS;
- }
- static int print_observed_pids(struct bpf_map *map, int max_samples, const char *dsq_name)
- {
- long count = 0;
- printf("Observed %s DSQ peek pids:\n", dsq_name);
- for (int i = 0; i < max_samples; i++) {
- long pid;
- int err;
- err = bpf_map_lookup_elem(bpf_map__fd(map), &i, &pid);
- if (err == 0) {
- if (pid == 0) {
- printf(" Sample %d: NULL peek\n", i);
- } else if (pid > 0) {
- printf(" Sample %d: pid %ld\n", i, pid);
- count++;
- }
- } else {
- printf(" Sample %d: error reading pid (err=%d)\n", i, err);
- }
- }
- printf("Observed ~%ld pids in the %s DSQ(s)\n", count, dsq_name);
- return count;
- }
- static enum scx_test_status run(void *ctx)
- {
- struct peek_dsq *skel = ctx;
- bool failed = false;
- int seconds = 3;
- int err;
- /* Enable the scheduler to test DSQ operations */
- printf("Enabling scheduler to test DSQ insert operations...\n");
- struct bpf_link *link =
- bpf_map__attach_struct_ops(skel->maps.peek_dsq_ops);
- if (!link) {
- SCX_ERR("Failed to attach struct_ops");
- return SCX_TEST_FAIL;
- }
- printf("Starting %d background workload threads...\n", NUM_WORKERS);
- workload_running = true;
- for (int i = 0; i < NUM_WORKERS; i++) {
- err = pthread_create(&workload_threads[i], NULL, workload_thread_fn, NULL);
- if (err) {
- SCX_ERR("Failed to create workload thread %d: %s", i, strerror(err));
- /* Stop already created threads */
- workload_running = false;
- for (int j = 0; j < i; j++)
- pthread_join(workload_threads[j], NULL);
- bpf_link__destroy(link);
- return SCX_TEST_FAIL;
- }
- }
- printf("Waiting for enqueue events.\n");
- sleep(seconds);
- while (skel->data->enqueue_count <= 0) {
- printf(".");
- fflush(stdout);
- sleep(1);
- seconds++;
- if (seconds >= 30) {
- printf("\n\u2717 Timeout waiting for enqueue events\n");
- /* Stop workload threads and cleanup */
- workload_running = false;
- for (int i = 0; i < NUM_WORKERS; i++)
- pthread_join(workload_threads[i], NULL);
- bpf_link__destroy(link);
- return SCX_TEST_FAIL;
- }
- }
- workload_running = false;
- for (int i = 0; i < NUM_WORKERS; i++) {
- err = pthread_join(workload_threads[i], NULL);
- if (err) {
- SCX_ERR("Failed to join workload thread %d: %s", i, strerror(err));
- bpf_link__destroy(link);
- return SCX_TEST_FAIL;
- }
- }
- printf("Background workload threads stopped.\n");
- SCX_EQ(skel->data->uei.kind, EXIT_KIND(SCX_EXIT_NONE));
- /* Detach the scheduler */
- bpf_link__destroy(link);
- printf("Enqueue/dispatch count over %d seconds: %d / %d\n", seconds,
- skel->data->enqueue_count, skel->data->dispatch_count);
- printf("Debug: ksym_exists=%d\n",
- skel->bss->debug_ksym_exists);
- /* Check DSQ insert result */
- printf("DSQ insert test done on cpu: %d\n", skel->data->insert_test_cpu);
- if (skel->data->insert_test_cpu != -1)
- printf("\u2713 DSQ insert succeeded !\n");
- else {
- printf("\u2717 DSQ insert failed or not attempted\n");
- failed = true;
- }
- /* Check DSQ peek results */
- printf(" DSQ peek result 1 (before insert): %d\n",
- skel->data->dsq_peek_result1);
- if (skel->data->dsq_peek_result1 == 0)
- printf("\u2713 DSQ peek verification success: peek returned NULL!\n");
- else {
- printf("\u2717 DSQ peek verification failed\n");
- failed = true;
- }
- printf(" DSQ peek result 2 (after insert): %ld\n",
- skel->data->dsq_peek_result2);
- printf(" DSQ peek result 2, expected: %ld\n",
- skel->data->dsq_peek_result2_expected);
- if (skel->data->dsq_peek_result2 ==
- skel->data->dsq_peek_result2_expected)
- printf("\u2713 DSQ peek verification success: peek returned the inserted task!\n");
- else {
- printf("\u2717 DSQ peek verification failed\n");
- failed = true;
- }
- printf(" Inserted test task -> pid: %ld\n", skel->data->dsq_inserted_pid);
- printf(" DSQ peek result 2 -> pid: %ld\n", skel->data->dsq_peek_result2_pid);
- int pid_count;
- pid_count = print_observed_pids(skel->maps.peek_results,
- skel->data->max_samples, "DSQ pool");
- printf("Total non-null peek observations: %ld out of %ld\n",
- skel->data->successful_peeks, skel->data->total_peek_attempts);
- if (skel->bss->debug_ksym_exists && pid_count == 0) {
- printf("\u2717 DSQ pool test failed: no successful peeks in native mode\n");
- failed = true;
- }
- if (skel->bss->debug_ksym_exists && pid_count > 0)
- printf("\u2713 DSQ pool test success: observed successful peeks in native mode\n");
- if (failed)
- return SCX_TEST_FAIL;
- else
- return SCX_TEST_PASS;
- }
- static void cleanup(void *ctx)
- {
- struct peek_dsq *skel = ctx;
- if (workload_running) {
- workload_running = false;
- for (int i = 0; i < NUM_WORKERS; i++)
- pthread_join(workload_threads[i], NULL);
- }
- peek_dsq__destroy(skel);
- }
- struct scx_test peek_dsq = {
- .name = "peek_dsq",
- .description =
- "Test DSQ create/destroy operations and future peek functionality",
- .setup = setup,
- .run = run,
- .cleanup = cleanup,
- };
- REGISTER_SCX_TEST(&peek_dsq)
|