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