1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright(c) 2022 Huawei Technologies Co., Ltd
4 * Author: Li Mengfei <[email protected]>
5 * Zhao Gongyi <[email protected]>
6 */
7
8 /*\
9 * [Description]
10 *
11 * 1. Create a high nice thread and a low nice thread, the main
12 * thread wake them at the same time
13 * 2. Both threads run on the same CPU
14 * 3. Verify that the low nice thread executes more time than
15 * the high nice thread
16 */
17
18 #define _GNU_SOURCE
19 #include <pthread.h>
20 #include <sys/types.h>
21 #include <stdio.h>
22 #include "tst_test.h"
23 #include "tst_safe_pthread.h"
24 #include "lapi/syscalls.h"
25 #include "tst_safe_clocks.h"
26 #include "tst_timer.h"
27
28 static pthread_barrier_t barrier;
29
set_nice(int nice_inc)30 static void set_nice(int nice_inc)
31 {
32 int orig_nice;
33
34 orig_nice = SAFE_GETPRIORITY(PRIO_PROCESS, 0);
35
36 TEST(nice(nice_inc));
37
38 if (TST_RET != (orig_nice + nice_inc)) {
39 tst_brk(TBROK | TTERRNO, "nice(%d) returned %li, expected %i",
40 nice_inc, TST_RET, orig_nice + nice_inc);
41 }
42
43 if (TST_ERR)
44 tst_brk(TBROK | TTERRNO, "nice(%d) failed", nice_inc);
45 }
46
do_something(void)47 static void do_something(void)
48 {
49 volatile int number = 0;
50
51 while (1) {
52 number++;
53
54 TEST(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL));
55 if (TST_RET != 0) {
56 tst_brk(TBROK | TRERRNO,
57 "pthread_setcancelstate() failed");
58 }
59 pthread_testcancel();
60 }
61 }
62
thread_fn(void * arg)63 static void *thread_fn(void *arg)
64 {
65 set_nice((intptr_t)arg);
66 SAFE_PTHREAD_BARRIER_WAIT(&barrier);
67 do_something();
68
69 return NULL;
70 }
71
setup(void)72 static void setup(void)
73 {
74 size_t size;
75 size_t i;
76 int nrcpus = 1024;
77 cpu_set_t *set;
78 int some_cpu;
79
80 set = CPU_ALLOC(nrcpus);
81 if (!set)
82 tst_brk(TBROK | TERRNO, "CPU_ALLOC()");
83
84 size = CPU_ALLOC_SIZE(nrcpus);
85 CPU_ZERO_S(size, set);
86 if (sched_getaffinity(0, size, set) < 0)
87 tst_brk(TBROK | TERRNO, "sched_getaffinity()");
88
89 for (i = 0; i < size * 8; i++)
90 if (CPU_ISSET_S(i, size, set))
91 some_cpu = i;
92
93 CPU_ZERO_S(size, set);
94 CPU_SET_S(some_cpu, size, set);
95 if (sched_setaffinity(0, size, set) < 0)
96 tst_brk(TBROK | TERRNO, "sched_setaffinity()");
97
98 CPU_FREE(set);
99 }
100
verify_nice(void)101 static void verify_nice(void)
102 {
103 intptr_t nice_inc_high = -1;
104 intptr_t nice_inc_low = -2;
105 clockid_t nice_low_clockid, nice_high_clockid;
106 struct timespec nice_high_ts, nice_low_ts;
107 long long delta;
108 pthread_t thread[2];
109
110 SAFE_PTHREAD_BARRIER_INIT(&barrier, NULL, 3);
111
112 SAFE_PTHREAD_CREATE(&thread[0], NULL, thread_fn,
113 (void *)nice_inc_high);
114 SAFE_PTHREAD_CREATE(&thread[1], NULL, thread_fn,
115 (void *)nice_inc_low);
116
117 SAFE_PTHREAD_BARRIER_WAIT(&barrier);
118
119 sleep(tst_remaining_runtime());
120
121 TEST(pthread_getcpuclockid(thread[1], &nice_low_clockid));
122 if (TST_RET != 0)
123 tst_brk(TBROK | TRERRNO, "clock_getcpuclockid() failed");
124
125 TEST(pthread_getcpuclockid(thread[0], &nice_high_clockid));
126 if (TST_RET != 0)
127 tst_brk(TBROK | TRERRNO, "clock_getcpuclockid() failed");
128
129 SAFE_CLOCK_GETTIME(nice_low_clockid, &nice_low_ts);
130 SAFE_CLOCK_GETTIME(nice_high_clockid, &nice_high_ts);
131
132 tst_res(TINFO, "Nice low thread CPU time: %ld.%09ld s",
133 nice_low_ts.tv_sec, nice_low_ts.tv_nsec);
134 tst_res(TINFO, "Nice high thread CPU time: %ld.%09ld s",
135 nice_high_ts.tv_sec, nice_high_ts.tv_nsec);
136
137 delta = tst_timespec_diff_ns(nice_low_ts, nice_high_ts);
138 if (delta < 0) {
139 tst_res(TFAIL, "executes less cycles than "
140 "the high nice thread, delta: %lld ns", delta);
141 } else {
142 tst_res(TPASS, "executes more cycles than "
143 "the high nice thread, delta: %lld ns", delta);
144 }
145
146 SAFE_PTHREAD_CANCEL(thread[0]);
147 SAFE_PTHREAD_CANCEL(thread[1]);
148 SAFE_PTHREAD_BARRIER_DESTROY(&barrier);
149 SAFE_PTHREAD_JOIN(thread[0], NULL);
150 SAFE_PTHREAD_JOIN(thread[1], NULL);
151 }
152
153 static struct tst_test test = {
154 .setup = setup,
155 .test_all = verify_nice,
156 .needs_root = 1,
157 .max_runtime = 3,
158 };
159