xref: /aosp_15_r20/external/ltp/testcases/kernel/mem/mtest01/mtest01.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  *  Copyright (c) International Business Machines Corp., 2001
4*49cdfc7eSAndroid Build Coastguard Worker  *  Copyright (c) Linux Test Project., 2019
5*49cdfc7eSAndroid Build Coastguard Worker  *
6*49cdfc7eSAndroid Build Coastguard Worker  *  DESCRIPTION:
7*49cdfc7eSAndroid Build Coastguard Worker  *
8*49cdfc7eSAndroid Build Coastguard Worker  *  mtest01 mallocs memory <chunksize> at a time until malloc fails.
9*49cdfc7eSAndroid Build Coastguard Worker  *
10*49cdfc7eSAndroid Build Coastguard Worker  *  Parent process starts several child processes (each child process is
11*49cdfc7eSAndroid Build Coastguard Worker  *  tasked with allocating some amount of memory), it waits until all child
12*49cdfc7eSAndroid Build Coastguard Worker  *  processes send SIGRTMIN signal and resumes all children by sending the
13*49cdfc7eSAndroid Build Coastguard Worker  *  SIGCONT signal.
14*49cdfc7eSAndroid Build Coastguard Worker  *
15*49cdfc7eSAndroid Build Coastguard Worker  *  Child process allocates certain amount of memory and fills it with some
16*49cdfc7eSAndroid Build Coastguard Worker  *  data (the '-w' option) so the pages are actually allocated when the desired
17*49cdfc7eSAndroid Build Coastguard Worker  *  amount of memory is allocated then it sends SIGRTMIN signal to the parent
18*49cdfc7eSAndroid Build Coastguard Worker  *  process, it pauses itself by raise SIGSTOP until get parent SIGCONT signal
19*49cdfc7eSAndroid Build Coastguard Worker  *  to continue and exit.
20*49cdfc7eSAndroid Build Coastguard Worker  */
21*49cdfc7eSAndroid Build Coastguard Worker 
22*49cdfc7eSAndroid Build Coastguard Worker #include <sys/types.h>
23*49cdfc7eSAndroid Build Coastguard Worker #include <sys/sysinfo.h>
24*49cdfc7eSAndroid Build Coastguard Worker #include <sys/wait.h>
25*49cdfc7eSAndroid Build Coastguard Worker #include <limits.h>
26*49cdfc7eSAndroid Build Coastguard Worker #include <signal.h>
27*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
28*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
29*49cdfc7eSAndroid Build Coastguard Worker #include <unistd.h>
30*49cdfc7eSAndroid Build Coastguard Worker 
31*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/abisize.h"
32*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
33*49cdfc7eSAndroid Build Coastguard Worker 
34*49cdfc7eSAndroid Build Coastguard Worker #define FIVE_HUNDRED_MB         (500ULL*1024*1024)
35*49cdfc7eSAndroid Build Coastguard Worker 
36*49cdfc7eSAndroid Build Coastguard Worker #if defined(__s390__) || defined(__s390x__)
37*49cdfc7eSAndroid Build Coastguard Worker #define ALLOC_THRESHOLD		FIVE_HUNDRED_MB
38*49cdfc7eSAndroid Build Coastguard Worker #elif defined(TST_ABI32)
39*49cdfc7eSAndroid Build Coastguard Worker #define ALLOC_THRESHOLD		(2*FIVE_HUNDRED_MB)
40*49cdfc7eSAndroid Build Coastguard Worker #elif defined(TST_ABI64)
41*49cdfc7eSAndroid Build Coastguard Worker #define ALLOC_THRESHOLD		(6*FIVE_HUNDRED_MB)
42*49cdfc7eSAndroid Build Coastguard Worker #endif
43*49cdfc7eSAndroid Build Coastguard Worker 
44*49cdfc7eSAndroid Build Coastguard Worker static pid_t *pid_list;
45*49cdfc7eSAndroid Build Coastguard Worker static sig_atomic_t children_done;
46*49cdfc7eSAndroid Build Coastguard Worker static int max_pids;
47*49cdfc7eSAndroid Build Coastguard Worker static unsigned long long alloc_maxbytes;
48*49cdfc7eSAndroid Build Coastguard Worker 
49*49cdfc7eSAndroid Build Coastguard Worker static int chunksize = 1024*1024;
50*49cdfc7eSAndroid Build Coastguard Worker static int maxpercent = 20;
51*49cdfc7eSAndroid Build Coastguard Worker static long maxbytes = 0;
52*49cdfc7eSAndroid Build Coastguard Worker static char *dowrite;
53*49cdfc7eSAndroid Build Coastguard Worker static char *verbose;
54*49cdfc7eSAndroid Build Coastguard Worker 
55*49cdfc7eSAndroid Build Coastguard Worker static char *opt_chunksize, *opt_maxbytes, *opt_maxpercent;
56*49cdfc7eSAndroid Build Coastguard Worker 
parse_mtest_options(char * str_chunksize,int * chunksize,char * str_maxbytes,long * maxbytes,char * str_maxpercent,int * maxpercent)57*49cdfc7eSAndroid Build Coastguard Worker static void parse_mtest_options(char *str_chunksize, int *chunksize,
58*49cdfc7eSAndroid Build Coastguard Worker 		char *str_maxbytes, long *maxbytes,
59*49cdfc7eSAndroid Build Coastguard Worker 		char *str_maxpercent, int *maxpercent)
60*49cdfc7eSAndroid Build Coastguard Worker {
61*49cdfc7eSAndroid Build Coastguard Worker 	if (str_chunksize)
62*49cdfc7eSAndroid Build Coastguard Worker 		if (tst_parse_int(str_chunksize, chunksize, 1, INT_MAX))
63*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK, "Invalid chunksize '%s'", str_chunksize);
64*49cdfc7eSAndroid Build Coastguard Worker 
65*49cdfc7eSAndroid Build Coastguard Worker 	if (str_maxbytes) {
66*49cdfc7eSAndroid Build Coastguard Worker 		if (tst_parse_long(str_maxbytes, maxbytes, 1, LONG_MAX)) {
67*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK, "Invalid maxbytes '%s'", str_maxbytes);
68*49cdfc7eSAndroid Build Coastguard Worker 		} else if (str_maxpercent) {
69*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK, "ERROR: -b option cannot be used with -p "
70*49cdfc7eSAndroid Build Coastguard Worker 					"option at the same time");
71*49cdfc7eSAndroid Build Coastguard Worker 		}
72*49cdfc7eSAndroid Build Coastguard Worker 		alloc_maxbytes = (unsigned long long)maxbytes;
73*49cdfc7eSAndroid Build Coastguard Worker 	}
74*49cdfc7eSAndroid Build Coastguard Worker 
75*49cdfc7eSAndroid Build Coastguard Worker 	if (str_maxpercent) {
76*49cdfc7eSAndroid Build Coastguard Worker 		if (tst_parse_int(str_maxpercent, maxpercent, 1, 99)) {
77*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK, "Invalid maxpercent '%s'", str_maxpercent);
78*49cdfc7eSAndroid Build Coastguard Worker 		} else if (str_maxbytes) {
79*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK, "ERROR: -p option cannot be used with -b "
80*49cdfc7eSAndroid Build Coastguard Worker 					"option at the same time");
81*49cdfc7eSAndroid Build Coastguard Worker 		}
82*49cdfc7eSAndroid Build Coastguard Worker 	}
83*49cdfc7eSAndroid Build Coastguard Worker }
84*49cdfc7eSAndroid Build Coastguard Worker 
handler(int sig LTP_ATTRIBUTE_UNUSED)85*49cdfc7eSAndroid Build Coastguard Worker static void handler(int sig LTP_ATTRIBUTE_UNUSED)
86*49cdfc7eSAndroid Build Coastguard Worker {
87*49cdfc7eSAndroid Build Coastguard Worker         children_done++;
88*49cdfc7eSAndroid Build Coastguard Worker }
89*49cdfc7eSAndroid Build Coastguard Worker 
do_write_mem(char * mem,int chunksize)90*49cdfc7eSAndroid Build Coastguard Worker static void do_write_mem(char *mem, int chunksize)
91*49cdfc7eSAndroid Build Coastguard Worker {
92*49cdfc7eSAndroid Build Coastguard Worker 	int i, pagesz = getpagesize();
93*49cdfc7eSAndroid Build Coastguard Worker 
94*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < chunksize; i += pagesz)
95*49cdfc7eSAndroid Build Coastguard Worker 		*(mem + i) = 'a';
96*49cdfc7eSAndroid Build Coastguard Worker }
97*49cdfc7eSAndroid Build Coastguard Worker 
setup(void)98*49cdfc7eSAndroid Build Coastguard Worker static void setup(void)
99*49cdfc7eSAndroid Build Coastguard Worker {
100*49cdfc7eSAndroid Build Coastguard Worker 	struct sysinfo sstats;
101*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long long total_free;
102*49cdfc7eSAndroid Build Coastguard Worker 
103*49cdfc7eSAndroid Build Coastguard Worker 	struct sigaction act;
104*49cdfc7eSAndroid Build Coastguard Worker 	act.sa_handler = handler;
105*49cdfc7eSAndroid Build Coastguard Worker 	act.sa_flags = 0;
106*49cdfc7eSAndroid Build Coastguard Worker 	sigemptyset(&act.sa_mask);
107*49cdfc7eSAndroid Build Coastguard Worker 	sigaction(SIGRTMIN, &act, 0);
108*49cdfc7eSAndroid Build Coastguard Worker 
109*49cdfc7eSAndroid Build Coastguard Worker 	parse_mtest_options(opt_chunksize, &chunksize,
110*49cdfc7eSAndroid Build Coastguard Worker 			opt_maxbytes, &maxbytes,
111*49cdfc7eSAndroid Build Coastguard Worker 			opt_maxpercent, &maxpercent);
112*49cdfc7eSAndroid Build Coastguard Worker 	sysinfo(&sstats);
113*49cdfc7eSAndroid Build Coastguard Worker 	total_free = sstats.freeram;
114*49cdfc7eSAndroid Build Coastguard Worker 
115*49cdfc7eSAndroid Build Coastguard Worker 	max_pids = total_free * sstats.mem_unit
116*49cdfc7eSAndroid Build Coastguard Worker 		/ (unsigned long)ALLOC_THRESHOLD + 10;
117*49cdfc7eSAndroid Build Coastguard Worker 	pid_list = SAFE_MALLOC(max_pids * sizeof(pid_t));
118*49cdfc7eSAndroid Build Coastguard Worker 
119*49cdfc7eSAndroid Build Coastguard Worker 	if (!alloc_maxbytes) {
120*49cdfc7eSAndroid Build Coastguard Worker 		/* set alloc_maxbytes to the extra amount we want to allocate */
121*49cdfc7eSAndroid Build Coastguard Worker 		alloc_maxbytes = ((float)maxpercent / 100.00)
122*49cdfc7eSAndroid Build Coastguard Worker 			* (sstats.mem_unit * total_free);
123*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "Filling up %d%% of free ram which is %llu kbytes",
124*49cdfc7eSAndroid Build Coastguard Worker 			 maxpercent, alloc_maxbytes / 1024);
125*49cdfc7eSAndroid Build Coastguard Worker 	}
126*49cdfc7eSAndroid Build Coastguard Worker }
127*49cdfc7eSAndroid Build Coastguard Worker 
cleanup(void)128*49cdfc7eSAndroid Build Coastguard Worker static void cleanup(void)
129*49cdfc7eSAndroid Build Coastguard Worker {
130*49cdfc7eSAndroid Build Coastguard Worker 	if(pid_list)
131*49cdfc7eSAndroid Build Coastguard Worker 		free(pid_list);
132*49cdfc7eSAndroid Build Coastguard Worker }
133*49cdfc7eSAndroid Build Coastguard Worker 
child_loop_alloc(unsigned long long alloc_bytes)134*49cdfc7eSAndroid Build Coastguard Worker static void child_loop_alloc(unsigned long long alloc_bytes)
135*49cdfc7eSAndroid Build Coastguard Worker {
136*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long bytecount = 0;
137*49cdfc7eSAndroid Build Coastguard Worker 	char *mem;
138*49cdfc7eSAndroid Build Coastguard Worker 	int runtime_rem;
139*49cdfc7eSAndroid Build Coastguard Worker 
140*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "... child %d starting", getpid());
141*49cdfc7eSAndroid Build Coastguard Worker 
142*49cdfc7eSAndroid Build Coastguard Worker 	while (1) {
143*49cdfc7eSAndroid Build Coastguard Worker 		mem = SAFE_MALLOC(chunksize);
144*49cdfc7eSAndroid Build Coastguard Worker 		if (dowrite)
145*49cdfc7eSAndroid Build Coastguard Worker 			do_write_mem(mem, chunksize);
146*49cdfc7eSAndroid Build Coastguard Worker 
147*49cdfc7eSAndroid Build Coastguard Worker 		if (verbose)
148*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TINFO,
149*49cdfc7eSAndroid Build Coastguard Worker 				"child %d allocated %lu bytes chunksize is %d",
150*49cdfc7eSAndroid Build Coastguard Worker 				getpid(), bytecount, chunksize);
151*49cdfc7eSAndroid Build Coastguard Worker 		bytecount += chunksize;
152*49cdfc7eSAndroid Build Coastguard Worker 		if (bytecount >= alloc_bytes)
153*49cdfc7eSAndroid Build Coastguard Worker 			break;
154*49cdfc7eSAndroid Build Coastguard Worker 	}
155*49cdfc7eSAndroid Build Coastguard Worker 
156*49cdfc7eSAndroid Build Coastguard Worker 	runtime_rem = tst_remaining_runtime();
157*49cdfc7eSAndroid Build Coastguard Worker 
158*49cdfc7eSAndroid Build Coastguard Worker 	if (dowrite)
159*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "... [t=%d] %lu bytes allocated and used in child %d",
160*49cdfc7eSAndroid Build Coastguard Worker 				runtime_rem, bytecount, getpid());
161*49cdfc7eSAndroid Build Coastguard Worker 	else
162*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "... [t=%d] %lu bytes allocated only in child %d",
163*49cdfc7eSAndroid Build Coastguard Worker 				runtime_rem, bytecount, getpid());
164*49cdfc7eSAndroid Build Coastguard Worker 
165*49cdfc7eSAndroid Build Coastguard Worker 	kill(getppid(), SIGRTMIN);
166*49cdfc7eSAndroid Build Coastguard Worker 	raise(SIGSTOP);
167*49cdfc7eSAndroid Build Coastguard Worker 	exit(0);
168*49cdfc7eSAndroid Build Coastguard Worker }
169*49cdfc7eSAndroid Build Coastguard Worker 
mem_test(void)170*49cdfc7eSAndroid Build Coastguard Worker static void mem_test(void)
171*49cdfc7eSAndroid Build Coastguard Worker {
172*49cdfc7eSAndroid Build Coastguard Worker 	pid_t pid;
173*49cdfc7eSAndroid Build Coastguard Worker 	int i = 0, pid_cntr = 0;
174*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long long alloc_bytes = alloc_maxbytes;
175*49cdfc7eSAndroid Build Coastguard Worker 	const char *write_msg = "";
176*49cdfc7eSAndroid Build Coastguard Worker 
177*49cdfc7eSAndroid Build Coastguard Worker 	if (dowrite)
178*49cdfc7eSAndroid Build Coastguard Worker 		write_msg = "(and written to) ";
179*49cdfc7eSAndroid Build Coastguard Worker 
180*49cdfc7eSAndroid Build Coastguard Worker 	/* to make mtest01 support -i N */
181*49cdfc7eSAndroid Build Coastguard Worker 	children_done = 0;
182*49cdfc7eSAndroid Build Coastguard Worker 
183*49cdfc7eSAndroid Build Coastguard Worker 	do {
184*49cdfc7eSAndroid Build Coastguard Worker 		pid = SAFE_FORK();
185*49cdfc7eSAndroid Build Coastguard Worker 		if (pid == 0) {
186*49cdfc7eSAndroid Build Coastguard Worker 			alloc_bytes = MIN(ALLOC_THRESHOLD, alloc_bytes);
187*49cdfc7eSAndroid Build Coastguard Worker 			child_loop_alloc(alloc_bytes);
188*49cdfc7eSAndroid Build Coastguard Worker 		}
189*49cdfc7eSAndroid Build Coastguard Worker 
190*49cdfc7eSAndroid Build Coastguard Worker 		pid_list[pid_cntr++] = pid;
191*49cdfc7eSAndroid Build Coastguard Worker 
192*49cdfc7eSAndroid Build Coastguard Worker 		if (alloc_bytes <= ALLOC_THRESHOLD)
193*49cdfc7eSAndroid Build Coastguard Worker 			break;
194*49cdfc7eSAndroid Build Coastguard Worker 
195*49cdfc7eSAndroid Build Coastguard Worker 		alloc_bytes -= ALLOC_THRESHOLD;
196*49cdfc7eSAndroid Build Coastguard Worker 	} while (pid_cntr < max_pids);
197*49cdfc7eSAndroid Build Coastguard Worker 
198*49cdfc7eSAndroid Build Coastguard Worker 	/* wait in the loop for all children finish allocating */
199*49cdfc7eSAndroid Build Coastguard Worker 	while (children_done < pid_cntr) {
200*49cdfc7eSAndroid Build Coastguard Worker 		if (!tst_remaining_runtime()) {
201*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TWARN,
202*49cdfc7eSAndroid Build Coastguard Worker 				"the remaininig time is not enough for testing");
203*49cdfc7eSAndroid Build Coastguard Worker 			break;
204*49cdfc7eSAndroid Build Coastguard Worker 		}
205*49cdfc7eSAndroid Build Coastguard Worker 
206*49cdfc7eSAndroid Build Coastguard Worker 		usleep(100000);
207*49cdfc7eSAndroid Build Coastguard Worker 	}
208*49cdfc7eSAndroid Build Coastguard Worker 
209*49cdfc7eSAndroid Build Coastguard Worker 	if (children_done < pid_cntr) {
210*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "kbytes allocated %sless than expected %llu",
211*49cdfc7eSAndroid Build Coastguard Worker 				write_msg, alloc_maxbytes / 1024);
212*49cdfc7eSAndroid Build Coastguard Worker 
213*49cdfc7eSAndroid Build Coastguard Worker 		for (i = 0; i < pid_cntr; i++)
214*49cdfc7eSAndroid Build Coastguard Worker 			kill(pid_list[i], SIGKILL);
215*49cdfc7eSAndroid Build Coastguard Worker 
216*49cdfc7eSAndroid Build Coastguard Worker 		return;
217*49cdfc7eSAndroid Build Coastguard Worker 	}
218*49cdfc7eSAndroid Build Coastguard Worker 
219*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TPASS, "%llu kbytes allocated %s",
220*49cdfc7eSAndroid Build Coastguard Worker 			alloc_maxbytes / 1024, write_msg);
221*49cdfc7eSAndroid Build Coastguard Worker 
222*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < pid_cntr; i++) {
223*49cdfc7eSAndroid Build Coastguard Worker 		TST_PROCESS_STATE_WAIT(pid_list[i], 'T', 0);
224*49cdfc7eSAndroid Build Coastguard Worker 		kill(pid_list[i], SIGCONT);
225*49cdfc7eSAndroid Build Coastguard Worker 	}
226*49cdfc7eSAndroid Build Coastguard Worker }
227*49cdfc7eSAndroid Build Coastguard Worker 
228*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
229*49cdfc7eSAndroid Build Coastguard Worker 	.forks_child = 1,
230*49cdfc7eSAndroid Build Coastguard Worker 	.options = (struct tst_option[]) {
231*49cdfc7eSAndroid Build Coastguard Worker 		{"c:", &opt_chunksize,	"Size of chunk in bytes to malloc on each pass"},
232*49cdfc7eSAndroid Build Coastguard Worker 		{"b:", &opt_maxbytes,	"Maximum number of bytes to allocate before stopping"},
233*49cdfc7eSAndroid Build Coastguard Worker 		{"p:", &opt_maxpercent, "Percent of total memory used at which the program stops"},
234*49cdfc7eSAndroid Build Coastguard Worker 		{"w",  &dowrite,   	"Write to the memory after allocating"},
235*49cdfc7eSAndroid Build Coastguard Worker 		{"v",  &verbose,     	"Verbose"},
236*49cdfc7eSAndroid Build Coastguard Worker 		{}
237*49cdfc7eSAndroid Build Coastguard Worker 	},
238*49cdfc7eSAndroid Build Coastguard Worker 	.max_runtime = 300,
239*49cdfc7eSAndroid Build Coastguard Worker 	.setup = setup,
240*49cdfc7eSAndroid Build Coastguard Worker 	.cleanup = cleanup,
241*49cdfc7eSAndroid Build Coastguard Worker 	.test_all = mem_test,
242*49cdfc7eSAndroid Build Coastguard Worker };
243