#include <sys/types.h>
#include <sys/resource.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <vm/vm_param.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define INCARNATIONS 32
static unsigned long size, original;
static int runtime, utime;
void
usage(void)
{
fprintf(stderr, "Usage: %s [-d delay] [-p pct] [-t runtime] "
"[-v]\n",
getprogname());
exit(1);
}
static unsigned long
usermem(void)
{
unsigned long mem;
size_t nlen = sizeof(mem);
if (sysctlbyname("hw.usermem", &mem, &nlen, NULL, 0) == -1)
err(1, "sysctlbyname() %s:%d", __FILE__, __LINE__);
#if defined(DEBUG)
printf("Total free user memory %lu Mb\n",
mem / 1024 / 1024);
#endif
return (mem);
}
static int64_t
swap(void)
{
struct xswdev xsw;
size_t mibsize, size;
int mib[16], n;
int64_t sz;
mibsize = sizeof mib / sizeof mib[0];
sz = 0;
if (sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)
err(1, "sysctlnametomib()");
for (n = 0; ; ++n) {
mib[mibsize] = n;
size = sizeof xsw;
if (sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1)
break;
if (xsw.xsw_version != XSWDEV_VERSION)
errx(1, "xswdev version mismatch");
sz = sz + xsw.xsw_nblks - xsw.xsw_used;
}
if (errno != ENOENT)
err(1, "sysctl()");
#if defined(DEBUG)
printf("Total free swap space %jd Mb\n",
sz * getpagesize() / 1024 / 1024);
#endif
return (sz * getpagesize());
}
static void
setup(void)
{
struct rlimit rlp;
size = size / INCARNATIONS;
original = size;
if (size == 0)
errx(1, "Argument too small");
if (getrlimit(RLIMIT_DATA, &rlp) < 0)
err(1,"getrlimit");
rlp.rlim_cur -= 1024 * 1024;
if (size > (unsigned long)rlp.rlim_cur)
size = rlp.rlim_cur;
#if 0
printf("setup: pid %d. Total %luMb\n",
getpid(), size / 1024 / 1024 * INCARNATIONS);
#endif
if (size == 0)
errx(1, "Argument too small");
return;
}
static int
test(void)
{
volatile char *c;
int page;
unsigned long i, j;
time_t start;
c = malloc(size);
while (c == NULL) {
size -= 1024 * 1024;
c = malloc(size);
}
if (size != original)
printf("Malloc size changed from %ld Mb to %ld Mb\n",
original / 1024 / 1024, size / 1024 / 1024);
page = getpagesize();
start = time(NULL);
while ((time(NULL) - start) < runtime) {
i = j = 0;
while (i < size) {
c[i] = 1;
i += page;
if ((time(NULL) - start) >= runtime)
break;
usleep(utime);
}
}
free((void *)c);
_exit(0);
}
int
main(int argc, char **argv)
{
int64_t s;
pid_t pids[INCARNATIONS];
unsigned long u;
int ch, i, pct, verbose;
s = swap();
u = usermem();
runtime = 120;
utime = 1000;
verbose = 0;
if (s == 0)
pct = 80;
else
pct = 101;
while ((ch = getopt(argc, argv, "d:p:t:v")) != -1) {
switch(ch) {
case 'd':
if (sscanf(optarg, "%d", &utime) != 1)
usage();
break;
case 'p':
if (sscanf(optarg, "%d", &pct) != 1)
usage();
break;
case 't':
if (sscanf(optarg, "%d", &runtime) != 1)
usage();
break;
case 'v':
verbose = 1;
break;
default:
usage();
}
}
if (s == 0 && pct > 80)
errx(1, "pct range with no swap is 0-80");
size = u / 100 * pct;
if (verbose == 1)
fprintf(stderr, "pct = %d, sleep = %d usec, size = %lumb\n",
pct, utime, size / 1024 / 1024);
setup();
for (i = 0; i < INCARNATIONS; i++)
if ((pids[i] = fork()) == 0)
test();
for (i = 0; i < INCARNATIONS; i++)
if (waitpid(pids[i], NULL, 0) != pids[i])
err(1, "paitpid(%d)", pids[i]);
return (0);
}