#!/bin/sh

if [ -n "$runtime" ]; then
	USEMEM="$CMD ./usemem --runtime $runtime"
else
	USEMEM="$CMD ./usemem"
fi

[ -n "$SYNC_RW" ] && USEMEM="$USEMEM -y"
[ -n "$SYNC_FREE" ] && USEMEM="$USEMEM -x"
[ -n "$BIND_CPU" ] && USEMEM="$USEMEM -b $BIND_CPU"
[ -n "$REPEAT_COUNT" ] && USEMEM="$USEMEM -r $REPEAT_COUNT"
[ -n "$DELAY" ] && USEMEM="$USEMEM -e $DELAY"
[ -n "$TIMED_WP" ] && USEMEM="$USEMEM --timed-wp $TIMED_WP"

TMPFS_MNT=/tmp/vm-scalability-tmp
SHM_FILE=$TMPFS_MNT/sparse-${0#*case-}

SPARSE_ROOT=${SPARSE_ROOT:-$TMPFS_MNT/vm-scalability}
SPARSE_FILE=$SPARSE_ROOT/sparse-${0#*case-}
# SPARSE_FSTYPE=$(/usr/bin/stat -fc %T $SPARSE_ROOT)
# [ $SPARSE_FSTYPE = tmpfs ] && echo "$SPARSE_ROOT is tmpfs, sparse files won't eat memory." && exit 1
# [ $SPARSE_FSTYPE = nfs ] && echo "$SPARSE_ROOT is nfs, sparse file reads will be slow." && exit 1

PIDFILE=$SPARSE_ROOT/${0#*case-}.pid

mount_tmpfs()
{
	if [ -d "$TMPFS_MNT" ]; then
		mountpoint -q $TMPFS_MNT && umount $TMPFS_MNT
	else
		mkdir $TMPFS_MNT
	fi
	$CMD mount -t tmpfs -o size=100% vm-scalability-tmp $TMPFS_MNT

	shm_size=$(/usr/bin/stat -f -c "%b*%S" $TMPFS_MNT)
	export shm_size=$(($shm_size))
}

create_loop_devices()
{
	local i

	modprobe loop 2>/dev/null
	[ -e "/dev/loop0" ] || modprobe loop 2>/dev/null

	for i in $(seq 0 8)
	do
		[ -e "/dev/loop$i" ] && continue
		mknod /dev/loop$i b 7 $i
	done
}

# sparse files won't work as expected on tmpfs/nfs
create_sparse_root () {
	$CMD truncate -s $((mem)) $SPARSE_ROOT.img
	case ${fs:-xfs} in
		btrfs)
			$CMD mkfs.btrfs $SPARSE_ROOT.img > /dev/null
			;;
		ext4)
			$CMD mkfs.ext4 -q -F $SPARSE_ROOT.img
			;;
		xfs)
			$CMD mkfs.xfs -q $SPARSE_ROOT.img
			;;
	esac
	[ -d "$SPARSE_ROOT" ] || mkdir $SPARSE_ROOT

	# check if already mounted
	if mountpoint -q $SPARSE_ROOT; then
		echo "$SPARSE_ROOT already mounted"
	else
		create_loop_devices
		$CMD mount -o loop $SPARSE_ROOT.img $SPARSE_ROOT 2>/dev/null || {
			local loop_dev=$(losetup -f --show $SPARSE_ROOT.img)
			[ -n "$loop_dev" ] || {
				grep -q loop /proc/devices || echo 'No loop block device!' >&2
				lsmod | grep -q loop || echo 'No loop module' >&2
				LOOPDEV_DEBUG=1 losetup -f --show $SPARSE_ROOT.img
				exit
			}
			mount $loop_dev $SPARSE_ROOT
		}
	fi
}

remove_tmpfs()
{
	$CMD umount $TMPFS_MNT
}

remove_sparse_root () {
	$CMD umount $SPARSE_ROOT || {
		df
		lsof $SPARSE_ROOT
	}
	# rmdir $SPARSE_ROOT
	$CMD rm $SPARSE_ROOT.img
}

create_sparse_file () {
	name=$1
	size=$2
	# echo "$name is of size $size"
	$CMD truncate $name -s $size
	# dd if=/dev/zero of=$name bs=1k count=1 seek=$((size >> 10)) 2>/dev/null
	# ls $SPARSE_ROOT
	# ls /tmp/vm-scalability/*
}


pagesize=$(getconf PAGESIZE)

nr_cpu=$(grep -c processor /proc/cpuinfo)
nr_node=$(echo /sys/devices/system/node/node* | wc -w)

nr_task=${nr_task:-$nr_cpu}

while read key val; do
	[ -n "${val}" ] || continue
	[ -z "${val##*[0-9]}" -a -z "${val%%[0-9]*}" ] || {
		echo "invalid vmstat line: $key $val" >&2
		break
	}
	eval "$key=$val"
done < /proc/vmstat

reclaimable=$((nr_free_pages + nr_file_pages))
reclaimable=$((reclaimable * pagesize))

while read key val unit; do
	key=${key%%:}
	key=${key%%)}
	[ "${key#*(}" != "$key" ] &&
	key=${key%(*}_${key#*(}
	eval $key=$val
done < /proc/meminfo

mem=$((MemTotal << 10))
mem_avail=$((MemAvailable << 10))
hugepagesize=$((Hugepagesize << 10))

ROTATE_BYTES=$((1<<42))

# Documentation/x86/x86_64/mm.txt
# 0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm
AS_LIMIT=$((1<<46))

# prevent OOM: limit pagetable pages to half available memory
# $mem_avail / 2 / 4K = upper_limit_nr_page_table_pages
# every PTE maps 2M space, so
# $upper_limit_nr_page_table_pages * 2M = upper_limit_test_size = PTE_LIMIT
# PTE_LIMIT = 256 * $mem_tail
PTE_LIMIT=$((mem_avail << 8))

[ "$ROTATE_BYTES" -gt $PTE_LIMIT ] && ROTATE_BYTES=$PTE_LIMIT
