File Index
Files and directories
Sign in
FILE

peek_dsq.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/sched_ext/peek_dsq.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Test for DSQ operations including create, destroy, and peek operations.
  4 *
  5 * Copyright (c) 2025 Meta Platforms, Inc. and affiliates.
  6 * Copyright (c) 2025 Ryan Newton <ryan.newton@alum.mit.edu>
  7 */
  8#include <bpf/bpf.h>
  9#include <scx/common.h>
 10#include <sys/wait.h>
 11#include <unistd.h>
 12#include <pthread.h>
 13#include <string.h>
 14#include <sched.h>
 15#include "peek_dsq.bpf.skel.h"
 16#include "scx_test.h"
 17
 18#define NUM_WORKERS 4
 19
 20static bool workload_running = true;
 21static pthread_t workload_threads[NUM_WORKERS];
 22
 23/**
 24 * Background workload thread that sleeps and wakes rapidly to exercise
 25 * the scheduler's enqueue operations and ensure DSQ operations get tested.
 26 */
 27static void *workload_thread_fn(void *arg)
 28{
 29	while (workload_running) {
 30		/* Sleep for a very short time to trigger scheduler activity */
 31		usleep(1000); /* 1ms sleep */
 32		/* Yield to ensure we go through the scheduler */
 33		sched_yield();
 34	}
 35	return NULL;
 36}
 37
 38static enum scx_test_status setup(void **ctx)
 39{
 40	struct peek_dsq *skel;
 41
 42	skel = peek_dsq__open();
 43	SCX_FAIL_IF(!skel, "Failed to open");
 44	SCX_ENUM_INIT(skel);
 45	SCX_FAIL_IF(peek_dsq__load(skel), "Failed to load skel");
 46
 47	*ctx = skel;
 48
 49	return SCX_TEST_PASS;
 50}
 51
 52static int print_observed_pids(struct bpf_map *map, int max_samples, const char *dsq_name)
 53{
 54	long count = 0;
 55
 56	printf("Observed %s DSQ peek pids:\n", dsq_name);
 57	for (int i = 0; i < max_samples; i++) {
 58		long pid;
 59		int err;
 60
 61		err = bpf_map_lookup_elem(bpf_map__fd(map), &i, &pid);
 62		if (err == 0) {
 63			if (pid == 0) {
 64				printf("  Sample %d: NULL peek\n", i);
 65			} else if (pid > 0) {
 66				printf("  Sample %d: pid %ld\n", i, pid);
 67				count++;
 68			}
 69		} else {
 70			printf("  Sample %d: error reading pid (err=%d)\n", i, err);
 71		}
 72	}
 73	printf("Observed ~%ld pids in the %s DSQ(s)\n", count, dsq_name);
 74	return count;
 75}
 76
 77static enum scx_test_status run(void *ctx)
 78{
 79	struct peek_dsq *skel = ctx;
 80	bool failed = false;
 81	int seconds = 3;
 82	int err;
 83
 84	/* Enable the scheduler to test DSQ operations */
 85	printf("Enabling scheduler to test DSQ insert operations...\n");
 86
 87	struct bpf_link *link =
 88		bpf_map__attach_struct_ops(skel->maps.peek_dsq_ops);
 89
 90	if (!link) {
 91		SCX_ERR("Failed to attach struct_ops");
 92		return SCX_TEST_FAIL;
 93	}
 94
 95	printf("Starting %d background workload threads...\n", NUM_WORKERS);
 96	workload_running = true;
 97	for (int i = 0; i < NUM_WORKERS; i++) {
 98		err = pthread_create(&workload_threads[i], NULL, workload_thread_fn, NULL);
 99		if (err) {
100			SCX_ERR("Failed to create workload thread %d: %s", i, strerror(err));
101			/* Stop already created threads */
102			workload_running = false;
103			for (int j = 0; j < i; j++)
104				pthread_join(workload_threads[j], NULL);
105			bpf_link__destroy(link);
106			return SCX_TEST_FAIL;
107		}
108	}
109
110	printf("Waiting for enqueue events.\n");
111	sleep(seconds);
112	while (skel->data->enqueue_count <= 0) {
113		printf(".");
114		fflush(stdout);
115		sleep(1);
116		seconds++;
117		if (seconds >= 30) {
118			printf("\n\u2717 Timeout waiting for enqueue events\n");
119			/* Stop workload threads and cleanup */
120			workload_running = false;
121			for (int i = 0; i < NUM_WORKERS; i++)
122				pthread_join(workload_threads[i], NULL);
123			bpf_link__destroy(link);
124			return SCX_TEST_FAIL;
125		}
126	}
127
128	workload_running = false;
129	for (int i = 0; i < NUM_WORKERS; i++) {
130		err = pthread_join(workload_threads[i], NULL);
131		if (err) {
132			SCX_ERR("Failed to join workload thread %d: %s", i, strerror(err));
133			bpf_link__destroy(link);
134			return SCX_TEST_FAIL;
135		}
136	}
137	printf("Background workload threads stopped.\n");
138
139	SCX_EQ(skel->data->uei.kind, EXIT_KIND(SCX_EXIT_NONE));
140
141	/* Detach the scheduler */
142	bpf_link__destroy(link);
143
144	printf("Enqueue/dispatch count over %d seconds: %d / %d\n", seconds,
145		skel->data->enqueue_count, skel->data->dispatch_count);
146	printf("Debug: ksym_exists=%d\n",
147	       skel->bss->debug_ksym_exists);
148
149	/* Check DSQ insert result */
150	printf("DSQ insert test done on cpu: %d\n", skel->data->insert_test_cpu);
151	if (skel->data->insert_test_cpu != -1)
152		printf("\u2713 DSQ insert succeeded !\n");
153	else {
154		printf("\u2717 DSQ insert failed or not attempted\n");
155		failed = true;
156	}
157
158	/* Check DSQ peek results */
159	printf("  DSQ peek result 1 (before insert): %d\n",
160	       skel->data->dsq_peek_result1);
161	if (skel->data->dsq_peek_result1 == 0)
162		printf("\u2713 DSQ peek verification success: peek returned NULL!\n");
163	else {
164		printf("\u2717 DSQ peek verification failed\n");
165		failed = true;
166	}
167
168	printf("  DSQ peek result 2 (after insert): %ld\n",
169	       skel->data->dsq_peek_result2);
170	printf("  DSQ peek result 2, expected: %ld\n",
171	       skel->data->dsq_peek_result2_expected);
172	if (skel->data->dsq_peek_result2 ==
173	    skel->data->dsq_peek_result2_expected)
174		printf("\u2713 DSQ peek verification success: peek returned the inserted task!\n");
175	else {
176		printf("\u2717 DSQ peek verification failed\n");
177		failed = true;
178	}
179
180	printf("  Inserted test task -> pid: %ld\n", skel->data->dsq_inserted_pid);
181	printf("  DSQ peek result 2 -> pid: %ld\n", skel->data->dsq_peek_result2_pid);
182
183	int pid_count;
184
185	pid_count = print_observed_pids(skel->maps.peek_results,
186					skel->data->max_samples, "DSQ pool");
187	printf("Total non-null peek observations: %ld out of %ld\n",
188	       skel->data->successful_peeks, skel->data->total_peek_attempts);
189
190	if (skel->bss->debug_ksym_exists && pid_count == 0) {
191		printf("\u2717 DSQ pool test failed: no successful peeks in native mode\n");
192		failed = true;
193	}
194	if (skel->bss->debug_ksym_exists && pid_count > 0)
195		printf("\u2713 DSQ pool test success: observed successful peeks in native mode\n");
196
197	if (failed)
198		return SCX_TEST_FAIL;
199	else
200		return SCX_TEST_PASS;
201}
202
203static void cleanup(void *ctx)
204{
205	struct peek_dsq *skel = ctx;
206
207	if (workload_running) {
208		workload_running = false;
209		for (int i = 0; i < NUM_WORKERS; i++)
210			pthread_join(workload_threads[i], NULL);
211	}
212
213	peek_dsq__destroy(skel);
214}
215
216struct scx_test peek_dsq = {
217	.name = "peek_dsq",
218	.description =
219		"Test DSQ create/destroy operations and future peek functionality",
220	.setup = setup,
221	.run = run,
222	.cleanup = cleanup,
223};
224REGISTER_SCX_TEST(&peek_dsq)
~/ Read-only file preview.