blob: 947a5aafcfef8eb0cce8a8d76bbc3e4316294f8a [file] [log] [blame]
/*
* Allocate and dirty memory.
*
* Usage: usemem size[k|m|g|t]
*
* gcc -lpthread -O -g -Wall usemem.c -o usemem
*
* Copyright (C) Andrew Morton <akpm@linux-foundation.org>
* Copyright (C) 2010-2015 Intel Corporation.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/sem.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/syscall.h>
#include <poll.h>
#include <sched.h>
#include <time.h>
#include "usemem_mincore.h"
#include "usemem_hugepages.h"
#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1))
#define HUGE_PAGE_SIZE (2UL * 1024 * 1024)
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
#define max(x, y) ({ \
typeof(x) _max1 = (x); \
typeof(y) _max2 = (y); \
(void) (&_max1 == &_max2); \
_max1 > _max2 ? _max1 : _max2; })
/* used for remapping the allocated size in remap() */
#define SCALE_FACTOR 10
#define PAGE_SHIFT 12
#define PFN_OF(addr) ((addr) >> PAGE_SHIFT)
#define MAX_POINTERS 32
#ifndef MAP_HUGE_SHIFT
#define MAP_HUGE_SHIFT 26
#endif
#ifndef MAP_HUGE_2MB
#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT)
#endif
char *ourname;
int pagesize;
unsigned long done_bytes = 0;
unsigned long opt_bytes = 0;
unsigned long unit = 0;
unsigned long step = 0;
unsigned long *prealloc;
unsigned long *buffer;
int sleep_secs = 0;
time_t runtime_secs = 0;
__thread struct timeval start_time;
__thread int started = 0;
int reps = 1;
int do_mlock = 0;
int do_getchar = 0;
int opt_randomise = 0;
int opt_readonly;
int opt_openrw;
int opt_malloc;
int opt_detach;
int opt_advise = 0;
int opt_shm = 0;
int opt_remap = 0;
int opt_mincore = 0;
int opt_mincore_hugepages = 0;
int opt_write_signal_read = 0;
int opt_sync_rw = 0;
int opt_sync_free = 0;
int opt_bind_interval = 0;
unsigned long opt_delay = 0;
int sem_id = -1;
int nr_task;
int nr_thread;
int nr_cpu;
int quiet = 0;
int msync_mode;
char *filename = "/dev/zero";
char *pid_filename;
int map_shared = MAP_PRIVATE;
int map_populate;
int map_anonymous;
int map_hugetlb;
off_t map_offset;
int fd;
int start_ready_fds[2];
int start_wake_fds[2];
int free_ready_fds[2];
int free_wake_fds[2];
void usage(int ok)
{
fprintf(stderr,
"Usage: %s [options] size[k|m|g|t]\n"
" -n|--nproc N do job in N processes\n"
" -t|--thread M do job in M threads\n"
" -b|--bind N bind tasks with CPU number internal as N\n"
" -a|--malloc obtain memory from malloc()\n"
" -f|--file FILE mmap FILE, default /dev/zero\n"
" -B|--offset bytes mmap offset, default 0\n"
" -F|--prefault prefault mmap with MAP_POPULATE\n"
" -P|--prealloc allocate memory before fork\n"
" -u|--unit SIZE allocate memory in SIZE chunks\n"
" -j|--step SIZE step size in the read/write loop\n"
" -r|--repeat N repeat read/write N times\n"
" -o|--readonly readonly access\n"
" -w|--open-rw open() and mmap() file in RW mode\n"
" -R|--random random access pattern\n"
" -M|--mlock mlock() the memory\n"
" -S|--msync msync(MS_SYNC) the memory\n"
" -A|--msync-async msync(MS_ASYNC) the memory\n"
" -d|--detach detach before go sleeping\n"
" -s|--sleep SEC sleep SEC seconds when done\n"
" -T|--runtime SEC terminate after SEC seconds\n"
" -p|--pid-file FILE store detached pid to FILE\n"
" -g|--getchar wait for <enter> before quitting\n"
" -q|--quiet operate quietly\n"
" -L|--lock Lock a shared memory using sys V IPC\n"
" -D|--advise advise file access pattern to kernel\n"
" -E|--remap remap file virtual memory\n"
" -N|--mincore get information about pages in memory\n"
" -H|--mincore-hgpg get information abt hugepages in memory\n"
" -W|--write-signal-read do write first, then wait for signal to resume and do read\n"
" -y|--sync-rw sync between tasks after allocate memory\n"
" -x|--sync-free sync between tasks before free memory\n"
" -e|--delay delay for each page in ns\n"
" -O|--anonymous mmap with MAP_ANONYMOUS\n"
" -U|--hugetlb allocate hugetlbfs page\n"
" -h|--help show this message\n"
, ourname);
exit(ok);
}
static const struct option opts[] = {
{ "malloc" , 0, NULL, 'a' },
{ "unit" , 1, NULL, 'u' },
{ "step" , 1, NULL, 'j' },
{ "mlock" , 0, NULL, 'M' },
{ "readonly" , 0, NULL, 'o' },
{ "open-rw" , 0, NULL, 'w' },
{ "quiet" , 0, NULL, 'q' },
{ "random" , 0, NULL, 'R' },
{ "msync" , 0, NULL, 'S' },
{ "msync-async" , 0, NULL, 'A' },
{ "nproc" , 1, NULL, 'n' },
{ "thread" , 1, NULL, 't' },
{ "bind" , 1, NULL, 'b' },
{ "prealloc" , 0, NULL, 'P' },
{ "prefault" , 0, NULL, 'F' },
{ "repeat" , 1, NULL, 'r' },
{ "file" , 1, NULL, 'f' },
{ "offset" , 1, NULL, 'B' },
{ "pid-file" , 1, NULL, 'p' },
{ "detach" , 0, NULL, 'd' },
{ "sleep" , 1, NULL, 's' },
{ "runtime" , 1, NULL, 'T' },
{ "getchar" , 0, NULL, 'g' },
{ "Lock" , 0, NULL, 'L' },
{ "advice" , 0, NULL, 'D' },
{ "remap" , 0, NULL, 'E' },
{ "mncr_hgpgs" , 0, NULL, 'H' },
{ "sync-rw" , 0, NULL, 'y' },
{ "delay" , 1, NULL, 'e' },
{ "help" , 0, NULL, 'h' },
{ NULL , 0, NULL, 0 }
};
/* print memory lock/unlock menu */
void print_menu() {
printf("**********************************************************\n");
printf("* *\n");
printf("* Enter an option *\n");
printf("**********************************************************\n");
printf("* *\n");
printf("* a ----> automate *\n");
printf("* l ----> locking *\n");
printf("* r ----> remapping *\n");
printf("* u ----> unlocking *\n");
printf("* q ----> quit *\n");
printf("* *\n");
printf("* *\n");
printf("**********************************************************\n\n\n");
printf("your option: ");
}
/**
* memparse - parse a string with mem suffixes into a number
* @ptr: Where parse begins
* @retptr: (output) Optional pointer to next char after parse completes
*
* Parses a string into a number. The number stored at @ptr is
* potentially suffixed with %K (for kilobytes, or 1024 bytes),
* %M (for megabytes, or 1048576 bytes), or %G (for gigabytes, or
* 1073741824). If the number is suffixed with K, M, or G, then
* the return value is the number multiplied by one kilobyte, one
* megabyte, or one gigabyte, respectively.
*/
unsigned long long memparse(const char *ptr, char **retptr)
{
char *endptr; /* local pointer to end of parsed string */
unsigned long long ret = strtoull(ptr, &endptr, 0);
switch (*endptr) {
case 'T':
case 't':
ret <<= 10;
case 'G':
case 'g':
ret <<= 10;
case 'M':
case 'm':
ret <<= 10;
case 'K':
case 'k':
ret <<= 10;
endptr++;
default:
break;
}
if (retptr)
*retptr = endptr;
return ret;
}
unsigned long time_parse(const char *ptr)
{
char *endptr;
unsigned long nsec = strtoul(ptr, &endptr, 0);
switch (*endptr) {
case 'm':
nsec *= 1000;
case 'u':
nsec *= 1000;
default:
break;
}
return nsec;
}
static inline void os_random_seed(unsigned long seed, struct drand48_data *rs)
{
srand48_r(seed, rs);
}
static inline long os_random_long(unsigned long max, struct drand48_data *rs)
{
long val;
lrand48_r(rs, &val);
return (unsigned long)((double)max * val / (RAND_MAX + 1.0));
}
/*
* semaphore get/put wrapper
*/
int down(int sem_id)
{
struct sembuf buf = {
.sem_num = 0,
.sem_op = -1,
.sem_flg = SEM_UNDO,
};
return semop(sem_id, &buf, 1);
}
int up(int sem_id)
{
struct sembuf buf = {
.sem_num = 0,
.sem_op = 1,
.sem_flg = SEM_UNDO,
};
return semop(sem_id, &buf, 1);
}
void update_pid_file(pid_t pid)
{
FILE *file;
if (!pid_filename)
return;
file = fopen(pid_filename, "a");
if (!file) {
perror(pid_filename);
exit(1);
}
fprintf(file, "%d\n", pid);
fclose(file);
}
void sighandler(int sig, siginfo_t *si, void *arg)
{
up(sem_id);
printf("usemem: exit on signal %d\n", sig);
exit(0);
}
void detach(void)
{
pid_t pid;
sem_id = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT|IPC_EXCL);
if (sem_id == -1) {
perror("semget");
exit(1);
}
if (semctl(sem_id, 0, SETVAL, 0) == -1) {
perror("semctl");
if (semctl(sem_id, 0, IPC_RMID) == -1)
perror("sem_id IPC_RMID");
exit(1);
}
pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
}
if (pid) { /* parent */
update_pid_file(pid);
if (down(sem_id))
perror("down");
semctl(sem_id, 0, IPC_RMID);
exit(0);
}
if (pid == 0) { /* child */
struct sigaction sa = {
.sa_sigaction = sighandler,
.sa_flags = SA_SIGINFO,
};
/*
* XXX: SIGKILL cannot be caught.
* The parent will wait for ever if child is OOM killed.
*/
sigaction(SIGINT, &sa, NULL);
}
}
unsigned long * allocate(unsigned long bytes)
{
unsigned long *p;
if (!bytes)
return NULL;
if (opt_malloc) {
p = malloc(bytes);
if (p == NULL) {
perror("malloc");
exit(1);
}
} else {
p = mmap(NULL, bytes, (opt_readonly && !opt_openrw) ?
PROT_READ : PROT_READ|PROT_WRITE,
map_shared|map_populate|map_anonymous|map_hugetlb,
map_anonymous ? -1 : fd, map_offset);
if (p == MAP_FAILED) {
fprintf(stderr, "%s: mmap failed: %s\n",
ourname, strerror(errno));
exit(1);
}
p = (unsigned long *)ALIGN((unsigned long)p, pagesize - 1);
}
if (do_mlock && mlock(p, bytes) < 0) {
perror("mlock");
exit(1);
}
return p;
}
void free_memory(void *ptrs[], unsigned int nptr,
unsigned long unit, unsigned long last_unit)
{
unsigned int i;
for (i = 0; i < nptr; i++) {
if (opt_malloc)
free(ptrs[i]);
else
munmap(ptrs[i], i == nptr - 1 ? last_unit : unit);
}
}
int runtime_exceeded(void)
{
struct timeval now;
if (!runtime_secs || start_time.tv_sec == 0)
return 0;
gettimeofday(&now, NULL);
return (now.tv_sec - start_time.tv_sec > runtime_secs);
}
/* Function to allocate sys V IPC shared object of size "bytes" */
void shm_allocate_and_lock(unsigned long bytes)
{
unsigned long *p = NULL; /* initialize to NULL */
unsigned long itr;
int page_size;
if (!bytes) {
perror("invalid size\n");
exit(1);
}
/* create a shared sys V IPC shared object of size "bytes"*/
/* Check if the shmget call was successful */
if ((seg_id = shmget(IPC_PRIVATE, bytes, IPC_CREAT|IPC_EXCL)) == EINVAL) {
fprintf(stderr, "SHM creation failed with error :%s\n", strerror(errno));
exit(1);
}
/* Attach the shared memory to callers virtual address space */
/* Check if the attachment was successful */
if ((p = shmat(seg_id, NULL, SHM_RND)) == (void *) -1) {
fprintf(stderr, "SHM attachment failed with error :%s\n", strerror(errno));
shm_free(seg_id);
exit(1);
} else {
/* Attach the shared segment to virtual space of process at p */
page_size = getpagesize();
/* Touch each page atleast once */
for (itr = 0; itr < bytes; itr += page_size)
*((char *)p + itr + 1) = 1;
}
if (shmctl(seg_id, SHM_LOCK, NULL) < 0) {
perror("Error in SYS V SHM locking\n");
exit(1);
}
}
/* Unlock a locked SYS V IPC shared memory */
void shm_unlock(int seg_id)
{
if (seg_id < 0) {
perror("Invalid seg_id\n");
exit(1);
}
/* Unlock shared memory segment */
shmctl(seg_id, SHM_UNLOCK, NULL);
}
unsigned long do_access(unsigned long *p, unsigned long idx, int read)
{
volatile unsigned long *vp = p;
if (read)
return vp[idx]; /* read data */
else {
vp[idx] = idx; /* write data */
return 0;
}
}
#define NSEC_PER_SEC (1UL * 1000 * 1000 * 1000)
long nsec_sub(long nsec1, long nsec2)
{
if (nsec1 < nsec2)
return nsec1 - nsec2 + NSEC_PER_SEC;
else
return nsec1 - nsec2;
}
void delay(unsigned long delay, unsigned long *p, unsigned long idx, int read)
{
struct timespec start, now;
clock_gettime(CLOCK_REALTIME, &start);
do {
do_access(p, idx, read);
clock_gettime(CLOCK_REALTIME, &now);
} while (nsec_sub(now.tv_nsec, start.tv_nsec) < delay);
}
static unsigned long do_rw_once(unsigned long *p, unsigned long bytes,
struct drand48_data *rand_data, int read,
int *rep, int reps)
{
unsigned long i;
unsigned long m = bytes / sizeof(*p);
unsigned long rw_bytes = 0;
unsigned long prev_addr = 0;
unsigned long addr;
for (i = 0; i < m; i += step / sizeof(*p)) {
unsigned long idx = i;
if (opt_randomise)
idx = os_random_long(m - 1, rand_data);
/* verify last write */
if (rep && *rep && !read && !opt_randomise && p[idx] != idx) {
fprintf(stderr, "Data wrong at offset 0x%lx. "
"Expected 0x%08lx, got 0x%08lx\n",
idx * sizeof(*p), idx, p[idx]);
exit(1);
}
/* read / write */
do_access(p, idx, read);
rw_bytes += sizeof(*p);
addr = (unsigned long)(p + idx);
if (opt_delay && PFN_OF(addr) != PFN_OF(prev_addr)) {
delay(opt_delay, p, idx, read);
prev_addr = addr;
}
if (!(i & 0xffff) && runtime_exceeded()) {
if (rep)
*rep = reps;
break;
}
}
return rw_bytes;
}
/* This is copied from hackbench, Thanks Ingo! */
static void ready(int ready_fds[], int wake_fds[])
{
char dummy = '*';
struct pollfd pollfd = { .fd = wake_fds[0], .events = POLLIN };
/* Tell them we're ready. */
if (write(ready_fds[1], &dummy, 1) != 1) {
perror("write pipe");
exit(1);
}
/* Wait for "GO" signal */
if (poll(&pollfd, 1, -1) != 1) {
perror("poll");
exit(1);
}
}
unsigned long do_unit(unsigned long bytes, struct drand48_data *rand_data,
void **pptr)
{
unsigned long rw_bytes;
unsigned long *p;
int rep;
int c;
if (prealloc) {
p = prealloc;
rw_bytes = 0;
} else {
p = allocate(bytes);
rw_bytes = bytes / 8;
if (pptr)
*pptr = p;
}
if (opt_sync_rw)
ready(start_ready_fds, start_wake_fds);
if (!started) {
/* Avoid timing memory allocation and syncing */
gettimeofday(&start_time, NULL);
started = 1;
}
if (opt_write_signal_read)
buffer = p;
for (rep = 0; rep < reps; rep++) {
if (rep > 0 && !quiet) {
printf(".");
fflush(stdout);
}
rw_bytes += do_rw_once(p, bytes, rand_data, opt_readonly, &rep, reps);
if (msync_mode) {
if ((msync(p, bytes, msync_mode)) == -1) {
fprintf(stderr, "msync failed with error %s \n", strerror(errno));
exit(1);
}
}
}
if (do_getchar) {
print_menu();
while (1) {
if ((c = getchar()) == '\n') continue;
switch (c) {
case 'a':
/* select this case for an automatic lock, remap and unlock */
mlock(p, bytes);
printf("locking memory ..... done!\n\n");
if ((p = mremap(p, bytes, SCALE_FACTOR * bytes, MREMAP_MAYMOVE)) == MAP_FAILED) {
fprintf(stderr, "remap failed: %s\n\n", strerror(errno));
exit(1);
}
bytes = SCALE_FACTOR * bytes;
printf("remapping locked memory.....done!\n\n");
munlock(p, bytes);
printf("unlocking memory ..... done!\n\n");
return rw_bytes;
case 'u':
munlock(p, bytes);
printf("unlocking memory ..... done!\n");
print_menu();
break;
case 'l':
mlock(p, bytes);
printf("locking memory ..... done!\n");
print_menu();
break;
case 'r':
if ((p = mremap(p, bytes, SCALE_FACTOR * bytes, MREMAP_MAYMOVE)) == MAP_FAILED) {
fprintf(stderr, "remap failed: %s\n", strerror(errno));
exit(1);
}
bytes = SCALE_FACTOR * bytes;
printf("remapping locked memory.....done!\n");
print_menu();
break;
case 'q':
printf("Quitting now\n");
return rw_bytes;
}
}
}
return rw_bytes;
}
static void output_statistics(unsigned long unit_bytes)
{
struct timeval stop;
char buf[1024];
size_t len;
unsigned long delta_us;
unsigned long throughput;
gettimeofday(&stop, NULL);
delta_us = (stop.tv_sec - start_time.tv_sec) * 1000000 +
(stop.tv_usec - start_time.tv_usec);
throughput = ((unit_bytes * 1000000ULL) >> 10) / delta_us;
len = snprintf(buf, sizeof(buf),
"%lu bytes / %lu usecs = %lu KB/s\n",
unit_bytes, delta_us, throughput);
fflush(stdout);
write(1, buf, len);
}
static void timing_free(void *ptrs[], unsigned int nptr,
unsigned long unit, unsigned long last_unit)
{
struct timeval start, stop;
unsigned long delta_us;
gettimeofday(&start, NULL);
free_memory(ptrs, nptr, unit, last_unit);
gettimeofday(&stop, NULL);
delta_us = (stop.tv_sec - start.tv_sec) * 1000000 +
(stop.tv_usec - start.tv_usec);
printf("%lu usecs to free memory\n", delta_us);
}
static void wait_for_sigusr1(int signal) {}
long do_units(void)
{
struct drand48_data rand_data;
unsigned long unit_bytes = done_bytes;
unsigned long bytes = opt_bytes;
unsigned long last_unit;
void *ptrs[MAX_POINTERS];
unsigned int nptr = 0;
if (opt_detach)
detach();
/* Base the random seed on the thread ID for multithreaded tests */
if (opt_randomise)
os_random_seed(time(0) ^ syscall(SYS_gettid), &rand_data);
if (!unit)
unit = bytes;
if (!opt_sync_rw)
ready(start_ready_fds, start_wake_fds);
/*
* Allow a bytes=0 pass for pure fork bomb:
* usemem -n 10000 0 --detach --sleep 10
*/
do {
unsigned long size = min(bytes, unit);
unit_bytes += do_unit(size, &rand_data,
nptr < MAX_POINTERS ? &ptrs[nptr] : NULL);
nptr++;
last_unit = size;
bytes -= size;
if (runtime_exceeded())
break;
} while (bytes);
if (!opt_write_signal_read && unit_bytes)
output_statistics(unit_bytes);
if (opt_write_signal_read) {
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = wait_for_sigusr1;
if (sigaction(SIGUSR1, &act, NULL) == -1) {
perror("sigaction");
exit(-1);
}
}
if (opt_detach && up(sem_id))
perror("up");
if (sleep_secs)
sleep(sleep_secs);
if (opt_write_signal_read) {
sigset_t set;
sigfillset(&set);
sigdelset(&set, SIGUSR1);
sigsuspend(&set);
gettimeofday(&start_time, NULL);
unit_bytes = do_rw_once(buffer, opt_bytes, &rand_data, 1, NULL, 0);
output_statistics(unit_bytes);
}
if (opt_sync_free)
ready(free_ready_fds, free_wake_fds);
if (!prealloc && nptr <= MAX_POINTERS)
timing_free(ptrs, nptr, unit, last_unit);
return 0;
}
typedef void * (*start_routine)(void *);
static inline int bind_cpu(int task_nr)
{
return task_nr * opt_bind_interval % nr_cpu;
}
int do_task(int task_nr)
{
pthread_t threads[nr_thread];
long thread_ret;
int ret;
int i;
cpu_set_t *mask;
size_t size;
size = CPU_ALLOC_SIZE(nr_cpu);
mask = CPU_ALLOC(nr_cpu);
if (mask == NULL) {
perror("CPU_ALLOC");
exit(1);
}
if (!nr_thread) {
if (opt_bind_interval) {
CPU_ZERO_S(size, mask);
CPU_SET_S(bind_cpu(task_nr), size, mask);
sched_setaffinity(getpid(), size, mask);
CPU_FREE(mask);
}
return do_units();
}
for (i = 0; i < nr_thread; i++) {
ret = pthread_create(&threads[i], NULL, (start_routine)do_units, NULL);
if (ret) {
perror("pthread_create");
exit(1);
}
if (opt_bind_interval) {
CPU_ZERO_S(size, mask);
CPU_SET_S(bind_cpu(task_nr * nr_thread + i), size, mask);
ret = pthread_setaffinity_np(threads[i], size, mask);
if (ret) {
perror("pthread_setaffinity_np");
exit(1);
}
}
}
CPU_FREE(mask);
for (i = 0; i < nr_thread; i++) {
ret = pthread_join(threads[i], (void *)&thread_ret);
if (ret) {
perror("pthread_join");
exit(1);
}
}
return 0;
}
int synchronize_tasks(int ready_fds[], int wake_fds[])
{
int i;
char dummy;
int tasks = nr_thread ? nr_task * nr_thread : nr_task;
for (i = 0; i < tasks; i++)
if (read(ready_fds[0], &dummy, 1) != 1) {
perror("read pipe");
return 1;
}
/* Fire! */
if (write(wake_fds[1], &dummy, 1) != 1) {
perror("write pipe");
return 1;
}
return 0;
}
int do_tasks(void)
{
int i;
int status;
int child_pid;
for (i = 0; i < nr_task; i++) {
if ((child_pid = fork()) == 0)
return do_task(i);
else if (child_pid < 0)
fprintf(stderr, "failed to fork: %s\n",
strerror(errno));
}
if (synchronize_tasks(start_ready_fds, start_wake_fds))
return 1;
if (opt_sync_free && synchronize_tasks(free_ready_fds, free_wake_fds))
return 1;
for (i = 0; i < nr_task; i++) {
if (wait3(&status, 0, 0) < 0) {
if (errno != EINTR) {
printf("wait3 error on %dth child\n", i);
perror("wait3");
return 1;
}
}
}
return 0;
}
int main(int argc, char *argv[])
{
int c;
#ifdef DBG
/* print the command line parameters passed on to main */
int itr = 0;
printf("main() invoked with %d arguments and they are as follows \n", argc);
for (itr = 0; itr < argc; itr++) {
printf("arg[%d] is -----> %s\n", itr, argv[itr]);
}
#endif
ourname = argv[0];
pagesize = getpagesize();
while ((c = getopt_long(argc, argv,
"aAB:f:FPp:gqowRMm:n:t:b:ds:T:Sr:u:j:e:EHDNLWyxOUh", opts, NULL)) != -1)
{
switch (c) {
case 'a':
opt_malloc++;
break;
case 'u':
unit = memparse(optarg, NULL);
break;
case 'j':
step = memparse(optarg, NULL);
break;
case 'A':
msync_mode = MS_ASYNC;
break;
case 'f':
filename = optarg;
map_shared = MAP_SHARED;
break;
case 'B':
map_offset = strtol(optarg, NULL, 10);
break;
case 'p':
pid_filename = optarg;
break;
case 'g':
do_getchar = 1;
break;
case 'm': /* kept for compatibility */
opt_bytes = strtol(optarg, NULL, 10);
opt_bytes <<= 20;
break;
case 'n':
nr_task = strtol(optarg, NULL, 10);
break;
case 't':
nr_thread = strtol(optarg, NULL, 10);
break;
case 'b':
opt_bind_interval = strtol(optarg, NULL, 10);
break;
case 'P':
prealloc++;
break;
case 'F':
map_populate = MAP_POPULATE;
break;
case 'M':
do_mlock = 1;
break;
case 'q':
quiet = 1;
break;
case 's':
sleep_secs = strtol(optarg, NULL, 10);
break;
case 'T':
runtime_secs = strtol(optarg, NULL, 10);
break;
case 'd':
opt_detach = 1;
break;
case 'r':
reps = strtol(optarg, NULL, 10);
break;
case 'R':
opt_randomise++;
break;
case 'S':
msync_mode = MS_SYNC;
break;
case 'o':
opt_readonly++;
break;
case 'w':
opt_openrw++;
break;
case 'h':
usage(0);
break;
case 'L':
opt_shm = 1;
break;
case 'D':
filename = argv[optind];
opt_advise = 1;
break;
case 'E':
opt_remap = 1;
break;
case 'N':
opt_mincore = 1;
break;
case 'H':
opt_mincore_hugepages = 1;
break;
case 'W':
opt_write_signal_read = 1;
break;
case 'y':
opt_sync_rw = 1;
break;
case 'x':
opt_sync_free = 1;
break;
case 'e':
opt_delay = time_parse(optarg);
break;
case 'O':
map_anonymous = MAP_ANONYMOUS;
case 'U':
map_hugetlb = MAP_HUGETLB | MAP_HUGE_2MB;
break;
default:
usage(1);
}
}
if (pipe(start_ready_fds) || pipe(start_wake_fds) ||
pipe(free_ready_fds) || pipe(free_wake_fds)) {
fprintf(stderr, "%s: failed to create pipes: %s\n",
ourname, strerror(errno));
exit(1);
}
nr_cpu = sysconf(_SC_NPROCESSORS_ONLN);
if (nr_cpu < 0) {
fprintf(stderr, "%s: failed to get online CPU number: %s\n",
ourname, strerror(errno));
exit(1);
}
if (opt_bind_interval >= nr_cpu) {
fprintf(stderr, "%s: invalid binding interval %d for %d CPUs\n",
ourname, opt_bind_interval, nr_cpu);
exit(1);
}
if (step < sizeof(long))
step = sizeof(long);
if (optind != argc - 1)
usage(0);
if (!opt_write_signal_read)
gettimeofday(&start_time, NULL);
opt_bytes = memparse(argv[optind], NULL);
if (opt_sync_rw && unit && unit != opt_bytes) {
fprintf(stderr, "%s: to sync tasks after allocation, unit must equal total size\n",
ourname);
exit(1);
}
if (!opt_malloc)
fd = open(filename, ((opt_readonly && !opt_openrw) ?
O_RDONLY : O_RDWR) | O_CREAT, 0666);
if (fd < 0) {
fprintf(stderr, "%s: failed to open `%s': %s\n",
ourname, filename, strerror(errno));
exit(1);
}
if (prealloc) {
prealloc = allocate(opt_bytes);
done_bytes = opt_bytes / 8;
}
if (opt_remap) {
prealloc = mremap(prealloc, opt_bytes, SCALE_FACTOR * opt_bytes, MREMAP_MAYMOVE);
done_bytes += opt_bytes / 8;
}
/* Allocate a shared sysV IPC shared object of size "opt_bytes" */
if (opt_shm) {
shm_allocate_and_lock(opt_bytes);
/* Unlocking memory now */
shm_unlock(seg_id);
/* mark for destruction */
shm_free(seg_id);
done_bytes += opt_bytes / 8;
}
/* Advise file access pattern */
if (opt_advise) {
/* advice : WILLNEED */
if ((posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED)) == -1) {
fprintf(stderr, "posix_advise() error : %s\n", strerror(errno));
exit(1);
}
/* close the file */
close(fd);
/* open again for POSIX_FADV_DONTNEED */
if ((fd = open(filename, ((opt_readonly && !opt_openrw) ?
O_RDONLY : O_RDWR) | O_CREAT, 0666)) < 0) {
fprintf(stderr, "%s: failed to open `%s': %s\n",
ourname, filename, strerror(errno));
exit(1);
}
/* advise : DONTNEED*/
if ((posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)) == -1) {
fprintf(stderr, "posix_advise() error : %s\n", strerror(errno));
exit(1);
}
done_bytes += opt_bytes;
close(fd);
}
if (opt_mincore) {
unsigned long length_of_vector = ((opt_bytes/getpagesize()) + 1);
unsigned char *ptr = NULL; /* initialize to NULL */
if ((ptr = (unsigned char *)malloc((sizeof(char)) * length_of_vector)) == NULL) {
fprintf(stderr, "Unable to allocate requested memory");
fprintf(stdout, "exiting now...");
exit(1);
}
if ((mincore(prealloc, opt_bytes, ptr)) == -1) {
fprintf(stderr, "mincore failed with error: %s", strerror(errno));
free(ptr);
exit(1);
}
done_bytes += opt_bytes / 8;
free(ptr);
return 0;
}
if (opt_mincore_hugepages) {
int i;
int number_of_pages;
unsigned char *p = (unsigned char *)allocate_hugepage_segment(opt_bytes);
unsigned long pagesize = HUGE_PAGE_SIZE;
char modify_nr_hugepages[50];
/* error checking done inside the mincore_hugepages function */
mincore_hugepages(p, opt_bytes);
/* change protection of the hugepage segment */
if (mprotect(p, opt_bytes, PROT_WRITE) == -1) {
fprintf(stderr, "mprotect error: %s", strerror(errno));
exit(1);
}
number_of_pages = opt_bytes/pagesize;
/* copy on write for allocating child address space */
for (i = 0; i < number_of_pages; i++)
p[i * pagesize] = (char) 1;
sprintf(modify_nr_hugepages, "echo 5 > /proc/sys/vm/nr_hugepages\n");
if ((system(modify_nr_hugepages)) == -1) {
fprintf(stderr, "bash command failed\n");
exit(1);
}
done_bytes += opt_bytes / 8;
/* free the shm segment */
shm_free(seg_id);
return 0; /* return with out doing anything */
}
if (!nr_task)
nr_task = 1;
return do_tasks();
}