18462SApril.Chin@Sun.COM#!/usr/bin/ksh93
28462SApril.Chin@Sun.COM
38462SApril.Chin@Sun.COM#
48462SApril.Chin@Sun.COM# CDDL HEADER START
58462SApril.Chin@Sun.COM#
68462SApril.Chin@Sun.COM# The contents of this file are subject to the terms of the
78462SApril.Chin@Sun.COM# Common Development and Distribution License (the "License").
88462SApril.Chin@Sun.COM# You may not use this file except in compliance with the License.
98462SApril.Chin@Sun.COM#
108462SApril.Chin@Sun.COM# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
118462SApril.Chin@Sun.COM# or http://www.opensolaris.org/os/licensing.
128462SApril.Chin@Sun.COM# See the License for the specific language governing permissions
138462SApril.Chin@Sun.COM# and limitations under the License.
148462SApril.Chin@Sun.COM#
158462SApril.Chin@Sun.COM# When distributing Covered Code, include this CDDL HEADER in each
168462SApril.Chin@Sun.COM# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
178462SApril.Chin@Sun.COM# If applicable, add the following below this CDDL HEADER, with the
188462SApril.Chin@Sun.COM# fields enclosed by brackets "[]" replaced with your own identifying
198462SApril.Chin@Sun.COM# information: Portions Copyright [yyyy] [name of copyright owner]
208462SApril.Chin@Sun.COM#
218462SApril.Chin@Sun.COM# CDDL HEADER END
228462SApril.Chin@Sun.COM#
238462SApril.Chin@Sun.COM
248462SApril.Chin@Sun.COM#
25*10898Sroland.mainz@nrubsig.org# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
268462SApril.Chin@Sun.COM# Use is subject to license terms.
278462SApril.Chin@Sun.COM#
288462SApril.Chin@Sun.COM
298462SApril.Chin@Sun.COM#
308462SApril.Chin@Sun.COM# mandelbrotset1 - a simple mandelbrot set generation and
318462SApril.Chin@Sun.COM# parallel execution demo
328462SApril.Chin@Sun.COM#
338462SApril.Chin@Sun.COM
348462SApril.Chin@Sun.COM# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
358462SApril.Chin@Sun.COMexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
368462SApril.Chin@Sun.COM
378462SApril.Chin@Sun.COM# Make sure all math stuff runs in the "C" locale to avoid problems
388462SApril.Chin@Sun.COM# with alternative # radix point representations (e.g. ',' instead of
398462SApril.Chin@Sun.COM# '.' in de_DE.*-locales). This needs to be set _before_ any
408462SApril.Chin@Sun.COM# floating-point constants are defined in this script).
418462SApril.Chin@Sun.COMif [[ "${LC_ALL}" != "" ]] ; then
428462SApril.Chin@Sun.COM    export \
438462SApril.Chin@Sun.COM        LC_MONETARY="${LC_ALL}" \
448462SApril.Chin@Sun.COM        LC_MESSAGES="${LC_ALL}" \
458462SApril.Chin@Sun.COM        LC_COLLATE="${LC_ALL}" \
468462SApril.Chin@Sun.COM        LC_CTYPE="${LC_ALL}"
478462SApril.Chin@Sun.COM        unset LC_ALL
488462SApril.Chin@Sun.COMfi
498462SApril.Chin@Sun.COMexport LC_NUMERIC=C
508462SApril.Chin@Sun.COM
518462SApril.Chin@Sun.COMfunction printmsg
528462SApril.Chin@Sun.COM{
538462SApril.Chin@Sun.COM	print -u2 "$*"
548462SApril.Chin@Sun.COM}
558462SApril.Chin@Sun.COM
568462SApril.Chin@Sun.COMfunction fatal_error
578462SApril.Chin@Sun.COM{
588462SApril.Chin@Sun.COM	print -u2 "${progname}: $*"
598462SApril.Chin@Sun.COM	exit 1
608462SApril.Chin@Sun.COM}
618462SApril.Chin@Sun.COM
628462SApril.Chin@Sun.COM# Get terminal size and put values into a compound variable with the integer
638462SApril.Chin@Sun.COM# members "columns" and "lines"
648462SApril.Chin@Sun.COMfunction get_term_size
658462SApril.Chin@Sun.COM{
668462SApril.Chin@Sun.COM	nameref rect=$1
678462SApril.Chin@Sun.COM
688462SApril.Chin@Sun.COM	rect.columns=${ tput cols ; } || return 1
698462SApril.Chin@Sun.COM	rect.lines=${ tput lines ; }  || return 1
708462SApril.Chin@Sun.COM
718462SApril.Chin@Sun.COM	return 0
728462SApril.Chin@Sun.COM}
738462SApril.Chin@Sun.COM
748462SApril.Chin@Sun.COMfunction mandelbrot
758462SApril.Chin@Sun.COM{
768462SApril.Chin@Sun.COM	nameref result=$1
778462SApril.Chin@Sun.COM	float   x=$2
788462SApril.Chin@Sun.COM	float   y=$3
798462SApril.Chin@Sun.COM	float   xx
808462SApril.Chin@Sun.COM	float   yy
818462SApril.Chin@Sun.COM	float   x1=$4
828462SApril.Chin@Sun.COM	float   y1=$5
838462SApril.Chin@Sun.COM	integer iteration=$6
848462SApril.Chin@Sun.COM	integer max_iteration=$7
858462SApril.Chin@Sun.COM	float   mag
868462SApril.Chin@Sun.COM
878462SApril.Chin@Sun.COM	for (( mag=0 ; mag < max_mag && iteration < max_iteration ; iteration++ )) ; do
888462SApril.Chin@Sun.COM		((
898462SApril.Chin@Sun.COM			xx=x*x ,
908462SApril.Chin@Sun.COM			yy=y*y ,
918462SApril.Chin@Sun.COM			mag=xx+yy ,
928462SApril.Chin@Sun.COM			y=x*y*2+y1 ,
938462SApril.Chin@Sun.COM			x=xx-yy+x1
948462SApril.Chin@Sun.COM		))
958462SApril.Chin@Sun.COM	done
968462SApril.Chin@Sun.COM
978462SApril.Chin@Sun.COM	(( result=iteration ))
988462SApril.Chin@Sun.COM
998462SApril.Chin@Sun.COM	return 0
1008462SApril.Chin@Sun.COM}
1018462SApril.Chin@Sun.COM
1028462SApril.Chin@Sun.COM# build mandelbrot image serially
1038462SApril.Chin@Sun.COMfunction loop_serial
1048462SApril.Chin@Sun.COM{
1058462SApril.Chin@Sun.COM	integer value
106*10898Sroland.mainz@nrubsig.org	typeset line=""
1078462SApril.Chin@Sun.COM
1088462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=stepwidth )) ; do
1098462SApril.Chin@Sun.COM		for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do
1108462SApril.Chin@Sun.COM			mandelbrot value ${x} ${y} ${x} ${y} 1 ${symbollistlen}
111*10898Sroland.mainz@nrubsig.org			line+="${symbollist:value:1}"
1128462SApril.Chin@Sun.COM		done
1138462SApril.Chin@Sun.COM
114*10898Sroland.mainz@nrubsig.org		line+=$'\n'
1158462SApril.Chin@Sun.COM	done
116*10898Sroland.mainz@nrubsig.org
117*10898Sroland.mainz@nrubsig.org	print -r -- "${line}"
118*10898Sroland.mainz@nrubsig.org
1198462SApril.Chin@Sun.COM	return 0
1208462SApril.Chin@Sun.COM}
1218462SApril.Chin@Sun.COM
1228462SApril.Chin@Sun.COM# build mandelbrot image using parallel worker jobs
1238462SApril.Chin@Sun.COMfunction loop_parallel
1248462SApril.Chin@Sun.COM{
1258462SApril.Chin@Sun.COM	integer numjobs=0
1268462SApril.Chin@Sun.COM	# the following calculation suffers from rounding errors
1278462SApril.Chin@Sun.COM	integer lines_per_job=$(( ((m_height+(numcpus-1)) / numcpus) ))
128*10898Sroland.mainz@nrubsig.org	typeset tmpjobdir
1298462SApril.Chin@Sun.COM
1308462SApril.Chin@Sun.COM	printmsg $"# lines_per_job=${lines_per_job}"
1318462SApril.Chin@Sun.COM	printmsg $"# numcpus=${numcpus}"
1328462SApril.Chin@Sun.COM
1338462SApril.Chin@Sun.COM	# "renice" worker jobs
1348462SApril.Chin@Sun.COM	set -o bgnice
1358462SApril.Chin@Sun.COM
136*10898Sroland.mainz@nrubsig.org	tmpjobdir="$(mktemp --default=/tmp --directory "mandelbrotset1${PPID}_$$_XXXXXX")" || fatal_error $"Could not create temporary directory."
137*10898Sroland.mainz@nrubsig.org	trap "rm -r ${tmpjobdir}" EXIT # cleanup
1388462SApril.Chin@Sun.COM
1398462SApril.Chin@Sun.COM	# try to generate a job identifer prefix which is unique across multiple hosts
1408462SApril.Chin@Sun.COM	jobident="job_host_$(uname -n)pid_$$_ppid${PPID}"
1418462SApril.Chin@Sun.COM
1428462SApril.Chin@Sun.COM	printmsg $"## prepare..."
1438462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
144*10898Sroland.mainz@nrubsig.org		rm -f "${tmpjobdir}/${jobident}_child_$y.joboutput"
1458462SApril.Chin@Sun.COM
1468462SApril.Chin@Sun.COM		(( numjobs++ ))
1478462SApril.Chin@Sun.COM	done
1488462SApril.Chin@Sun.COM
1498462SApril.Chin@Sun.COM	printmsg $"## running ${numjobs} children..."
1508462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
1518462SApril.Chin@Sun.COM		(
1528462SApril.Chin@Sun.COM			integer value
153*10898Sroland.mainz@nrubsig.org			typeset line=""
154*10898Sroland.mainz@nrubsig.org			# save file name since we're going to modify "y"
155*10898Sroland.mainz@nrubsig.org			typeset filename="${tmpjobdir}/${jobident}_child_$y.joboutput"
1568462SApril.Chin@Sun.COM
1578462SApril.Chin@Sun.COM			for (( ; y < y_max && lines_per_job-- > 0 ; y+=stepwidth )) ; do
1588462SApril.Chin@Sun.COM				for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do
1598462SApril.Chin@Sun.COM					mandelbrot value ${x} ${y} ${x} ${y} 1 ${symbollistlen}
160*10898Sroland.mainz@nrubsig.org					line+="${symbollist:value:1}"
1618462SApril.Chin@Sun.COM				done
1628462SApril.Chin@Sun.COM
163*10898Sroland.mainz@nrubsig.org				line+=$'\n'
164*10898Sroland.mainz@nrubsig.org			done
165*10898Sroland.mainz@nrubsig.org			print -r -- "${line}" >"${filename}"
166*10898Sroland.mainz@nrubsig.org
167*10898Sroland.mainz@nrubsig.org			exit 0
1688462SApril.Chin@Sun.COM		) &
1698462SApril.Chin@Sun.COM	done
1708462SApril.Chin@Sun.COM
1718462SApril.Chin@Sun.COM	printmsg $"## waiting for ${numjobs} children..."
1728462SApril.Chin@Sun.COM	wait
1738462SApril.Chin@Sun.COM
1748462SApril.Chin@Sun.COM	printmsg $"## output:"
1758462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
176*10898Sroland.mainz@nrubsig.org		print -r -- "$( < "${tmpjobdir}/${jobident}_child_$y.joboutput")"
177*10898Sroland.mainz@nrubsig.org		# EXIT trap will cleanup temporary files
1788462SApril.Chin@Sun.COM	done
1798462SApril.Chin@Sun.COM
1808462SApril.Chin@Sun.COM	return 0
1818462SApril.Chin@Sun.COM}
1828462SApril.Chin@Sun.COM
1838462SApril.Chin@Sun.COMfunction usage
1848462SApril.Chin@Sun.COM{
1858462SApril.Chin@Sun.COM	OPTIND=0
1868462SApril.Chin@Sun.COM	getopts -a "${progname}" "${mandelbrotset1_usage}" OPT '-?'
1878462SApril.Chin@Sun.COM	exit 2
1888462SApril.Chin@Sun.COM}
1898462SApril.Chin@Sun.COM
1908462SApril.Chin@Sun.COM# main
1918462SApril.Chin@Sun.COMbuiltin basename
1928462SApril.Chin@Sun.COMbuiltin cat
1938462SApril.Chin@Sun.COMbuiltin rm
1948462SApril.Chin@Sun.COMbuiltin uname # loop_parallel needs the ksh93 builtin version to generate unique job file names
195*10898Sroland.mainz@nrubsig.orgbuiltin mktemp
196*10898Sroland.mainz@nrubsig.org
197*10898Sroland.mainz@nrubsig.orgset -o noglob
198*10898Sroland.mainz@nrubsig.orgset -o nounset
1998462SApril.Chin@Sun.COM
2008462SApril.Chin@Sun.COMtypeset progname="${ basename "${0}" ; }"
2018462SApril.Chin@Sun.COM
2028462SApril.Chin@Sun.COMfloat x_max
2038462SApril.Chin@Sun.COMfloat x_min
2048462SApril.Chin@Sun.COMfloat y_max
2058462SApril.Chin@Sun.COMfloat y_min
2068462SApril.Chin@Sun.COMfloat m_width
2078462SApril.Chin@Sun.COMfloat m_height
2088462SApril.Chin@Sun.COMfloat max_mag
2098462SApril.Chin@Sun.COMfloat stepwidth
2108462SApril.Chin@Sun.COMinteger numcpus
2118462SApril.Chin@Sun.COM
2128462SApril.Chin@Sun.COM# terminal size rect
213*10898Sroland.mainz@nrubsig.orgcompound termsize=(
2148462SApril.Chin@Sun.COM	integer columns=-1
2158462SApril.Chin@Sun.COM	integer lines=-1
2168462SApril.Chin@Sun.COM)
2178462SApril.Chin@Sun.COM
2188462SApril.Chin@Sun.COMget_term_size termsize || fatal_error $"Could not get terminal size."
2198462SApril.Chin@Sun.COM
2208462SApril.Chin@Sun.COMtypeset symbollist='    .:0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%#'
2218462SApril.Chin@Sun.COMtypeset symbollistlen=$(( ${#symbollist} - 1))
2228462SApril.Chin@Sun.COMtypeset mode="parallel"
2238462SApril.Chin@Sun.COM
2248462SApril.Chin@Sun.COMmax_mag=400
2258462SApril.Chin@Sun.COMstepwidth=0.1
2268462SApril.Chin@Sun.COMnumcpus=16
2278462SApril.Chin@Sun.COM
2288462SApril.Chin@Sun.COM(( m_width=termsize.columns-1 , m_height=termsize.lines-2 ))
2298462SApril.Chin@Sun.COM
2308462SApril.Chin@Sun.COMtypeset -r mandelbrotset1_usage=$'+
231*10898Sroland.mainz@nrubsig.org[-?\n@(#)\$Id: mandelbrotset1 (Roland Mainz) 2009-06-14 \$\n]
2328462SApril.Chin@Sun.COM[-author?Roland Mainz <roland.mainz@nrubsig.org>]
2338462SApril.Chin@Sun.COM[+NAME?mandelbrotset1 - generate mandelbrot set fractals with ksh93]
2348462SApril.Chin@Sun.COM[+DESCRIPTION?\bmandelbrotset1\b mandelbrot set fractal generator
2358462SApril.Chin@Sun.COM	which runs either in serial or parallel mode (using multiple worker jobs).]
2368462SApril.Chin@Sun.COM[w:width?Width of fractal.]:[width]
2378462SApril.Chin@Sun.COM[h:height?Height of fractal.]:[height]
2388462SApril.Chin@Sun.COM[s:symbols?Symbols to build the fractal from.]:[symbolstring]
2398462SApril.Chin@Sun.COM[m:mag?Magnification level.]:[magnificationlevel]
2408462SApril.Chin@Sun.COM[p:stepwidth?Width per step.]:[widthperstep]
2418462SApril.Chin@Sun.COM[S:serial?Run in serial mode.]
2428462SApril.Chin@Sun.COM[P:parallel?Run in parallel mode.]
2438462SApril.Chin@Sun.COM[M:mode?Execution mode.]:[mode]
2448462SApril.Chin@Sun.COM[C:numcpus?Number of processors used for parallel execution.]:[numcpus]
2458462SApril.Chin@Sun.COM[+SEE ALSO?\bjuliaset1\b(1), \bksh93\b(1)]
2468462SApril.Chin@Sun.COM'
2478462SApril.Chin@Sun.COM
2488462SApril.Chin@Sun.COMwhile getopts -a "${progname}" "${mandelbrotset1_usage}" OPT ; do
2498462SApril.Chin@Sun.COM#	printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
2508462SApril.Chin@Sun.COM	case ${OPT} in
2518462SApril.Chin@Sun.COM		w)	m_width="${OPTARG}"	;;
2528462SApril.Chin@Sun.COM		h)	m_height="${OPTARG}"	;;
2538462SApril.Chin@Sun.COM		s)	symbollist="${OPTARG}"	;;
2548462SApril.Chin@Sun.COM		m)	max_mag="${OPTARG}"	;;
2558462SApril.Chin@Sun.COM		p)	stepwidth="${OPTARG}"	;;
2568462SApril.Chin@Sun.COM		S)	mode="serial"		;;
257*10898Sroland.mainz@nrubsig.org		+S)	mode="parallel"		;;
2588462SApril.Chin@Sun.COM		P)	mode="parallel"		;;
259*10898Sroland.mainz@nrubsig.org		+P)	mode="serial"		;;
2608462SApril.Chin@Sun.COM		M)	mode="${OPTARG}"	;;
2618462SApril.Chin@Sun.COM		C)	numcpus="${OPTARG}"	;;
2628462SApril.Chin@Sun.COM		*)	usage			;;
2638462SApril.Chin@Sun.COM	esac
2648462SApril.Chin@Sun.COMdone
2658462SApril.Chin@Sun.COMshift $((OPTIND-1))
2668462SApril.Chin@Sun.COM
2678462SApril.Chin@Sun.COMprintmsg "# width=${m_width}"
2688462SApril.Chin@Sun.COMprintmsg "# height=${m_height}"
2698462SApril.Chin@Sun.COMprintmsg "# max_mag=${max_mag}"
2708462SApril.Chin@Sun.COMprintmsg "# stepwidth=${stepwidth}"
2718462SApril.Chin@Sun.COMprintmsg "# symbollist='${symbollist}'"
2728462SApril.Chin@Sun.COMprintmsg "# mode=${mode}"
2738462SApril.Chin@Sun.COM
2748462SApril.Chin@Sun.COM(( symbollistlen=${#symbollist}-1 ))
2758462SApril.Chin@Sun.COM
2768462SApril.Chin@Sun.COM((
2778462SApril.Chin@Sun.COM	x_max=m_width*stepwidth/2. ,
2788462SApril.Chin@Sun.COM	x_min=-x_max ,
2798462SApril.Chin@Sun.COM	y_max=m_height*stepwidth/2. ,
2808462SApril.Chin@Sun.COM	y_min=-y_max
2818462SApril.Chin@Sun.COM))
2828462SApril.Chin@Sun.COM
2838462SApril.Chin@Sun.COMcase "${mode}" in
2848462SApril.Chin@Sun.COM	parallel)	loop_parallel	; exit $? ;;
2858462SApril.Chin@Sun.COM	serial)		loop_serial	; exit $? ;;
2868462SApril.Chin@Sun.COM	*)		fatal_error $"Unknown mode \"${mode}\"." ;;
2878462SApril.Chin@Sun.COMesac
2888462SApril.Chin@Sun.COM
2898462SApril.Chin@Sun.COMfatal_error "not reached."
2908462SApril.Chin@Sun.COM# EOF.
291