xref: /onnv-gate/usr/src/lib/libshell/common/scripts/mandelbrotset1.sh (revision 12068:08a39a083754)
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*12068SRoger.Faulkner@Oracle.COM# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
268462SApril.Chin@Sun.COM#
278462SApril.Chin@Sun.COM
288462SApril.Chin@Sun.COM#
298462SApril.Chin@Sun.COM# mandelbrotset1 - a simple mandelbrot set generation and
308462SApril.Chin@Sun.COM# parallel execution demo
318462SApril.Chin@Sun.COM#
328462SApril.Chin@Sun.COM
338462SApril.Chin@Sun.COM# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
348462SApril.Chin@Sun.COMexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
358462SApril.Chin@Sun.COM
368462SApril.Chin@Sun.COM# Make sure all math stuff runs in the "C" locale to avoid problems
378462SApril.Chin@Sun.COM# with alternative # radix point representations (e.g. ',' instead of
388462SApril.Chin@Sun.COM# '.' in de_DE.*-locales). This needs to be set _before_ any
398462SApril.Chin@Sun.COM# floating-point constants are defined in this script).
408462SApril.Chin@Sun.COMif [[ "${LC_ALL}" != "" ]] ; then
418462SApril.Chin@Sun.COM    export \
428462SApril.Chin@Sun.COM        LC_MONETARY="${LC_ALL}" \
438462SApril.Chin@Sun.COM        LC_MESSAGES="${LC_ALL}" \
448462SApril.Chin@Sun.COM        LC_COLLATE="${LC_ALL}" \
458462SApril.Chin@Sun.COM        LC_CTYPE="${LC_ALL}"
468462SApril.Chin@Sun.COM        unset LC_ALL
478462SApril.Chin@Sun.COMfi
488462SApril.Chin@Sun.COMexport LC_NUMERIC=C
498462SApril.Chin@Sun.COM
508462SApril.Chin@Sun.COMfunction printmsg
518462SApril.Chin@Sun.COM{
528462SApril.Chin@Sun.COM	print -u2 "$*"
538462SApril.Chin@Sun.COM}
548462SApril.Chin@Sun.COM
558462SApril.Chin@Sun.COMfunction fatal_error
568462SApril.Chin@Sun.COM{
578462SApril.Chin@Sun.COM	print -u2 "${progname}: $*"
588462SApril.Chin@Sun.COM	exit 1
598462SApril.Chin@Sun.COM}
608462SApril.Chin@Sun.COM
618462SApril.Chin@Sun.COM# Get terminal size and put values into a compound variable with the integer
628462SApril.Chin@Sun.COM# members "columns" and "lines"
638462SApril.Chin@Sun.COMfunction get_term_size
648462SApril.Chin@Sun.COM{
658462SApril.Chin@Sun.COM	nameref rect=$1
668462SApril.Chin@Sun.COM
678462SApril.Chin@Sun.COM	rect.columns=${ tput cols ; } || return 1
688462SApril.Chin@Sun.COM	rect.lines=${ tput lines ; }  || return 1
698462SApril.Chin@Sun.COM
708462SApril.Chin@Sun.COM	return 0
718462SApril.Chin@Sun.COM}
728462SApril.Chin@Sun.COM
738462SApril.Chin@Sun.COMfunction mandelbrot
748462SApril.Chin@Sun.COM{
758462SApril.Chin@Sun.COM	nameref result=$1
768462SApril.Chin@Sun.COM	float   x=$2
778462SApril.Chin@Sun.COM	float   y=$3
788462SApril.Chin@Sun.COM	float   xx
798462SApril.Chin@Sun.COM	float   yy
808462SApril.Chin@Sun.COM	float   x1=$4
818462SApril.Chin@Sun.COM	float   y1=$5
828462SApril.Chin@Sun.COM	integer iteration=$6
838462SApril.Chin@Sun.COM	integer max_iteration=$7
848462SApril.Chin@Sun.COM	float   mag
858462SApril.Chin@Sun.COM
868462SApril.Chin@Sun.COM	for (( mag=0 ; mag < max_mag && iteration < max_iteration ; iteration++ )) ; do
878462SApril.Chin@Sun.COM		((
888462SApril.Chin@Sun.COM			xx=x*x ,
898462SApril.Chin@Sun.COM			yy=y*y ,
908462SApril.Chin@Sun.COM			mag=xx+yy ,
918462SApril.Chin@Sun.COM			y=x*y*2+y1 ,
928462SApril.Chin@Sun.COM			x=xx-yy+x1
938462SApril.Chin@Sun.COM		))
948462SApril.Chin@Sun.COM	done
958462SApril.Chin@Sun.COM
968462SApril.Chin@Sun.COM	(( result=iteration ))
978462SApril.Chin@Sun.COM
988462SApril.Chin@Sun.COM	return 0
998462SApril.Chin@Sun.COM}
1008462SApril.Chin@Sun.COM
1018462SApril.Chin@Sun.COM# build mandelbrot image serially
1028462SApril.Chin@Sun.COMfunction loop_serial
1038462SApril.Chin@Sun.COM{
1048462SApril.Chin@Sun.COM	integer value
10510898Sroland.mainz@nrubsig.org	typeset line=""
1068462SApril.Chin@Sun.COM
1078462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=stepwidth )) ; do
1088462SApril.Chin@Sun.COM		for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do
1098462SApril.Chin@Sun.COM			mandelbrot value ${x} ${y} ${x} ${y} 1 ${symbollistlen}
11010898Sroland.mainz@nrubsig.org			line+="${symbollist:value:1}"
1118462SApril.Chin@Sun.COM		done
1128462SApril.Chin@Sun.COM
11310898Sroland.mainz@nrubsig.org		line+=$'\n'
1148462SApril.Chin@Sun.COM	done
11510898Sroland.mainz@nrubsig.org
11610898Sroland.mainz@nrubsig.org	print -r -- "${line}"
11710898Sroland.mainz@nrubsig.org
1188462SApril.Chin@Sun.COM	return 0
1198462SApril.Chin@Sun.COM}
1208462SApril.Chin@Sun.COM
1218462SApril.Chin@Sun.COM# build mandelbrot image using parallel worker jobs
1228462SApril.Chin@Sun.COMfunction loop_parallel
1238462SApril.Chin@Sun.COM{
1248462SApril.Chin@Sun.COM	integer numjobs=0
1258462SApril.Chin@Sun.COM	# the following calculation suffers from rounding errors
1268462SApril.Chin@Sun.COM	integer lines_per_job=$(( ((m_height+(numcpus-1)) / numcpus) ))
12710898Sroland.mainz@nrubsig.org	typeset tmpjobdir
1288462SApril.Chin@Sun.COM
1298462SApril.Chin@Sun.COM	printmsg $"# lines_per_job=${lines_per_job}"
1308462SApril.Chin@Sun.COM	printmsg $"# numcpus=${numcpus}"
1318462SApril.Chin@Sun.COM
1328462SApril.Chin@Sun.COM	# "renice" worker jobs
1338462SApril.Chin@Sun.COM	set -o bgnice
1348462SApril.Chin@Sun.COM
13510898Sroland.mainz@nrubsig.org	tmpjobdir="$(mktemp --default=/tmp --directory "mandelbrotset1${PPID}_$$_XXXXXX")" || fatal_error $"Could not create temporary directory."
13610898Sroland.mainz@nrubsig.org	trap "rm -r ${tmpjobdir}" EXIT # cleanup
1378462SApril.Chin@Sun.COM
1388462SApril.Chin@Sun.COM	# try to generate a job identifer prefix which is unique across multiple hosts
1398462SApril.Chin@Sun.COM	jobident="job_host_$(uname -n)pid_$$_ppid${PPID}"
1408462SApril.Chin@Sun.COM
1418462SApril.Chin@Sun.COM	printmsg $"## prepare..."
1428462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
14310898Sroland.mainz@nrubsig.org		rm -f "${tmpjobdir}/${jobident}_child_$y.joboutput"
1448462SApril.Chin@Sun.COM
1458462SApril.Chin@Sun.COM		(( numjobs++ ))
1468462SApril.Chin@Sun.COM	done
1478462SApril.Chin@Sun.COM
1488462SApril.Chin@Sun.COM	printmsg $"## running ${numjobs} children..."
1498462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
1508462SApril.Chin@Sun.COM		(
1518462SApril.Chin@Sun.COM			integer value
15210898Sroland.mainz@nrubsig.org			typeset line=""
15310898Sroland.mainz@nrubsig.org			# save file name since we're going to modify "y"
15410898Sroland.mainz@nrubsig.org			typeset filename="${tmpjobdir}/${jobident}_child_$y.joboutput"
1558462SApril.Chin@Sun.COM
1568462SApril.Chin@Sun.COM			for (( ; y < y_max && lines_per_job-- > 0 ; y+=stepwidth )) ; do
1578462SApril.Chin@Sun.COM				for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do
1588462SApril.Chin@Sun.COM					mandelbrot value ${x} ${y} ${x} ${y} 1 ${symbollistlen}
15910898Sroland.mainz@nrubsig.org					line+="${symbollist:value:1}"
1608462SApril.Chin@Sun.COM				done
1618462SApril.Chin@Sun.COM
16210898Sroland.mainz@nrubsig.org				line+=$'\n'
16310898Sroland.mainz@nrubsig.org			done
16410898Sroland.mainz@nrubsig.org			print -r -- "${line}" >"${filename}"
16510898Sroland.mainz@nrubsig.org
16610898Sroland.mainz@nrubsig.org			exit 0
1678462SApril.Chin@Sun.COM		) &
1688462SApril.Chin@Sun.COM	done
1698462SApril.Chin@Sun.COM
1708462SApril.Chin@Sun.COM	printmsg $"## waiting for ${numjobs} children..."
1718462SApril.Chin@Sun.COM	wait
1728462SApril.Chin@Sun.COM
1738462SApril.Chin@Sun.COM	printmsg $"## output:"
1748462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
17510898Sroland.mainz@nrubsig.org		print -r -- "$( < "${tmpjobdir}/${jobident}_child_$y.joboutput")"
17610898Sroland.mainz@nrubsig.org		# EXIT trap will cleanup temporary files
1778462SApril.Chin@Sun.COM	done
1788462SApril.Chin@Sun.COM
1798462SApril.Chin@Sun.COM	return 0
1808462SApril.Chin@Sun.COM}
1818462SApril.Chin@Sun.COM
1828462SApril.Chin@Sun.COMfunction usage
1838462SApril.Chin@Sun.COM{
1848462SApril.Chin@Sun.COM	OPTIND=0
1858462SApril.Chin@Sun.COM	getopts -a "${progname}" "${mandelbrotset1_usage}" OPT '-?'
1868462SApril.Chin@Sun.COM	exit 2
1878462SApril.Chin@Sun.COM}
1888462SApril.Chin@Sun.COM
1898462SApril.Chin@Sun.COM# main
1908462SApril.Chin@Sun.COMbuiltin basename
1918462SApril.Chin@Sun.COMbuiltin cat
1928462SApril.Chin@Sun.COMbuiltin rm
1938462SApril.Chin@Sun.COMbuiltin uname # loop_parallel needs the ksh93 builtin version to generate unique job file names
19410898Sroland.mainz@nrubsig.orgbuiltin mktemp
19510898Sroland.mainz@nrubsig.org
19610898Sroland.mainz@nrubsig.orgset -o noglob
19710898Sroland.mainz@nrubsig.orgset -o nounset
1988462SApril.Chin@Sun.COM
1998462SApril.Chin@Sun.COMtypeset progname="${ basename "${0}" ; }"
2008462SApril.Chin@Sun.COM
2018462SApril.Chin@Sun.COMfloat x_max
2028462SApril.Chin@Sun.COMfloat x_min
2038462SApril.Chin@Sun.COMfloat y_max
2048462SApril.Chin@Sun.COMfloat y_min
2058462SApril.Chin@Sun.COMfloat m_width
2068462SApril.Chin@Sun.COMfloat m_height
2078462SApril.Chin@Sun.COMfloat max_mag
2088462SApril.Chin@Sun.COMfloat stepwidth
2098462SApril.Chin@Sun.COMinteger numcpus
2108462SApril.Chin@Sun.COM
2118462SApril.Chin@Sun.COM# terminal size rect
21210898Sroland.mainz@nrubsig.orgcompound termsize=(
2138462SApril.Chin@Sun.COM	integer columns=-1
2148462SApril.Chin@Sun.COM	integer lines=-1
2158462SApril.Chin@Sun.COM)
2168462SApril.Chin@Sun.COM
2178462SApril.Chin@Sun.COMget_term_size termsize || fatal_error $"Could not get terminal size."
2188462SApril.Chin@Sun.COM
2198462SApril.Chin@Sun.COMtypeset symbollist='    .:0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%#'
2208462SApril.Chin@Sun.COMtypeset symbollistlen=$(( ${#symbollist} - 1))
2218462SApril.Chin@Sun.COMtypeset mode="parallel"
2228462SApril.Chin@Sun.COM
223*12068SRoger.Faulkner@Oracle.COM(( max_mag=400 ))
224*12068SRoger.Faulkner@Oracle.COM(( stepwidth=0.1 ))
225*12068SRoger.Faulkner@Oracle.COM
226*12068SRoger.Faulkner@Oracle.COM# calculate number of worker CPUs and use 3 as fallback
227*12068SRoger.Faulkner@Oracle.COM(( numcpus=$(getconf NPROCESSORS_ONLN || print "3") ))
228*12068SRoger.Faulkner@Oracle.COM(( numcpus=numcpus*4 ))
2298462SApril.Chin@Sun.COM
2308462SApril.Chin@Sun.COM(( m_width=termsize.columns-1 , m_height=termsize.lines-2 ))
2318462SApril.Chin@Sun.COM
2328462SApril.Chin@Sun.COMtypeset -r mandelbrotset1_usage=$'+
233*12068SRoger.Faulkner@Oracle.COM[-?\n@(#)\$Id: mandelbrotset1 (Roland Mainz) 2010-03-31 \$\n]
2348462SApril.Chin@Sun.COM[-author?Roland Mainz <roland.mainz@nrubsig.org>]
2358462SApril.Chin@Sun.COM[+NAME?mandelbrotset1 - generate mandelbrot set fractals with ksh93]
2368462SApril.Chin@Sun.COM[+DESCRIPTION?\bmandelbrotset1\b mandelbrot set fractal generator
2378462SApril.Chin@Sun.COM	which runs either in serial or parallel mode (using multiple worker jobs).]
2388462SApril.Chin@Sun.COM[w:width?Width of fractal.]:[width]
2398462SApril.Chin@Sun.COM[h:height?Height of fractal.]:[height]
2408462SApril.Chin@Sun.COM[s:symbols?Symbols to build the fractal from.]:[symbolstring]
2418462SApril.Chin@Sun.COM[m:mag?Magnification level.]:[magnificationlevel]
2428462SApril.Chin@Sun.COM[p:stepwidth?Width per step.]:[widthperstep]
2438462SApril.Chin@Sun.COM[S:serial?Run in serial mode.]
2448462SApril.Chin@Sun.COM[P:parallel?Run in parallel mode.]
2458462SApril.Chin@Sun.COM[M:mode?Execution mode.]:[mode]
2468462SApril.Chin@Sun.COM[C:numcpus?Number of processors used for parallel execution.]:[numcpus]
2478462SApril.Chin@Sun.COM[+SEE ALSO?\bjuliaset1\b(1), \bksh93\b(1)]
2488462SApril.Chin@Sun.COM'
2498462SApril.Chin@Sun.COM
2508462SApril.Chin@Sun.COMwhile getopts -a "${progname}" "${mandelbrotset1_usage}" OPT ; do
2518462SApril.Chin@Sun.COM#	printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
2528462SApril.Chin@Sun.COM	case ${OPT} in
2538462SApril.Chin@Sun.COM		w)	m_width="${OPTARG}"	;;
2548462SApril.Chin@Sun.COM		h)	m_height="${OPTARG}"	;;
2558462SApril.Chin@Sun.COM		s)	symbollist="${OPTARG}"	;;
2568462SApril.Chin@Sun.COM		m)	max_mag="${OPTARG}"	;;
2578462SApril.Chin@Sun.COM		p)	stepwidth="${OPTARG}"	;;
2588462SApril.Chin@Sun.COM		S)	mode="serial"		;;
25910898Sroland.mainz@nrubsig.org		+S)	mode="parallel"		;;
2608462SApril.Chin@Sun.COM		P)	mode="parallel"		;;
26110898Sroland.mainz@nrubsig.org		+P)	mode="serial"		;;
2628462SApril.Chin@Sun.COM		M)	mode="${OPTARG}"	;;
2638462SApril.Chin@Sun.COM		C)	numcpus="${OPTARG}"	;;
2648462SApril.Chin@Sun.COM		*)	usage			;;
2658462SApril.Chin@Sun.COM	esac
2668462SApril.Chin@Sun.COMdone
2678462SApril.Chin@Sun.COMshift $((OPTIND-1))
2688462SApril.Chin@Sun.COM
2698462SApril.Chin@Sun.COMprintmsg "# width=${m_width}"
2708462SApril.Chin@Sun.COMprintmsg "# height=${m_height}"
2718462SApril.Chin@Sun.COMprintmsg "# max_mag=${max_mag}"
2728462SApril.Chin@Sun.COMprintmsg "# stepwidth=${stepwidth}"
2738462SApril.Chin@Sun.COMprintmsg "# symbollist='${symbollist}'"
2748462SApril.Chin@Sun.COMprintmsg "# mode=${mode}"
2758462SApril.Chin@Sun.COM
2768462SApril.Chin@Sun.COM(( symbollistlen=${#symbollist}-1 ))
2778462SApril.Chin@Sun.COM
2788462SApril.Chin@Sun.COM((
2798462SApril.Chin@Sun.COM	x_max=m_width*stepwidth/2. ,
2808462SApril.Chin@Sun.COM	x_min=-x_max ,
2818462SApril.Chin@Sun.COM	y_max=m_height*stepwidth/2. ,
2828462SApril.Chin@Sun.COM	y_min=-y_max
2838462SApril.Chin@Sun.COM))
2848462SApril.Chin@Sun.COM
2858462SApril.Chin@Sun.COMcase "${mode}" in
2868462SApril.Chin@Sun.COM	parallel)	loop_parallel	; exit $? ;;
2878462SApril.Chin@Sun.COM	serial)		loop_serial	; exit $? ;;
2888462SApril.Chin@Sun.COM	*)		fatal_error $"Unknown mode \"${mode}\"." ;;
2898462SApril.Chin@Sun.COMesac
2908462SApril.Chin@Sun.COM
2918462SApril.Chin@Sun.COMfatal_error "not reached."
2928462SApril.Chin@Sun.COM# EOF.
293