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