| /* |
| * |
| * Copyright (c) International Business Machines Corp., 2001 |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| * the GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| /* |
| * FILE : mtest01.c |
| * DESCRIPTION : mallocs memory <chunksize> at a time until malloc fails. |
| * HISTORY: |
| * 04/10/2001 Paul Larson (plars@us.ibm.com) |
| * written |
| * 11/09/2001 Manoj Iyer (manjo@austin.ibm.com) |
| * Modified. |
| * - Removed compile warnings. |
| * - Added header file #include <unistd.h> definition for getopt() |
| * 05/13/2003 Robbie Williamson (robbiew@us.ibm.com) |
| * Modified. |
| * - Rewrote the test to be able to execute on large memory machines. |
| * |
| */ |
| |
| #include <sys/types.h> |
| #include <sys/sysinfo.h> |
| #include <sys/wait.h> |
| #include <limits.h> |
| #include <signal.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| |
| #include "test.h" |
| |
| #define FIVE_HUNDRED_MB (unsigned long long)(500*1024*1024) |
| #define ONE_GB (unsigned long long)(1024*1024*1024) |
| #define THREE_GB (unsigned long long)(3*ONE_GB) |
| |
| char *TCID = "mtest01"; |
| int TST_TOTAL = 1; |
| static sig_atomic_t pid_count; |
| static sig_atomic_t sigchld_count; |
| static pid_t *pid_list; |
| |
| static void handler(int signo) |
| { |
| if (signo == SIGCHLD) |
| sigchld_count++; |
| pid_count++; |
| } |
| |
| static void cleanup(void) |
| { |
| int i = 0; |
| |
| while (pid_list[i] > 0) { |
| kill(pid_list[i], SIGKILL); |
| i++; |
| } |
| |
| free(pid_list); |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| int c; |
| char *mem; |
| float percent; |
| unsigned int maxpercent = 0, dowrite = 0, verbose = 0, j; |
| unsigned long bytecount, alloc_bytes, max_pids; |
| unsigned long long original_maxbytes, maxbytes = 0; |
| unsigned long long pre_mem = 0, post_mem = 0; |
| unsigned long long total_ram, total_free, D, C; |
| int chunksize = 1024 * 1024; /* one meg at a time by default */ |
| struct sysinfo sstats; |
| int i, pid_cntr; |
| pid_t pid; |
| struct sigaction act; |
| |
| act.sa_handler = handler; |
| act.sa_flags = 0; |
| sigemptyset(&act.sa_mask); |
| sigaction(SIGRTMIN, &act, 0); |
| sigaction(SIGCHLD, &act, 0); |
| |
| while ((c = getopt(argc, argv, "c:b:p:wvh")) != -1) { |
| switch (c) { |
| case 'c': |
| chunksize = atoi(optarg); |
| break; |
| case 'b': |
| if (maxpercent != 0) |
| tst_brkm(TBROK, NULL, |
| "ERROR: -b option cannot be used with -p " |
| "option at the same time"); |
| maxbytes = atoll(optarg); |
| break; |
| case 'p': |
| if (maxbytes != 0) |
| tst_brkm(TBROK, NULL, |
| "ERROR: -p option cannot be used with -b " |
| "option at the same time"); |
| maxpercent = atoi(optarg); |
| if (maxpercent <= 0) |
| tst_brkm(TBROK, NULL, |
| "ERROR: -p option requires number greater " |
| "than 0"); |
| if (maxpercent > 99) |
| tst_brkm(TBROK, NULL, |
| "ERROR: -p option cannot be greater than " |
| "99"); |
| break; |
| case 'w': |
| dowrite = 1; |
| break; |
| case 'v': |
| verbose = 1; |
| break; |
| case 'h': |
| default: |
| printf |
| ("usage: %s [-c <bytes>] [-b <bytes>|-p <percent>] [-v]\n", |
| argv[0]); |
| printf |
| ("\t-c <num>\tsize of chunk in bytes to malloc on each pass\n"); |
| printf |
| ("\t-b <bytes>\tmaximum number of bytes to allocate before stopping\n"); |
| printf |
| ("\t-p <bytes>\tpercent of total memory used at which the program stops\n"); |
| printf |
| ("\t-w\t\twrite to the memory after allocating\n"); |
| printf("\t-v\t\tverbose\n"); |
| printf("\t-h\t\tdisplay usage\n"); |
| exit(1); |
| } |
| } |
| |
| sysinfo(&sstats); |
| total_ram = sstats.totalram + sstats.totalswap; |
| total_free = sstats.freeram + sstats.freeswap; |
| /* Total Free Pre-Test RAM */ |
| pre_mem = sstats.mem_unit * total_free; |
| max_pids = total_ram * sstats.mem_unit |
| / (unsigned long)FIVE_HUNDRED_MB + 10; |
| |
| if ((pid_list = malloc(max_pids * sizeof(pid_t))) == NULL) |
| tst_brkm(TBROK | TERRNO, NULL, "malloc failed."); |
| memset(pid_list, 0, max_pids * sizeof(pid_t)); |
| |
| /* Currently used memory */ |
| C = sstats.mem_unit * (total_ram - total_free); |
| tst_resm(TINFO, "Total memory already used on system = %llu kbytes", |
| C / 1024); |
| |
| if (maxpercent) { |
| percent = (float)maxpercent / 100.00; |
| |
| /* Desired memory needed to reach maxpercent */ |
| D = percent * (sstats.mem_unit * total_ram); |
| tst_resm(TINFO, |
| "Total memory used needed to reach maximum = %llu kbytes", |
| D / 1024); |
| |
| /* Are we already using more than maxpercent? */ |
| if (C > D) { |
| tst_resm(TFAIL, |
| "More memory than the maximum amount you specified " |
| " is already being used"); |
| free(pid_list); |
| tst_exit(); |
| } |
| |
| /* set maxbytes to the extra amount we want to allocate */ |
| maxbytes = D - C; |
| tst_resm(TINFO, "Filling up %d%% of ram which is %llu kbytes", |
| maxpercent, maxbytes / 1024); |
| } |
| original_maxbytes = maxbytes; |
| i = 0; |
| pid_cntr = 0; |
| pid = fork(); |
| if (pid < 0) |
| tst_brkm(TBROK | TERRNO, cleanup, "fork failed"); |
| if (pid != 0) { |
| pid_cntr++; |
| pid_list[i] = pid; |
| } |
| |
| #if defined (_s390_) /* s390's 31bit addressing requires smaller chunks */ |
| while (pid != 0 && maxbytes > FIVE_HUNDRED_MB) { |
| i++; |
| if (i >= max_pids) |
| tst_brkm(TBROK, cleanup, "max_pids needs to be increased"); |
| maxbytes -= FIVE_HUNDRED_MB; |
| pid = fork(); |
| if (pid < 0) |
| tst_brkm(TBROK | TERRNO, cleanup, "fork failed"); |
| if (pid != 0) { |
| pid_cntr++; |
| pid_list[i] = pid; |
| } |
| } |
| if (maxbytes > FIVE_HUNDRED_MB) |
| alloc_bytes = FIVE_HUNDRED_MB; |
| else |
| alloc_bytes = (unsigned long)maxbytes; |
| |
| #elif __WORDSIZE == 32 |
| while (pid != 0 && maxbytes > ONE_GB) { |
| i++; |
| if (i >= max_pids) |
| tst_brkm(TBROK, cleanup, "max_pids needs to be increased"); |
| maxbytes -= ONE_GB; |
| pid = fork(); |
| if (pid < 0) |
| tst_brkm(TBROK | TERRNO, cleanup, "fork failed"); |
| if (pid != 0) { |
| pid_cntr++; |
| pid_list[i] = pid; |
| } |
| } |
| if (maxbytes > ONE_GB) |
| alloc_bytes = ONE_GB; |
| else |
| alloc_bytes = (unsigned long)maxbytes; |
| |
| #elif __WORDSIZE == 64 |
| while (pid != 0 && maxbytes > THREE_GB) { |
| i++; |
| if (i >= max_pids) |
| tst_brkm(TBROK, cleanup, "max_pids needs to be increased"); |
| maxbytes -= THREE_GB; |
| pid = fork(); |
| if (pid < 0) |
| tst_brkm(TBROK | TERRNO, cleanup, "fork failed"); |
| if (pid != 0) { |
| pid_cntr++; |
| pid_list[i] = pid; |
| } |
| } |
| alloc_bytes = MIN(THREE_GB, maxbytes); |
| #endif |
| |
| if (pid == 0) { |
| bytecount = chunksize; |
| while (1) { |
| if ((mem = malloc(chunksize)) == NULL) { |
| tst_resm(TBROK | TERRNO, |
| "stopped at %lu bytes", bytecount); |
| free(pid_list); |
| tst_exit(); |
| } |
| if (dowrite) |
| for (j = 0; j < chunksize; j++) |
| *(mem + j) = 'a'; |
| if (verbose) |
| tst_resm(TINFO, |
| "allocated %lu bytes chunksize is %d", |
| bytecount, chunksize); |
| bytecount += chunksize; |
| if (alloc_bytes && bytecount >= alloc_bytes) |
| break; |
| } |
| if (dowrite) |
| tst_resm(TINFO, "... %lu bytes allocated and used.", |
| bytecount); |
| else |
| tst_resm(TINFO, "... %lu bytes allocated only.", |
| bytecount); |
| kill(getppid(), SIGRTMIN); |
| while (1) |
| sleep(1); |
| } else { |
| sysinfo(&sstats); |
| |
| if (dowrite) { |
| /* Total Free Post-Test RAM */ |
| post_mem = |
| (unsigned long long)sstats.mem_unit * |
| sstats.freeram; |
| post_mem = |
| post_mem + |
| (unsigned long long)sstats.mem_unit * |
| sstats.freeswap; |
| |
| while ((((unsigned long long)pre_mem - post_mem) < |
| (unsigned long long)original_maxbytes) && |
| pid_count < pid_cntr && !sigchld_count) { |
| sleep(1); |
| sysinfo(&sstats); |
| post_mem = |
| (unsigned long long)sstats.mem_unit * |
| sstats.freeram; |
| post_mem = |
| post_mem + |
| (unsigned long long)sstats.mem_unit * |
| sstats.freeswap; |
| } |
| } |
| |
| if (sigchld_count) { |
| tst_resm(TFAIL, "child process exited unexpectedly"); |
| } else if (dowrite) { |
| tst_resm(TPASS, "%llu kbytes allocated and used.", |
| original_maxbytes / 1024); |
| } else { |
| tst_resm(TPASS, "%llu kbytes allocated only.", |
| original_maxbytes / 1024); |
| } |
| |
| } |
| cleanup(); |
| tst_exit(); |
| } |