xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/nice/nice05.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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