summaryrefslogtreecommitdiff
path: root/src/utest/smp/smp_bind_affinity_tc.c
blob: 8247e3dbfd8ae199cea51d1141e17a1d6b035608 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
 * Copyright (c) 2006-2024, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-08-10     RV           the first version
 */

#include <rtthread.h>
#include "utest.h"

/**
 * @brief   Binding core affinity testcase.
 *
 * @note    Create RT_CPUS_NR threads, thread 0 is bound to core 0, other threads are not bound to specific cores,
 *          after running for a set number of times, count the number of times each core is run on the corresponding core,
 *          thread 0 should always be run on core 0, other threads will be run on different cores.
 *
 * Test Case Name: [smp_bind_affinity]
 *
 * Test Objectives:
 * - Verify that threads bound to specific cores run on those cores.
 *
 * Test Scenarios:
 * - RT_CPUS_NR threads (T0~T(RT_CPUS_NR-1)) are created, with only T0 bound to core 0. When thread Tx is running,
 * - thread_tic[x] increments by 1; if x is equal to the core ID, thread_inc[x] also increments by 1. After the
 * - program runs for a period of time, observe the value relationship between the thread_inc and thread_tic arrays.
 * - If thread_inc[x] is equal to thread_tic[x], it indicates that thread Tx is correctly bound to core x. In this test case,
 * - only thread_inc[0] will be equal to thread_tic[0].
 *
 * Verification Metrics:
 * - Output message: [I/utest] [ PASSED ] [ result ] testcase (core.smp_bind_affinity)
 *
 * Dependencies:
 * - Enable RT_USING_SMP, set RT_THREAD_PRIORITY_MAX = 256.
 *
 * Expected Results:
 * - You will see the relevant PASS message. Additionally, RT_CPUS_NR lines of printed information will be displayed,
 * - indicating whether each thread Tx has been running on core x all the time. The results show that only T0 has been
 * - running on core 0 consistently.
 */

/* Number of thread runs */
static int run_num = 100;
#define THREAD_STACK_SIZE UTEST_THR_STACK_SIZE
#define THREAD_PRIORITY   20
static rt_thread_t threads[RT_CPUS_NR];
static struct rt_spinlock lock;
static int thread_inc[RT_CPUS_NR] = {0};
static int thread_tic[RT_CPUS_NR] = {0};
static int finsh_flag = 0;
static int                num        = 0;

static void thread_entry(void *parameter)
{
    int id   = 0;
    int para = *(int *)parameter;
    while (1)
    {
        thread_tic[para]++;
        id = rt_hw_cpu_id();
        if (para == id)
        {
            thread_inc[para]++;
        }

        if (thread_tic[para] == run_num)
        {
            if (para == 0)
                uassert_int_equal(thread_inc[para], thread_tic[para]);
            else
                uassert_int_not_equal(thread_inc[para], thread_tic[para]);
            finsh_flag ++;
        }
        rt_thread_delay(5);
    }
}

static void thread_bind_affinity_tc(void)
{
    static int params[RT_CPUS_NR] = {0};
    char       thread_name[8];
    int        i, j;

    for (i = 0; i < RT_CPUS_NR; i++)
    {
        params[i] = i;
    }

    /* Create RT_CPUS_NR threads Thread 0 is bound to core 0 Other threads are not bound */
    for (i = 0; i < RT_CPUS_NR; i++)
    {
        rt_snprintf(thread_name, sizeof(thread_name), "thread%d", i);
        threads[i] = rt_thread_create(thread_name, thread_entry, (int *)&params[i], THREAD_STACK_SIZE, THREAD_PRIORITY, 20);
        if (i == 0)
        {
            rt_thread_control(threads[0], RT_THREAD_CTRL_BIND_CPU, (void *)0);
        }
        if (threads[i] != RT_NULL)
        {
            rt_thread_startup(threads[i]);
        }
    }

    while (finsh_flag != RT_CPUS_NR);

    /* Displays the number of times a thread was executed on the relevant core */
    for (j = 0; j < RT_CPUS_NR; j++)
    {
        rt_spin_lock(&lock);
        rt_kprintf("Total runs[%d], Number of times thread[%d] run on [core%d]: [%4d], always run at core%d ? %s \r\n", run_num, j, j, thread_inc[j], j, (thread_inc[j] == run_num) ? "yes" : "no");
        rt_spin_unlock(&lock);
    }
}

static rt_err_t utest_tc_init(void)
{
    rt_spin_lock_init(&lock);
    return RT_EOK;
}

static rt_err_t utest_tc_cleanup(void)
{
    for (num = 0; num < RT_CPUS_NR; num++)
    {
        rt_thread_delete(threads[num]);
    }
    return RT_EOK;
}

static void testcase(void)
{
    UTEST_UNIT_RUN(thread_bind_affinity_tc);
}
UTEST_TC_EXPORT(testcase, "core.smp_bind_affinity", utest_tc_init, utest_tc_cleanup, 10);