xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/timers/posix_timers.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker <fweisbec@redhat.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Selftests for a few posix timers interface.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Kernel loop code stolen from Steven Rostedt <srostedt@redhat.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <sys/time.h>
11*4882a593Smuzhiyun #include <stdio.h>
12*4882a593Smuzhiyun #include <signal.h>
13*4882a593Smuzhiyun #include <unistd.h>
14*4882a593Smuzhiyun #include <time.h>
15*4882a593Smuzhiyun #include <pthread.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include "../kselftest.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define DELAY 2
20*4882a593Smuzhiyun #define USECS_PER_SEC 1000000
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun static volatile int done;
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /* Busy loop in userspace to elapse ITIMER_VIRTUAL */
user_loop(void)25*4882a593Smuzhiyun static void user_loop(void)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	while (!done);
28*4882a593Smuzhiyun }
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /*
31*4882a593Smuzhiyun  * Try to spend as much time as possible in kernelspace
32*4882a593Smuzhiyun  * to elapse ITIMER_PROF.
33*4882a593Smuzhiyun  */
kernel_loop(void)34*4882a593Smuzhiyun static void kernel_loop(void)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	void *addr = sbrk(0);
37*4882a593Smuzhiyun 	int err = 0;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	while (!done && !err) {
40*4882a593Smuzhiyun 		err = brk(addr + 4096);
41*4882a593Smuzhiyun 		err |= brk(addr);
42*4882a593Smuzhiyun 	}
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun /*
46*4882a593Smuzhiyun  * Sleep until ITIMER_REAL expiration.
47*4882a593Smuzhiyun  */
idle_loop(void)48*4882a593Smuzhiyun static void idle_loop(void)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	pause();
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
sig_handler(int nr)53*4882a593Smuzhiyun static void sig_handler(int nr)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	done = 1;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun  * Check the expected timer expiration matches the GTOD elapsed delta since
60*4882a593Smuzhiyun  * we armed the timer. Keep a 0.5 sec error margin due to various jitter.
61*4882a593Smuzhiyun  */
check_diff(struct timeval start,struct timeval end)62*4882a593Smuzhiyun static int check_diff(struct timeval start, struct timeval end)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	long long diff;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	diff = end.tv_usec - start.tv_usec;
67*4882a593Smuzhiyun 	diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) {
70*4882a593Smuzhiyun 		printf("Diff too high: %lld..", diff);
71*4882a593Smuzhiyun 		return -1;
72*4882a593Smuzhiyun 	}
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	return 0;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
check_itimer(int which)77*4882a593Smuzhiyun static int check_itimer(int which)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	int err;
80*4882a593Smuzhiyun 	struct timeval start, end;
81*4882a593Smuzhiyun 	struct itimerval val = {
82*4882a593Smuzhiyun 		.it_value.tv_sec = DELAY,
83*4882a593Smuzhiyun 	};
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	printf("Check itimer ");
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	if (which == ITIMER_VIRTUAL)
88*4882a593Smuzhiyun 		printf("virtual... ");
89*4882a593Smuzhiyun 	else if (which == ITIMER_PROF)
90*4882a593Smuzhiyun 		printf("prof... ");
91*4882a593Smuzhiyun 	else if (which == ITIMER_REAL)
92*4882a593Smuzhiyun 		printf("real... ");
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	fflush(stdout);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	done = 0;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	if (which == ITIMER_VIRTUAL)
99*4882a593Smuzhiyun 		signal(SIGVTALRM, sig_handler);
100*4882a593Smuzhiyun 	else if (which == ITIMER_PROF)
101*4882a593Smuzhiyun 		signal(SIGPROF, sig_handler);
102*4882a593Smuzhiyun 	else if (which == ITIMER_REAL)
103*4882a593Smuzhiyun 		signal(SIGALRM, sig_handler);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	err = gettimeofday(&start, NULL);
106*4882a593Smuzhiyun 	if (err < 0) {
107*4882a593Smuzhiyun 		perror("Can't call gettimeofday()\n");
108*4882a593Smuzhiyun 		return -1;
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	err = setitimer(which, &val, NULL);
112*4882a593Smuzhiyun 	if (err < 0) {
113*4882a593Smuzhiyun 		perror("Can't set timer\n");
114*4882a593Smuzhiyun 		return -1;
115*4882a593Smuzhiyun 	}
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	if (which == ITIMER_VIRTUAL)
118*4882a593Smuzhiyun 		user_loop();
119*4882a593Smuzhiyun 	else if (which == ITIMER_PROF)
120*4882a593Smuzhiyun 		kernel_loop();
121*4882a593Smuzhiyun 	else if (which == ITIMER_REAL)
122*4882a593Smuzhiyun 		idle_loop();
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	err = gettimeofday(&end, NULL);
125*4882a593Smuzhiyun 	if (err < 0) {
126*4882a593Smuzhiyun 		perror("Can't call gettimeofday()\n");
127*4882a593Smuzhiyun 		return -1;
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (!check_diff(start, end))
131*4882a593Smuzhiyun 		printf("[OK]\n");
132*4882a593Smuzhiyun 	else
133*4882a593Smuzhiyun 		printf("[FAIL]\n");
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	return 0;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
check_timer_create(int which)138*4882a593Smuzhiyun static int check_timer_create(int which)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	int err;
141*4882a593Smuzhiyun 	timer_t id;
142*4882a593Smuzhiyun 	struct timeval start, end;
143*4882a593Smuzhiyun 	struct itimerspec val = {
144*4882a593Smuzhiyun 		.it_value.tv_sec = DELAY,
145*4882a593Smuzhiyun 	};
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	printf("Check timer_create() ");
148*4882a593Smuzhiyun 	if (which == CLOCK_THREAD_CPUTIME_ID) {
149*4882a593Smuzhiyun 		printf("per thread... ");
150*4882a593Smuzhiyun 	} else if (which == CLOCK_PROCESS_CPUTIME_ID) {
151*4882a593Smuzhiyun 		printf("per process... ");
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 	fflush(stdout);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	done = 0;
156*4882a593Smuzhiyun 	err = timer_create(which, NULL, &id);
157*4882a593Smuzhiyun 	if (err < 0) {
158*4882a593Smuzhiyun 		perror("Can't create timer\n");
159*4882a593Smuzhiyun 		return -1;
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun 	signal(SIGALRM, sig_handler);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	err = gettimeofday(&start, NULL);
164*4882a593Smuzhiyun 	if (err < 0) {
165*4882a593Smuzhiyun 		perror("Can't call gettimeofday()\n");
166*4882a593Smuzhiyun 		return -1;
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	err = timer_settime(id, 0, &val, NULL);
170*4882a593Smuzhiyun 	if (err < 0) {
171*4882a593Smuzhiyun 		perror("Can't set timer\n");
172*4882a593Smuzhiyun 		return -1;
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	user_loop();
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	err = gettimeofday(&end, NULL);
178*4882a593Smuzhiyun 	if (err < 0) {
179*4882a593Smuzhiyun 		perror("Can't call gettimeofday()\n");
180*4882a593Smuzhiyun 		return -1;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	if (!check_diff(start, end))
184*4882a593Smuzhiyun 		printf("[OK]\n");
185*4882a593Smuzhiyun 	else
186*4882a593Smuzhiyun 		printf("[FAIL]\n");
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	return 0;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun 
main(int argc,char ** argv)191*4882a593Smuzhiyun int main(int argc, char **argv)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun 	printf("Testing posix timers. False negative may happen on CPU execution \n");
194*4882a593Smuzhiyun 	printf("based timers if other threads run on the CPU...\n");
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (check_itimer(ITIMER_VIRTUAL) < 0)
197*4882a593Smuzhiyun 		return ksft_exit_fail();
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (check_itimer(ITIMER_PROF) < 0)
200*4882a593Smuzhiyun 		return ksft_exit_fail();
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	if (check_itimer(ITIMER_REAL) < 0)
203*4882a593Smuzhiyun 		return ksft_exit_fail();
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0)
206*4882a593Smuzhiyun 		return ksft_exit_fail();
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	/*
209*4882a593Smuzhiyun 	 * It's unfortunately hard to reliably test a timer expiration
210*4882a593Smuzhiyun 	 * on parallel multithread cputime. We could arm it to expire
211*4882a593Smuzhiyun 	 * on DELAY * nr_threads, with nr_threads busy looping, then wait
212*4882a593Smuzhiyun 	 * the normal DELAY since the time is elapsing nr_threads faster.
213*4882a593Smuzhiyun 	 * But for that we need to ensure we have real physical free CPUs
214*4882a593Smuzhiyun 	 * to ensure true parallelism. So test only one thread until we
215*4882a593Smuzhiyun 	 * find a better solution.
216*4882a593Smuzhiyun 	 */
217*4882a593Smuzhiyun 	if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
218*4882a593Smuzhiyun 		return ksft_exit_fail();
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	return ksft_exit_pass();
221*4882a593Smuzhiyun }
222