[RFC v3 i-g-t] tests/intel/sec_xe_exec_queue_timeslice_abuse: Validate the Impact of Timeslice Abuse on Exec Queues
Kamil Konieczny
kamil.konieczny at linux.intel.com
Wed May 7 12:33:25 UTC 2025
Hi Peter,
On 2025-05-07 at 12:41:10 +0200, Peter Senna Tschudin wrote:
> DO NOT MERGE!
>
> The objective is to test the behavior of the GPU scheduler under
> conditions where one execution queue ("attacker") is configured with an
> abnormally large timeslice, potentially disrupting the normal execution
> of another queue ("attacked"). The explicit attack point is the ioctl
> DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY.
>
> This temporarily disables drm and xe logging to prevent it from slowing
> down and serializing the tests. Using igt_drm_debug_level_update()
> ensures that the logging level is restored after this igt is done.
>
> This RFC implements the first step that is reading timeslice values for
> each engine and run the following tests on timeslice limits:
> - Boundary Value Analysis: Focuses on testing at the boundaries of
> input values with values such as max - 1, max, max + 1.
> - Equivalence Partitioning: Divide values into partitions where all
> values behave similarly and test one value from each partition.
> - Fuzz Testing: Basic fuzz tester for
> - Large numbers
> - Empty value
> - '\0'
> - 10'000 u64 random values
> - Fuzz stress test: Create 1000 threads and call the fuzzing test.
> While this takes about 30 seconds to run, it produces several
> megabytes of dmesg.
>
> The proposed steps are (this patch goes until 2a):
>
> 1. Determine the values for the following parameters:
> - `timeslice_duration_us`: Default timeslice duration in
> microseconds.
> - `timeslice_duration_min`: Minimum allowable timeslice duration.
> - `timeslice_duration_max`: Maximum allowable timeslice duration.
>
> 2. Create two execution queues with the following configurations:
> - `attacked`: Queue with standard/default settings.
> - `attacker`: Queue configured with an extended timeslice
> duration. The goal is to:
> a) Try to set timeslice to invalid values. This is
> expected to fail.
>
> b) Create the attacker queue setting the timeslice to
> `timeslice_duration_max`.
>
> 3. Submit tasks to both queues:
> - Submit a workload to the `attacked` queue with normal
> operations.
> - Submit a workload to the `attacker` queue designed to
> maximize its timeslice and potentially disrupt the GPU
> scheduler.
>
> 4. Verify the behavior of the `attacked` queue:
> - Ensure that tasks in the `attacked` queue execute within the
> expected time constraints and are not delayed or blocked due
> to the extended timeslice of the `attacker` queue.
> - Specifically, confirm that tasks in the `attacked` queue do
> not exceed `timeslice_duration_max` in terms of execution
> delays or interruptions.
>
> Cc: michal.winiarski at intel.com
> Cc: rodrigo.vivi at intel.com
> Signed-off-by: Peter Senna Tschudin <peter.senna at linux.intel.com>
> ---
> .../intel/sec_xe_exec_queue_timeslice_abuse.c | 689 ++++++++++++++++++
Small nit about naming, please start all Xe tests with xe_ prefix,
so for example use for filename:
(imho this name looks good)
tests/intel/xe_sec_exec_queue.c
or (looks not so good)
tests/intel/xe_exec_queue_sec.c
and then name tests like timeslice-abuse
> tests/meson.build | 1 +
> 2 files changed, 690 insertions(+)
> create mode 100644 tests/intel/sec_xe_exec_queue_timeslice_abuse.c
>
> diff --git a/tests/intel/sec_xe_exec_queue_timeslice_abuse.c b/tests/intel/sec_xe_exec_queue_timeslice_abuse.c
> new file mode 100644
> index 000000000..abbc384c4
> --- /dev/null
> +++ b/tests/intel/sec_xe_exec_queue_timeslice_abuse.c
> @@ -0,0 +1,689 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2025 Intel Corporation
> + */
> +
> +/*
> + * Test Specification: Validate the Impact of Timeslice Abuse on Exec Queues
> + *
> + * Objective
> + * Test the behavior of the GPU scheduler under conditions where one execution
> + * queue ("attacker") is configured with an abnormally large timeslice,
> + * potentially disrupting the normal execution of another queue ("attacked").
> + *
> + * Steps:
> + *
> + * For each GPU engine available:
> + * 1. Determine the values for the following parameters:
> + * - `timeslice_duration_us`: Default timeslice duration in
> + * microseconds.
> + * - `timeslice_duration_min`: Minimum allowable timeslice duration.
> + * - `timeslice_duration_max`: Maximum allowable timeslice duration.
> + *
> + * 2. Create two execution queues with the following configurations:
> + * - `attacked`: Queue with standard/default settings.
> + * - `attacker`: Queue configured with an extended timeslice
> + * duration. The goal is to:
> + * a) First attempt to set a timeslice greater than
> + * `timeslice_duration_max`.
> + * b) If setting a timeslice above `timeslice_duration_max`
> + * fails, fallback to setting the timeslice to
> + * `timeslice_duration_max`.
> + *
> + * 3. Submit tasks to both queues:
> + * - Submit a workload to the `attacked` queue with normal
> + * operations.
> + * - Submit a workload to the `attacker` queue designed to
> + * maximize its timeslice and potentially disrupt the GPU
> + * scheduler.
> + *
> + * 4. Verify the behavior of the `attacked` queue:
> + * - Ensure that tasks in the `attacked` queue execute within the
> + * expected time constraints and are not delayed or blocked due
> + * to the extended timeslice of the `attacker` queue.
> + * - Specifically, confirm that tasks in the `attacked` queue do
> + * not exceed `timeslice_duration_max` in terms of execution
> + * delays or interruptions.
> + *
> + */
> +
> +#include <dirent.h>
> +#include <fcntl.h>
> +
> +#include "igt.h"
> +#include "igt_list.h"
> +#include "igt_sysfs.h"
> +#include "xe_drm.h"
> +#include "xe/xe_ioctl.h"
> +#include "xe/xe_query.h"
> +
> +#define MAX_U64 0xFFFFFFFFFFFFFFFF
> +
> +static struct igt_list_head engines_list;
> +
> +/* Struct to Hold Data for Each Engine */
> +struct engines_timeslice_test_data {
> + /* Name of the GPU engine (e.g., "CCS", "VCS", "RCS", "BCS", "VECS") */
> + const char *engine_name;
> +
> + /* Minimum allowable timeslice duration (microseconds) */
> + uint32_t timeslice_min;
> +
> + /* Maximum allowable timeslice duration (microseconds) */
> + uint32_t timeslice_max;
> +
> + /* Timeslice value set for the attacker queue (microseconds) */
> + uint32_t timeslice_set;
> +
> + /* Linked list node */
> + struct igt_list_head link;
> +};
> +
> +/* Struct for parametric testing */
> +struct timeslice_test_case {
> + uint64_t value;
> + int expected_result;
> +};
> +
> +typedef struct {
> + int xe;
> + int vm;
> + int random_count;
> +} thread_args_t;
> +
> +/**
> + * engines_list_add_timeslices: Check if there is already an entry in the list
> + * for the engine and add timeslices.
> + * @engine: name of the engine
> + * @set: timeslice duration set for the attacker queue
> + * @min: minimum allowable timeslice duration
> + * @max: maximum allowable timeslice duration
> + *
> + * Returns: bool indicating if timeslices were added to the list
> + *
> + */
> +static bool engines_list_add_timeslices(const char *engine, uint32_t set,
> + uint32_t min, uint32_t max)
> +{
> + struct engines_timeslice_test_data *engine_data = NULL;
> +
> + /* Check if the engine already exists in the list. If it does
> + * add the timeslice values to the existing entry
> + */
> + igt_list_for_each_entry(engine_data, &engines_list, link) {
> + if (strcmp(engine_data->engine_name, engine) == 0) {
> + engine_data->timeslice_set = set;
> + engine_data->timeslice_min = min;
> + engine_data->timeslice_max = max;
> + return true;
> + }
> + }
> + /* If the engine does not exist, create a new entry */
> + engine_data = malloc(sizeof(*engine_data));
> + if (!engine_data)
> + return false;
> +
> + engine_data->engine_name = strdup(engine);
> + engine_data->timeslice_set = set;
> + engine_data->timeslice_min = min;
> + engine_data->timeslice_max = max;
> +
> + igt_list_add(&engine_data->link, &engines_list);
> + return true;
> +}
> +
> +/**
> + * engines_list_print_all: Print all engines in the list
> + *
> + * Returns: void
> + *
> + */
> +static void engines_list_print_all(void)
> +{
> + struct engines_timeslice_test_data *engine_data = NULL;
> +
> + igt_warn("Engines List:\n");
> + igt_list_for_each_entry(engine_data, &engines_list, link) {
> + igt_warn("Engine: %s, Set: %u, Min: %u, Max: %u\n",
> + engine_data->engine_name,
> + engine_data->timeslice_set,
> + engine_data->timeslice_min,
> + engine_data->timeslice_max);
> + }
> +}
> +
> +/**
> + * engines_list_free_all: Free all engines in the list
> + *
> + * Returns: void
> + *
> + */
> +static void engines_list_free_all(void)
> +{
> + struct engines_timeslice_test_data *engine_data = NULL, *tmp = NULL;
> +
> + igt_list_for_each_entry_safe(engine_data, tmp, &engines_list, link) {
> + free((void *)engine_data->engine_name);
> + free(engine_data);
> + }
> +}
> +
> +/**
> + * debug_info_igt_assert: Print debug information for assertion failures
> + * @msg: message to print
> + * @cond: condition to evaluate
> + */
> +static void debug_info_igt_assert(const char *msg, bool cond)
> +{
> + if (!cond) {
> + igt_warn("Assertion failed: %s\n", msg);
> + engines_list_print_all();
> + }
> + igt_assert(cond);
> +}
> +
> +/**
> + * get_queue_timeslice_properties: Get the timeslice properties for an engine
> + *
> + * @xe: xe device file descriptor
> + * @engine: engine file descriptor
> + * @set: pointer to store the timeslice duration set for the attacker queue
> + * @min: pointer to store the minimum allowable timeslice duration
> + * @max: pointer to store the maximum allowable timeslice duration
> + *
> + * Returns: 0 on success, -1 on failure
> + */
> +static int get_queue_timeslice_properties(int xe, int engine,
> + unsigned int *set, unsigned int *min, unsigned int *max)
> +{
> + int defaults;
> +
> + defaults = openat(engine, ".defaults", O_DIRECTORY);
> + if (defaults == -1)
> + return -1; /* Failure: Unable to open the defaults directory */
> +
> + /* Read the max, min, and set values from the sysfs */
> + if (igt_sysfs_scanf(defaults, "timeslice_duration_max", "%u", max) != 1 ||
> + igt_sysfs_scanf(defaults, "timeslice_duration_min", "%u", min) != 1 ||
> + igt_sysfs_scanf(engine, "timeslice_duration_us", "%u", set) != 1) {
> + close(defaults);
> + return -1; /* Failure: Unable to read sysfs values */
> + }
> + close(defaults);
> +
> + return 0; /* Success */
> +}
> +
> +/**
> + * random_u64: Generate a random 64-bit unsigned integer
> + *
> + * Returns: A random 64-bit unsigned integer
> + */
> +static uint64_t random_u64(void)
> +{
> + uint64_t high = ((uint64_t)rand() << 32);
> + uint64_t low = (uint64_t)rand();
> +
> + return high | low;
> +}
> +
> +/**
> + * TEST: Validate the Impact of Timeslice Abuse on Exec Queues
> + * Category: Security
> + * Mega feature: Security Validation Plan
> + * Sub-category: Security Validation Plan
> + * Functionality: Test if exec queue timeslice property can be used as an
> + * attack to prevent other queues from running
> + * Test category: security test
> + *
> + * SUBTEST: get-xe-exec-queue-timeslice-properties
> + * Description: Test to check if timeslice properties are available and
> + * read them.
> + * Test category: functionality test
> + */
Move this 'TEST:' to begin of file, just after a copyright.
SUBTEST imho should be a short name, you could describe it at lenght
in descriprion. Same note about subtests names len apply below.
Regards,
Kamil
> +
> +/**
> + * get_xe_exec_queue_timeslice_properties:
> + * @xe: xe device file descriptor
> + *
> + * Returns: void
> + */
> +static void get_xe_exec_queue_timeslice_properties(int xe)
> +{
> + unsigned int max = -1;
> + unsigned int min = -1;
> + unsigned int set = -1;
> + int gt = -1;
> +
> + xe_for_each_gt(xe, gt) {
> + int engines = -1;
> + int gt_fd = -1;
> + DIR *dir;
> + struct dirent *de;
> +
> + gt_fd = xe_sysfs_gt_open(xe, gt);
> + igt_require(gt_fd != -1);
> +
> + engines = openat(gt_fd, "engines", O_RDONLY);
> + igt_require(engines != -1);
> +
> + lseek(engines, 0, SEEK_SET);
> +
> + dir = fdopendir(engines);
> + if (!dir)
> + close(engines);
> +
> + while ((de = readdir(dir))) {
> + int engine_fd = -1;
> +
> + if (*de->d_name == '.')
> + continue;
> +
> + engine_fd = openat(engines, de->d_name, O_RDONLY);
> + if (engine_fd < 0)
> + continue;
> +
> + /* Check if the timeslice properties are available */
> + if (get_queue_timeslice_properties(xe, engine_fd, &set, &min, &max) == 0)
> + engines_list_add_timeslices(de->d_name, set, min, max);
> + else
> + igt_warn("Failed to get timeslice properties\n");
> +
> + close(engine_fd);
> + }
> + close(gt_fd);
> + }
> +}
> +
> +/**
> + * xe_exec_queue_test_create_timeslice:
> + * @xe: xe device file descriptor
> + * @vm: vm file descriptor
> + * @timeslice: timeslice value to be set
> + * @expected_ret: expected return value
> + *§
> + * Returns: bool indicating if the queue creation was successful
> + *
> + */
> +static bool xe_exec_queue_test_create_timeslice(int xe, int vm,
> + uint64_t timeslice,
> + int expected_ret)
> +{
> + uint32_t queue_id = -1;
> + int ret;
> + char error_msg[256];
> +
> + struct drm_xe_engine_class_instance instance = {
> + .engine_class = DRM_XE_ENGINE_CLASS_VM_BIND,
> + };
> + struct drm_xe_ext_set_property property = {
> + .base.name = DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY,
> + .base.next_extension = 0,
> + .property = DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE,
> + .value = timeslice,
> + };
> +
> + igt_assert(vm != -1);
> +
> + ret = __xe_exec_queue_create(xe, vm, 1, 1,
> + &instance, to_user_pointer(&property),
> + &queue_id);
> + if (ret == 0)
> + xe_exec_queue_destroy(xe, queue_id);
> +
> + if (ret == expected_ret)
> + return true;
> +
> + snprintf(error_msg, sizeof(error_msg),
> + "ERROR: Failed to create exec queue with timeslice %lu, expected %d, got %d",
> + timeslice, expected_ret, ret);
> + debug_info_igt_assert(error_msg, ret == expected_ret);
> +
> + return false;
> +}
> +
> +/**
> + * xe_exec_queue_test_iterate_create_timeslice:
> + * @xe: xe device file descriptor
> + * @vm: vm file descriptor
> + * @test_case: struct containing the timeslice value and expected result
> + * @test_case_count: number of test cases
> + *
> + * Returns: void
> + *
> + */
> +static void xe_exec_queue_test_iterate_create_timeslice(int xe, int vm,
> + struct timeslice_test_case *test_case,
> + int test_case_count)
> +{
> + for (int i = 0; i < test_case_count; i++)
> + xe_exec_queue_test_create_timeslice(xe, vm,
> + test_case[i].value,
> + test_case[i].expected_result);
> +}
> +
> +/**
> + * SUBTEST: xe-exec-queue-timeslice-boundary-value-analysis
> + * Description: Test to check if the timeslice boundary values are
> + * working as expected.
> + * Test category: functionality test
> + */
> +
> +/**
> + * xe_exec_queue_timeslice_boundary_value_analysis:
> + * @xe: xe device file descriptor
> + * @vm: vm file descriptor
> + *
> + * Returns: void
> + *
> + */
> +static void xe_exec_queue_timeslice_boundary_value_analysis(int xe, int vm)
> +{
> + struct engines_timeslice_test_data *engine_data = NULL;
> + int test_case_count = 6;
> + struct timeslice_test_case test_cases[test_case_count];
> +
> + igt_list_for_each_entry(engine_data, &engines_list, link) {
> + if (engine_data->timeslice_set != -1)
> + break;
> + }
> + igt_assert(engine_data != NULL);
> + igt_assert(engine_data->timeslice_set != -1);
> +
> + /* Test cases for boundary value analysis */
> + test_cases[0].value = engine_data->timeslice_max + 1;
> + test_cases[0].expected_result = -EINVAL;
> + test_cases[1].value = engine_data->timeslice_max;
> + test_cases[1].expected_result = 0;
> + test_cases[2].value = engine_data->timeslice_max - 1;
> + test_cases[2].expected_result = 0;
> + test_cases[3].value = engine_data->timeslice_min - 1;
> + test_cases[3].expected_result = -EINVAL;
> + test_cases[4].value = engine_data->timeslice_min;
> + test_cases[4].expected_result = 0;
> + test_cases[5].value = engine_data->timeslice_min + 1;
> + test_cases[5].expected_result = 0;
> +
> + /* Check if the timeslice values are working as expected */
> + xe_exec_queue_test_iterate_create_timeslice(xe, vm, test_cases,
> + test_case_count);
> +}
> +
> +/**
> + * SUBTEST: xe-exec-queue-timeslice-equivalence-partitioning
> + * Description: Divide timeslice values into partitions where all values should
> + * have the same behavior. This test checks if the timeslice
> + * values are working as expected.
> + *
> + * Test category: functionality test
> + */
> +
> +/**
> + * xe_exec_queue_timeslice_equivalence_partitioning:
> + * @xe: xe device file descriptor
> + * @vm: vm file descriptor
> + *
> + * Returns: void
> + *
> + */
> +static void xe_exec_queue_timeslice_equivalence_partitioning(int xe, int vm)
> +{
> + struct engines_timeslice_test_data *engine_data = NULL;
> + int test_case_count = 5;
> + struct timeslice_test_case test_cases[test_case_count];
> +
> + igt_list_for_each_entry(engine_data, &engines_list, link) {
> + if (engine_data->timeslice_set != -1)
> + break;
> + }
> + igt_assert(engine_data != NULL);
> + igt_assert(engine_data->timeslice_set != -1);
> +
> + /* Test cases for equivalence partitioning */
> + test_cases[0].value = engine_data->timeslice_min - 1;
> + test_cases[0].expected_result = -EINVAL;
> + test_cases[1].value = engine_data->timeslice_min;
> + test_cases[1].expected_result = 0;
> + test_cases[2].value = (engine_data->timeslice_min + engine_data->timeslice_max) / 2;
> + test_cases[2].expected_result = 0;
> + test_cases[3].value = engine_data->timeslice_max;
> + test_cases[3].expected_result = 0;
> + test_cases[4].value = engine_data->timeslice_max + 1;
> + test_cases[4].expected_result = -EINVAL;
> +
> + /* Check if the timeslice values are working as expected */
> + xe_exec_queue_test_iterate_create_timeslice(xe, vm, test_cases,
> + test_case_count);
> +}
> +
> +/**
> + * SUBTEST: xe-exec-queue-timeslice-fuzzing
> + * Description: Test a large set of random timeslice values to check if the
> + * behavior is as expected. Includes testing for:
> + * - very large numbers
> + * - empty value
> + * - null value
> + *
> + * Test category: functionality test
> + */
> +
> +/**
> + * xe_exec_queue_timeslice_fuzzing:
> + * @xe: xe device file descriptor
> + * @random_count: number of random timeslice values to test
> + *
> + * Returns: void
> + *
> + */
> +static void xe_exec_queue_timeslice_fuzzing(int xe, int vm, int random_count)
> +{
> + struct engines_timeslice_test_data *engine_data = NULL;
> + __u64 timeslice_value;
> + uint32_t queue_id = -1;
> +
> + struct drm_xe_engine_class_instance instance = {
> + .engine_class = DRM_XE_ENGINE_CLASS_VM_BIND,
> + };
> + struct drm_xe_ext_set_property empty_value_property = {
> + .base.name = DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY,
> + .base.next_extension = 0,
> + .property = DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE,
> + };
> +
> + igt_list_for_each_entry(engine_data, &engines_list, link) {
> + if (engine_data->timeslice_set != -1)
> + break;
> + }
> + igt_assert(engine_data != NULL);
> + igt_assert(engine_data->timeslice_set != -1);
> +
> + igt_assert(vm != -1);
> +
> + /* test empty timeslice_value 10 times*/
> + for (int i = 0; i < 10; i++)
> + igt_assert_eq(__xe_exec_queue_create(xe, vm, 1, 1, &instance,
> + to_user_pointer(&empty_value_property),
> + &queue_id), -EINVAL);
> +
> + /* Very large number 10 times for max_u64 and for max_u64 -1 */
> + timeslice_value = MAX_U64;
> + for (int i = 0; i < 10; i++)
> + xe_exec_queue_test_create_timeslice(xe, vm, timeslice_value,
> + -EINVAL);
> + timeslice_value = MAX_U64 - 1;
> + for (int i = 0; i < 10; i++)
> + xe_exec_queue_test_create_timeslice(xe, vm, timeslice_value,
> + -EINVAL);
> +
> + /* Test '\0' timeslice_value 10 times */
> + for (int i = 0; i < 10; i++)
> + xe_exec_queue_test_create_timeslice(xe, vm, '\0', -EINVAL);
> +
> + /* Test random_count random values */
> + srand((unsigned int)time(NULL));
> +
> + for (int i = 0; i < random_count; i++) {
> + timeslice_value = random_u64();
> +
> + if (timeslice_value < engine_data->timeslice_min ||
> + timeslice_value > engine_data->timeslice_max)
> + xe_exec_queue_test_create_timeslice(xe, vm,
> + timeslice_value,
> + -EINVAL);
> + else
> + xe_exec_queue_test_create_timeslice(xe, vm,
> + timeslice_value,
> + 0);
> + }
> +}
> +
> +/**
> + * SUBTEST: xe-exec-queue-timeslice-fuzzing-stress-test
> + * Description: Test a large set of random timeslice values to check if the
> + * behavior is as expected. Includes testing for:
> + * - very large numbers
> + * - empty value
> + * - null value
> + *
> + * Test category: functionality test
> + */
> +
> + /**
> + * fuzz_workload: Thread function to perform fuzz testing
> + * @args: thread arguments containing the xe device file descriptor and
> + * random count
> + *
> + * Returns: void
> + */
> +static void *fuzz_workload(void *args)
> +{
> + thread_args_t *thread_args = (thread_args_t *) args;
> +
> + /* Call the fuzz testing function with the provided arguments */
> + xe_exec_queue_timeslice_fuzzing(thread_args->xe, thread_args->vm,
> + thread_args->random_count);
> +
> + return NULL;
> +}
> +
> +/**
> + * xe_exec_queue_timeslice_fuzzing_stress_threads:
> + * @xe: xe device file descriptor
> + * @vm: vm file descriptor
> + * @thread_count: number of threads to create
> + * @random_count_per_thread: number of random timeslice values per thread
> + *
> + * Returns: void
> + *
> + */
> +static void xe_exec_queue_timeslice_fuzzing_stress_threads(int xe,
> + int vm,
> + int thread_count,
> + int random_count_per_thread)
> +{
> + pthread_t *threads;
> + thread_args_t *thread_args;
> +
> + threads = malloc(thread_count * sizeof(pthread_t));
> + igt_assert(threads);
> + thread_args = malloc(thread_count * sizeof(thread_args_t));
> + igt_assert(thread_args);
> +
> + igt_info("Starting stress test with %d threads and with %d random tests each...\n",
> + thread_count, random_count_per_thread);
> +
> + // Create the specified number of threads
> + for (int i = 0; i < thread_count; i++) {
> + thread_args[i].xe = xe;
> + thread_args[i].vm = vm;
> + thread_args[i].random_count = random_count_per_thread;
> +
> + if (pthread_create(&threads[i], NULL, fuzz_workload, &thread_args[i]) != 0) {
> + igt_info("Failed to create thread %d.\n", i);
> + exit(EXIT_FAILURE);
> + }
> + }
> +
> + // Wait for all threads to finish
> + for (int i = 0; i < thread_count; i++) {
> + if (pthread_join(threads[i], NULL) != 0)
> + igt_info("Failed to join thread %d.\n", i);
> + }
> +
> + igt_info("Stress test with %d threads completed successfully.\n",
> + thread_count);
> +
> + // Free allocated memory
> + free(threads);
> + free(thread_args);
> +}
> +
> +igt_main
> +{
> + bool has_sysfs = false;
> + int sys_fd = -1;
> + int xe = -1;
> + int vm = -1;
> +
> + igt_fixture {
> + /* Disable logging for this igt: Logging imposes a 20X slowdown
> + * on the operations we are trying to stress test. The logging
> + * slows down and serializes the operations, which is not what
> + * we want. igt_drm_debug_level_update() installs an exit
> + * handler making sure that the logging is reset to the previous
> + * value when the test ends.
> + */
> + igt_drm_debug_level_update(0);
> +
> + /* Initialize the list of engines */
> + IGT_INIT_LIST_HEAD(&engines_list);
> +
> + xe = drm_open_driver(DRIVER_XE);
> + sys_fd = igt_sysfs_open(xe);
> +
> + if (sys_fd != -1) {
> + close(sys_fd);
> + has_sysfs = true;
> + } else {
> + has_sysfs = false;
> + }
> + }
> +
> + igt_subtest("get-xe-exec-queue-timeslice-properties") {
> + igt_require(has_sysfs);
> + get_xe_exec_queue_timeslice_properties(xe);
> + }
> +
> + igt_fixture {
> + vm = xe_vm_create(xe, 0, 0);
> + igt_assert(vm != -1);
> + }
> +
> + igt_subtest("xe-exec-queue-timeslice-boundary-value-analysis") {
> + xe_exec_queue_timeslice_boundary_value_analysis(xe, vm);
> + }
> +
> + igt_subtest("xe-exec-queue-timeslice-equivalence-partitioning") {
> + xe_exec_queue_timeslice_equivalence_partitioning(xe, vm);
> + }
> +
> + igt_subtest("xe-exec-queue-timeslice-fuzzing") {
> + xe_exec_queue_timeslice_fuzzing(xe, vm, 1000000);
> + }
> +
> + igt_subtest("xe-exec-queue-timeslice-fuzzing-stress-test") {
> + xe_exec_queue_timeslice_fuzzing_stress_threads(xe, vm,
> + 50000, 500);
> + }
> +
> + igt_fixture {
> + engines_list_free_all();
> + close(sys_fd);
> +
> + if (vm != -1)
> + xe_vm_destroy(xe, vm);
> +
> + xe_device_put(xe);
> + drm_close_driver(xe);
> + }
> +}
> diff --git a/tests/meson.build b/tests/meson.build
> index 20ddddb89..560b74ceb 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -273,6 +273,7 @@ intel_kms_progs = [
> ]
>
> intel_xe_progs = [
> + 'sec_xe_exec_queue_timeslice_abuse',
> 'xe_wedged',
> 'xe_ccs',
> 'xe_create',
> --
> 2.43.0
>
More information about the igt-dev
mailing list