#!/bin/sh -

#	MOSIX	$Id: tune_kernel.sh,v 1.7 2000/07/04 14:33:10 amnons Exp $

instructions() {
	while :
	do
		echo
		echo For correct results, please make sure that:
		echo --------------------------------------------
		echo
		echo "1. Only 2 nodes (this and another one) are currently ON"
		echo "   (or connected to the network), both running MOSIX."
		echo
		echo "2. Both nodes are in single-user mode."
		case `tty ; runlevel` in /dev/console*1*) : ;; *)
			echo "   (if this node is in multi-user mode, stop now and"
			echo "    bring it to single-user mode by typing 'telinit 1')"
			;;
		esac
		echo
		echo "3. If any other MOSIX node(s) must remain connected to the network because"
		echo "   they act as routers between the two tested nodes, then MOSIX must be"
		echo "   disabled on those node(s) for the duration of the test:"
		echo "   (this can be done by running 'setpe -off')".
		echo
		echo "4. The network and MOSIX are enabled and MOSIX is in a special 'quiet' mode:"
		echo "   While this node is automatically taken care of, the following command"
		echo "   must be typed on the console of the other participating node:"
		echo
		echo "   /sbin/prep_tune"
		echo -----------------------------------------------------------------------
		echo
		echo -n "All OK and ready? "
		read ok
		case "$ok" in [yY]*) break ;;
			[qQ]*) exit ;;
			[nN]*) echo "Please fix the problem, or type 'q' to quit now:" ;;
			*) echo
			   echo "Please check the following and answer with a 'Yes' or a 'No':" ;;
		esac
	done
}

stoptune() {
	usleep 200000	# so kernel message does not interfere with output
	/sbin/prep_tune stop
	echo
	echo "Unless you wish to repeat this procedure again now, you should type"
	echo "the following line on the other node's console:"
	echo
	echo "          /sbin/prep_tune stop"
	echo
}

clear
echo " MOSIX Kernel Load-Balancing Optimization Procedure:"
echo "====================================================="
echo
[ -f /proc/mosix/admin/overheads ] || {
	echo Sorry, this system does not support MOSIX.
	exit 1
}
if [ -f /proc/mosix/admin/mfscosts ]
then
	while :
	do
		/bin/echo -n "Do you wish to optimize the Kernel, MFS or Both (k/m/B)? "
		read which
		case "$which" in "" | [bB]*) do_tune=y ; do_mfs=y ; break ;;
			[kK]*) do_tune=y ; do_mfs=n ; break ;;
			[mM]*) do_tune=n ; do_mfs=y ; break ;;
			[nNqQ]*) echo OK - not optimizing any! ; exit ;;
			*) echo Please Answer - the available options are: Kernel, MFS, Both, or None. ;;
		esac
	done
else
	do_tune=y
	do_mfs=n
fi
sets=`wc /proc/mosix/admin/overheads | awk '{ printf "%.0f", $2/16;}'`
if [ $sets -gt 1 ]
then
	echo "Most MOSIX clusters use a linear (flat) network toplogy,"
	echo "where the network-distance between each two nodes is the same."
	echo "MOSIX can support non-linear topologies, but it makes this procedure longer."
	echo
	echo -n "Do you use a complex network-topology for MOSIX [y/N]? "
	read topo
	case "$topo" in [qQ]*) exit ;;
		[yY]*)
			topo=y
			donesets=0
			echo
			echo MOSIX currently supports network topologies where each node can have up to
			echo $sets different network-distances to $sets sets of nodes of consecutive MOSIX-IDs.
			echo
			echo If this node has more than one such set of network-distances with other
			echo MOSIX nodes, then you will need to repeat the tuning procedure,
			echo each time with a selected member of a different set.
			echo "As you repeat the tuning procedure with different nodes, you will need to"
			echo "follow the given instructions carefully, as you will be required to shut-down"
			echo "the node that was previously tested and bring up the next node to be tested."
			echo
			echo "The final results of the whole '$0' procedure may then be copied"
			echo "to other nodes of the same hardware that are situated in the same toplogical"
			echo "network position as this one, but for all other nodes, you will need to repeat"
			echo "'$0' separately afterwards from the console(s) of those nodes."
			echo
			echo -n "Press <Enter> to continue..."
			read nothing
		;;
	esac
fi
cd /tmp
/sbin/prep_tune
cp /sbin/tunepass .
if [ "$topo" != "y" ]
then
instructions
echo
echo "For future reference, if you like to enter any comment to characterize the"
echo "measurement, describe its circumstances, nodes and network used, etc.,"
echo -n "please do so now :- "
read comment
while :
do
	echo
	echo "If you do not remember the MOSIX-ID of the other node, you can find it out"
	echo "by typing 'cat /proc/mosix/admin/mospe' on the other node's console."
	echo
	/bin/echo -n "Please enter the MOSIX-ID of the other node :- "
	read other
	case "$other" in [qQ]*) exit ;;
		[1-9] | [1-9][0-9] | [1-9][0-9][0-9]) break ;;
		[1-9][0-9][0-9][0-9] | [1-6][0-9][0-9][0-9][0-9]) break ;;
	esac
done
ok=t
[ $do_tune = n ] || /sbin/tune -o -c "$comment" $other || ok=f
[ $ok = f -o $do_mfs = n ] || /sbin/mtune -o -c "$comment" $other || ok=f
[ $ok = t ] && {
	echo Copying the results:
	dir=/usr/src/mosix
	echo -n "Kernel-source directory (default=$dir) :- "
	read d
	case "$d" in ?*)
		if [ -d $d ]
		then
			dir=$d
		else
			dir=/NeVerFindMe
		fi ;;
	esac
	if [ -d $dir/include/mos ]
	then
		ok=t
		[ $do_tune = n ] || \
			cp /tmp/dscosts.h $dir/include/mos/dscosts.h || {
			echo "Copy of '/tmp/dscosts.h' to '$dir/mos/dscosts.h' failed!"
			ok=f
		}
		[ $ok = f -o $do_mfs = n ] || \
			cp /tmp/mfscosts.h $dir/include/mos/mfscosts.h || {
			echo "Copy of '/tmp/mfscosts.h' to '$dir/mos/mfscosts.h' failed!"
			ok=f
		}
		[ $ok = t ] && {
			echo -n "Make a new MOSIX kernel now [Yes/no/install]? "
			read now
			case "$now" in [iI]*) ins=install ;; *) ins= ;; esac
			case "$now" in [iIyY]* | "")
				   cd $dir
				   make $ins && {
					echo
					echo MOSIX-kernel created.
					case "$now" in [iI]*)
						lilo
						echo "Done.  please copy the new kernel to all other MOSIX nodes and run LILO there."
						echo
					esac
				   }
			esac
		}
	else
		echo No such MOSIX-kernel-source directory!
		/bin/echo -n "The optimisation results are now in "
		case $do_tune$do_mfs in yn)
			echo "'/tmp/dscosts.h' and should be copied to"
			echo "{KERNEL_SOURCE_DIR}/include/mos/dscosts.h." ;;
		    ny) echo "'/tmp/mfscosts.h' and should be copied to"
			echo "{KERNEL_SOURCE_DIR}/include/mos/mfscosts.h." ;;
		    yy) echo "'/tmp/dscosts.h' and '/tmp/mfscosts.h'"
			echo and should be copied to "{KERNEL_SOURCE_DIR}/include/mos/dscosts.h and "
			echo and "{KERNEL_SOURCE_DIR}/include/mos/mfscosts.h (respectively)." ;;
		esac
		echo
	fi
	[ $do_tune = y ] && cp mosix.costs overheads
	[ $do_mfs = y ] && cp mfs.costs mfscosts
}
stoptune
else
	setno=1
	/bin/cat << OVINSTRUCT > explanation
# integers (FIRST and LAST) describing the range of MOSIX nodes to which those
# constants apply.
# When searching for the constants applicable to a particular node,
# the first applicapble line is selected.  If no line is applicable,
# then the first line is selected.
#
# When FIRST <= LAST, the range includes all nodes between FIRST and LAST.
# When FIRST > LAST, the range includes all nodes NOT between LAST and FIRST.
# When FIRST is nonzero and LAST is 0, the range includes all nodes but FIRST.
# When FIRST is 0, the range includes all the rest of the nodes.
#
OVINSTRUCT
	case "$do_tune" in y)
		echo "# Each line in this file contains 14 integer tuning contants plus another 2" > overheads
		cat explanation >> overheads
	esac
	case $do_mfs in y)
		echo "# Each line in this file contains 6 integer MFS tuning contants plus another 2" > mfscosts
		cat explanation >> mfscosts
	esac
	while [ $setno -le $sets ]
	do
		echo
		case $setno in
			1) echo "Please select any range of nodes with the same distance to this one." ;;
			2) echo If there are any nodes with a different network distance,
			   echo Please select another range of nodes now. ;;
			$sets)
			   echo If there are any more nodes with a different network distance,
		           echo Please select the last range of nodes now. ;;
			*)
			   echo If there are any other nodes with a different network distance,
			   echo Please select a range of them now. ;;
		esac
		case $setno in 1) : ;;
			*) echo "If all the rest of the nodes have the same network distance, type 'r'"
			   echo "or if all nodes were already covered, type '0'".
		esac
		echo
		echo -n "First node in range :- "
		read first
		case "$first" in "") continue ;;
			[rR]) first=r ;;
			[qQ]*) /sbin/prep_tune stop ; exit ;;
			0) case "$setno" in 1) continue ;; esac ; break ;;
			[1-9] | [1-9][0-9] | [1-9][0-9][0-9] | \
			[1-9][0-9][0-9][0-9] | [1-6][0-9][0-9][0-9][0-9]) : ;;
			*) continue ;;
		esac
		case $first in r) : ;; *)
		echo -n "Last node in range :- "
		read last
		case "$last" in "") continue ;;
			[qQ]*) /sbin/prep_tune stop ; exit ;;
			0) case "$setno" in 1) continue ;; esac ; break ;;
			[1-9] | [1-9][0-9] | [1-9][0-9][0-9] | \
			[1-9][0-9][0-9][0-9] | [1-6][0-9][0-9][0-9][0-9]) : ;;
			*) continue ;;
		esac
		[ $last -ge $first ] || {
			echo "$last < $first ..."
			echo Please Try Again!
			continue
		}
		i=1
		while [ $i -lt $setno ]
		do
			eval f="$"first$i
			eval l="$"last$i
			i=`/usr/bin/expr $i + 1`
			[ $first -gt $l -o $last -lt $f ] && continue
			echo "This range ($first-$last) overlaps with the $f-$l range ..."
			echo Please Try Again!
			continue 2
		done
		;; esac
		case $last in $first) other=$first ;;
		*)
			case $first in
				r) echo -n "Which node of the rest will you be now using for the test :- " ;;
				*) echo -n "Which node in this range will you be now using for the test :- " ;;
			esac
			read other
			case "$other" in "") continue ;;
				[qQ]*) /sbin/prep_tune stop ; exit ;;
				0) case "$setno" in 1) continue ;; esac ; break ;;
				[1-9] | [1-9][0-9] | [1-9][0-9][0-9] | \
				[1-9][0-9][0-9][0-9] | [1-6][0-9][0-9][0-9][0-9]) : ;;
				*) continue ;;
			esac
			if [ $first != r ]
			then
			if [ $other -lt $first -o $other -gt $last ]
			then
				echo Not in Range ...
				echo Please Try Again!
				continue
			fi
			fi
			;;
		esac
echo Tuning with $other
		instructions
		[ $do_tune = n ] || /sbin/tune -o $other || continue
		[ $do_mfs = n ] || /sbin/mtune -o $other || continue
		echo
		echo "Procedure completed with node #$other - you now need to either:"
		echo "1) shut node #$other down."
		echo "2) physically disconnect node #$other from the network."
		echo "3) if node #$other is used as router to other MOSIX nodes,"
		echo "   turn off MOSIX there by typing 'setpe -off' on node #$other's console."
		echo
		echo "In cases 2 or 3, also type '/sbin/prep_tune stop' on node #$other's console."
		echo
		echo -n "Once done, please press <Enter> to continue..."
		read nothing
		case $first in r)
			[ $do_tune = y ] && echo `/bin/cat mosix.costs` 0 0 >> overheads
			[ $do_mfs = y ] && echo `/bin/cat mfs.costs` 0 0 >> mfscosts
			break ;;
			*)
			[ $do_tune = y ] && echo `/bin/cat mosix.costs` $first $last >> overheads
			[ $do_mfs = y ] && echo `/bin/cat mfs.costs` $first $last >> mfscosts
		esac
		eval first$setno=$first
		eval last$setno=$last
		setno=`expr $setno + 1`
	done
	stoptune
	echo
	echo All Done.
	case $do_tune$do_mfs in yn)
		echo "The file '/tmp/overheads' now contains all the computed results" ;;
		ny) echo "The file '/tmp/mfscosts' now contains all the computed results" ;;
		yy) echo "The files '/tmp/overheads' and '/tmp/mfscosts' now contain"
		    echo "all the computed results (for the kernel and MFS respectively)" ;;
	esac
	echo with relation to this node and all other nodes of the same hardware
	echo that are situated in the same topological network position as this node.
	while [ $do_tune = y ]
	do
		echo -n "Commit the changes to /etc/overheads? "
		read yesno
		case "$yesno" in [nN]*) break ;;
			[yY]*) [ -f /etc/overheads ] && \
				/bin/mv -f /etc/overheads /etc/overheads.bkp &&\
				echo Previous constants saved to /etc/overheads.bkp
				/bin/cp overheads /etc/overheads
				break ;;
			[qQ]*) exit ;;
			*) echo Please respond with Yes or No...
		esac
	done
	while [ $do_mfs = y ]
	do
		echo -n "Commit the changes to /etc/mfscosts? "
		read yesno
		case "$yesno" in [nN]*) break ;;
			[yY]*) [ -f /etc/mfscosts ] && \
				/bin/mv -f /etc/mfscosts /etc/mfscosts.bkp &&\
				echo Previous constants saved to /etc/mfscosts.bkp
				/bin/cp mfscosts /etc/mfscosts
				break ;;
			[qQ]*) exit ;;
			*) echo Please respond with Yes or No...
		esac
	done
	echo
	echo If you wish to use the same results by other nodes that share
	echo both the same hardware and topological position on the network,
	case $do_tune$do_mfs in yn)
		echo copy the file "'/etc/overheads'" to all those nodes. ;;
		ny) echo copy the file "'/etc/mfscosts'" to all those nodes. ;;
		yy) echo copy the files "'/etc/overheads' and '/etc/mfscosts'" to all those nodes. ;;
	esac
	echo
	echo Sophisticated users who wish to apply these results to nodes with
	echo identical hardware that are situated in symetric positions on the
	/bin/echo -n "network may also do so by editing "
	case $do_tune$do_mfs in yn) echo /etc/overheads. ;;
		 ny) echo /etc/mfscosts. ;;
		 yy) echo /etc/overheads and /etc/mfscosts. ;;
	esac
	echo
fi
echo Thank you.
rm -f /tmp/pg /tmp/tunepass
