1*8462SApril.Chin@Sun.COM#!/usr/bin/ksh93
2*8462SApril.Chin@Sun.COM
3*8462SApril.Chin@Sun.COM#
4*8462SApril.Chin@Sun.COM# CDDL HEADER START
5*8462SApril.Chin@Sun.COM#
6*8462SApril.Chin@Sun.COM# The contents of this file are subject to the terms of the
7*8462SApril.Chin@Sun.COM# Common Development and Distribution License (the "License").
8*8462SApril.Chin@Sun.COM# You may not use this file except in compliance with the License.
9*8462SApril.Chin@Sun.COM#
10*8462SApril.Chin@Sun.COM# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11*8462SApril.Chin@Sun.COM# or http://www.opensolaris.org/os/licensing.
12*8462SApril.Chin@Sun.COM# See the License for the specific language governing permissions
13*8462SApril.Chin@Sun.COM# and limitations under the License.
14*8462SApril.Chin@Sun.COM#
15*8462SApril.Chin@Sun.COM# When distributing Covered Code, include this CDDL HEADER in each
16*8462SApril.Chin@Sun.COM# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17*8462SApril.Chin@Sun.COM# If applicable, add the following below this CDDL HEADER, with the
18*8462SApril.Chin@Sun.COM# fields enclosed by brackets "[]" replaced with your own identifying
19*8462SApril.Chin@Sun.COM# information: Portions Copyright [yyyy] [name of copyright owner]
20*8462SApril.Chin@Sun.COM#
21*8462SApril.Chin@Sun.COM# CDDL HEADER END
22*8462SApril.Chin@Sun.COM#
23*8462SApril.Chin@Sun.COM
24*8462SApril.Chin@Sun.COM#
25*8462SApril.Chin@Sun.COM# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
26*8462SApril.Chin@Sun.COM# Use is subject to license terms.
27*8462SApril.Chin@Sun.COM#
28*8462SApril.Chin@Sun.COM
29*8462SApril.Chin@Sun.COM#
30*8462SApril.Chin@Sun.COM# mandelbrotset1 - a simple mandelbrot set generation and
31*8462SApril.Chin@Sun.COM# parallel execution demo
32*8462SApril.Chin@Sun.COM#
33*8462SApril.Chin@Sun.COM
34*8462SApril.Chin@Sun.COM# Solaris needs /usr/xpg6/bin:/usr/xpg4/bin because the tools in /usr/bin are not POSIX-conformant
35*8462SApril.Chin@Sun.COMexport PATH=/usr/xpg6/bin:/usr/xpg4/bin:/bin:/usr/bin
36*8462SApril.Chin@Sun.COM
37*8462SApril.Chin@Sun.COM# Make sure all math stuff runs in the "C" locale to avoid problems
38*8462SApril.Chin@Sun.COM# with alternative # radix point representations (e.g. ',' instead of
39*8462SApril.Chin@Sun.COM# '.' in de_DE.*-locales). This needs to be set _before_ any
40*8462SApril.Chin@Sun.COM# floating-point constants are defined in this script).
41*8462SApril.Chin@Sun.COMif [[ "${LC_ALL}" != "" ]] ; then
42*8462SApril.Chin@Sun.COM    export \
43*8462SApril.Chin@Sun.COM        LC_MONETARY="${LC_ALL}" \
44*8462SApril.Chin@Sun.COM        LC_MESSAGES="${LC_ALL}" \
45*8462SApril.Chin@Sun.COM        LC_COLLATE="${LC_ALL}" \
46*8462SApril.Chin@Sun.COM        LC_CTYPE="${LC_ALL}"
47*8462SApril.Chin@Sun.COM        unset LC_ALL
48*8462SApril.Chin@Sun.COMfi
49*8462SApril.Chin@Sun.COMexport LC_NUMERIC=C
50*8462SApril.Chin@Sun.COM
51*8462SApril.Chin@Sun.COMfunction printmsg
52*8462SApril.Chin@Sun.COM{
53*8462SApril.Chin@Sun.COM	print -u2 "$*"
54*8462SApril.Chin@Sun.COM}
55*8462SApril.Chin@Sun.COM
56*8462SApril.Chin@Sun.COMfunction fatal_error
57*8462SApril.Chin@Sun.COM{
58*8462SApril.Chin@Sun.COM	print -u2 "${progname}: $*"
59*8462SApril.Chin@Sun.COM	exit 1
60*8462SApril.Chin@Sun.COM}
61*8462SApril.Chin@Sun.COM
62*8462SApril.Chin@Sun.COM# Get terminal size and put values into a compound variable with the integer
63*8462SApril.Chin@Sun.COM# members "columns" and "lines"
64*8462SApril.Chin@Sun.COMfunction get_term_size
65*8462SApril.Chin@Sun.COM{
66*8462SApril.Chin@Sun.COM	nameref rect=$1
67*8462SApril.Chin@Sun.COM
68*8462SApril.Chin@Sun.COM	rect.columns=${ tput cols ; } || return 1
69*8462SApril.Chin@Sun.COM	rect.lines=${ tput lines ; }  || return 1
70*8462SApril.Chin@Sun.COM
71*8462SApril.Chin@Sun.COM	return 0
72*8462SApril.Chin@Sun.COM}
73*8462SApril.Chin@Sun.COM
74*8462SApril.Chin@Sun.COMfunction print_color
75*8462SApril.Chin@Sun.COM{
76*8462SApril.Chin@Sun.COM	print -r -n -- "${symbollist:${1}:1}"
77*8462SApril.Chin@Sun.COM	return 0
78*8462SApril.Chin@Sun.COM}
79*8462SApril.Chin@Sun.COM
80*8462SApril.Chin@Sun.COMfunction mandelbrot
81*8462SApril.Chin@Sun.COM{
82*8462SApril.Chin@Sun.COM	nameref result=$1
83*8462SApril.Chin@Sun.COM	float   x=$2
84*8462SApril.Chin@Sun.COM	float   y=$3
85*8462SApril.Chin@Sun.COM	float   xx
86*8462SApril.Chin@Sun.COM	float   yy
87*8462SApril.Chin@Sun.COM	float   x1=$4
88*8462SApril.Chin@Sun.COM	float   y1=$5
89*8462SApril.Chin@Sun.COM	integer iteration=$6
90*8462SApril.Chin@Sun.COM	integer max_iteration=$7
91*8462SApril.Chin@Sun.COM	float   mag
92*8462SApril.Chin@Sun.COM
93*8462SApril.Chin@Sun.COM	for (( mag=0 ; mag < max_mag && iteration < max_iteration ; iteration++ )) ; do
94*8462SApril.Chin@Sun.COM		((
95*8462SApril.Chin@Sun.COM			xx=x*x ,
96*8462SApril.Chin@Sun.COM			yy=y*y ,
97*8462SApril.Chin@Sun.COM			mag=xx+yy ,
98*8462SApril.Chin@Sun.COM			y=x*y*2+y1 ,
99*8462SApril.Chin@Sun.COM			x=xx-yy+x1
100*8462SApril.Chin@Sun.COM		))
101*8462SApril.Chin@Sun.COM	done
102*8462SApril.Chin@Sun.COM
103*8462SApril.Chin@Sun.COM	(( result=iteration ))
104*8462SApril.Chin@Sun.COM
105*8462SApril.Chin@Sun.COM	return 0
106*8462SApril.Chin@Sun.COM}
107*8462SApril.Chin@Sun.COM
108*8462SApril.Chin@Sun.COM# build mandelbrot image serially
109*8462SApril.Chin@Sun.COMfunction loop_serial
110*8462SApril.Chin@Sun.COM{
111*8462SApril.Chin@Sun.COM	integer value
112*8462SApril.Chin@Sun.COM
113*8462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=stepwidth )) ; do
114*8462SApril.Chin@Sun.COM		for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do
115*8462SApril.Chin@Sun.COM			mandelbrot value ${x} ${y} ${x} ${y} 1 ${symbollistlen}
116*8462SApril.Chin@Sun.COM			print_color ${value}
117*8462SApril.Chin@Sun.COM		done
118*8462SApril.Chin@Sun.COM
119*8462SApril.Chin@Sun.COM		print
120*8462SApril.Chin@Sun.COM	done
121*8462SApril.Chin@Sun.COM
122*8462SApril.Chin@Sun.COM	return 0
123*8462SApril.Chin@Sun.COM}
124*8462SApril.Chin@Sun.COM
125*8462SApril.Chin@Sun.COM# build mandelbrot image using parallel worker jobs
126*8462SApril.Chin@Sun.COMfunction loop_parallel
127*8462SApril.Chin@Sun.COM{
128*8462SApril.Chin@Sun.COM	integer numjobs=0
129*8462SApril.Chin@Sun.COM	# the following calculation suffers from rounding errors
130*8462SApril.Chin@Sun.COM	integer lines_per_job=$(( ((m_height+(numcpus-1)) / numcpus) ))
131*8462SApril.Chin@Sun.COM
132*8462SApril.Chin@Sun.COM	printmsg $"# lines_per_job=${lines_per_job}"
133*8462SApril.Chin@Sun.COM	printmsg $"# numcpus=${numcpus}"
134*8462SApril.Chin@Sun.COM
135*8462SApril.Chin@Sun.COM	# "renice" worker jobs
136*8462SApril.Chin@Sun.COM	set -o bgnice
137*8462SApril.Chin@Sun.COM
138*8462SApril.Chin@Sun.COM	if [[ "${TMPDIR}" == "" ]] ; then
139*8462SApril.Chin@Sun.COM		TMPDIR="/tmp"
140*8462SApril.Chin@Sun.COM	fi
141*8462SApril.Chin@Sun.COM
142*8462SApril.Chin@Sun.COM	# try to generate a job identifer prefix which is unique across multiple hosts
143*8462SApril.Chin@Sun.COM	jobident="job_host_$(uname -n)pid_$$_ppid${PPID}"
144*8462SApril.Chin@Sun.COM
145*8462SApril.Chin@Sun.COM	printmsg $"## prepare..."
146*8462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
147*8462SApril.Chin@Sun.COM		rm -f "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput"
148*8462SApril.Chin@Sun.COM
149*8462SApril.Chin@Sun.COM		(( numjobs++ ))
150*8462SApril.Chin@Sun.COM	done
151*8462SApril.Chin@Sun.COM
152*8462SApril.Chin@Sun.COM	printmsg $"## running ${numjobs} children..."
153*8462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
154*8462SApril.Chin@Sun.COM		(
155*8462SApril.Chin@Sun.COM			integer value
156*8462SApril.Chin@Sun.COM
157*8462SApril.Chin@Sun.COM			for (( ; y < y_max && lines_per_job-- > 0 ; y+=stepwidth )) ; do
158*8462SApril.Chin@Sun.COM				for (( x=x_min ; x < x_max ; x+=stepwidth )) ; do
159*8462SApril.Chin@Sun.COM					mandelbrot value ${x} ${y} ${x} ${y} 1 ${symbollistlen}
160*8462SApril.Chin@Sun.COM					print_color ${value}
161*8462SApril.Chin@Sun.COM				done
162*8462SApril.Chin@Sun.COM
163*8462SApril.Chin@Sun.COM				print
164*8462SApril.Chin@Sun.COM			done >"${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput"
165*8462SApril.Chin@Sun.COM		) &
166*8462SApril.Chin@Sun.COM	done
167*8462SApril.Chin@Sun.COM
168*8462SApril.Chin@Sun.COM	printmsg $"## waiting for ${numjobs} children..."
169*8462SApril.Chin@Sun.COM	wait
170*8462SApril.Chin@Sun.COM
171*8462SApril.Chin@Sun.COM	printmsg $"## output:"
172*8462SApril.Chin@Sun.COM	for (( y=y_min ; y < y_max ; y+=(stepwidth*lines_per_job) )) ; do
173*8462SApril.Chin@Sun.COM		print -- "$( < "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput")"
174*8462SApril.Chin@Sun.COM		rm "${TMPDIR}/mandelbrot_${jobident}_child_$y.joboutput"
175*8462SApril.Chin@Sun.COM	done
176*8462SApril.Chin@Sun.COM
177*8462SApril.Chin@Sun.COM	return 0
178*8462SApril.Chin@Sun.COM}
179*8462SApril.Chin@Sun.COM
180*8462SApril.Chin@Sun.COMfunction usage
181*8462SApril.Chin@Sun.COM{
182*8462SApril.Chin@Sun.COM	OPTIND=0
183*8462SApril.Chin@Sun.COM	getopts -a "${progname}" "${mandelbrotset1_usage}" OPT '-?'
184*8462SApril.Chin@Sun.COM	exit 2
185*8462SApril.Chin@Sun.COM}
186*8462SApril.Chin@Sun.COM
187*8462SApril.Chin@Sun.COM# main
188*8462SApril.Chin@Sun.COMbuiltin basename
189*8462SApril.Chin@Sun.COMbuiltin cat
190*8462SApril.Chin@Sun.COMbuiltin rm
191*8462SApril.Chin@Sun.COMbuiltin uname # loop_parallel needs the ksh93 builtin version to generate unique job file names
192*8462SApril.Chin@Sun.COM
193*8462SApril.Chin@Sun.COMtypeset progname="${ basename "${0}" ; }"
194*8462SApril.Chin@Sun.COM
195*8462SApril.Chin@Sun.COMfloat x_max
196*8462SApril.Chin@Sun.COMfloat x_min
197*8462SApril.Chin@Sun.COMfloat y_max
198*8462SApril.Chin@Sun.COMfloat y_min
199*8462SApril.Chin@Sun.COMfloat m_width
200*8462SApril.Chin@Sun.COMfloat m_height
201*8462SApril.Chin@Sun.COMfloat max_mag
202*8462SApril.Chin@Sun.COMfloat stepwidth
203*8462SApril.Chin@Sun.COMinteger numcpus
204*8462SApril.Chin@Sun.COM
205*8462SApril.Chin@Sun.COM# terminal size rect
206*8462SApril.Chin@Sun.COMtypeset -C termsize=(
207*8462SApril.Chin@Sun.COM	integer columns=-1
208*8462SApril.Chin@Sun.COM	integer lines=-1
209*8462SApril.Chin@Sun.COM)
210*8462SApril.Chin@Sun.COM
211*8462SApril.Chin@Sun.COMget_term_size termsize || fatal_error $"Could not get terminal size."
212*8462SApril.Chin@Sun.COM
213*8462SApril.Chin@Sun.COMtypeset symbollist='    .:0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%#'
214*8462SApril.Chin@Sun.COMtypeset symbollistlen=$(( ${#symbollist} - 1))
215*8462SApril.Chin@Sun.COMtypeset mode="parallel"
216*8462SApril.Chin@Sun.COM
217*8462SApril.Chin@Sun.COMmax_mag=400
218*8462SApril.Chin@Sun.COMstepwidth=0.1
219*8462SApril.Chin@Sun.COMnumcpus=16
220*8462SApril.Chin@Sun.COM
221*8462SApril.Chin@Sun.COM(( m_width=termsize.columns-1 , m_height=termsize.lines-2 ))
222*8462SApril.Chin@Sun.COM
223*8462SApril.Chin@Sun.COMtypeset -r mandelbrotset1_usage=$'+
224*8462SApril.Chin@Sun.COM[-?\n@(#)\$Id: mandelbrotset1 (Roland Mainz) 2008-11-04 \$\n]
225*8462SApril.Chin@Sun.COM[-author?Roland Mainz <roland.mainz@nrubsig.org>]
226*8462SApril.Chin@Sun.COM[+NAME?mandelbrotset1 - generate mandelbrot set fractals with ksh93]
227*8462SApril.Chin@Sun.COM[+DESCRIPTION?\bmandelbrotset1\b mandelbrot set fractal generator
228*8462SApril.Chin@Sun.COM	which runs either in serial or parallel mode (using multiple worker jobs).]
229*8462SApril.Chin@Sun.COM[w:width?Width of fractal.]:[width]
230*8462SApril.Chin@Sun.COM[h:height?Height of fractal.]:[height]
231*8462SApril.Chin@Sun.COM[s:symbols?Symbols to build the fractal from.]:[symbolstring]
232*8462SApril.Chin@Sun.COM[m:mag?Magnification level.]:[magnificationlevel]
233*8462SApril.Chin@Sun.COM[p:stepwidth?Width per step.]:[widthperstep]
234*8462SApril.Chin@Sun.COM[S:serial?Run in serial mode.]
235*8462SApril.Chin@Sun.COM[P:parallel?Run in parallel mode.]
236*8462SApril.Chin@Sun.COM[M:mode?Execution mode.]:[mode]
237*8462SApril.Chin@Sun.COM[C:numcpus?Number of processors used for parallel execution.]:[numcpus]
238*8462SApril.Chin@Sun.COM[+SEE ALSO?\bjuliaset1\b(1), \bksh93\b(1)]
239*8462SApril.Chin@Sun.COM'
240*8462SApril.Chin@Sun.COM
241*8462SApril.Chin@Sun.COMwhile getopts -a "${progname}" "${mandelbrotset1_usage}" OPT ; do
242*8462SApril.Chin@Sun.COM#	printmsg "## OPT=|${OPT}|, OPTARG=|${OPTARG}|"
243*8462SApril.Chin@Sun.COM	case ${OPT} in
244*8462SApril.Chin@Sun.COM		w)	m_width="${OPTARG}"	;;
245*8462SApril.Chin@Sun.COM		h)	m_height="${OPTARG}"	;;
246*8462SApril.Chin@Sun.COM		s)	symbollist="${OPTARG}"	;;
247*8462SApril.Chin@Sun.COM		m)	max_mag="${OPTARG}"	;;
248*8462SApril.Chin@Sun.COM		p)	stepwidth="${OPTARG}"	;;
249*8462SApril.Chin@Sun.COM		S)	mode="serial"		;;
250*8462SApril.Chin@Sun.COM		P)	mode="parallel"		;;
251*8462SApril.Chin@Sun.COM		M)	mode="${OPTARG}"	;;
252*8462SApril.Chin@Sun.COM		C)	numcpus="${OPTARG}"	;;
253*8462SApril.Chin@Sun.COM		*)	usage			;;
254*8462SApril.Chin@Sun.COM	esac
255*8462SApril.Chin@Sun.COMdone
256*8462SApril.Chin@Sun.COMshift $((OPTIND-1))
257*8462SApril.Chin@Sun.COM
258*8462SApril.Chin@Sun.COMprintmsg "# width=${m_width}"
259*8462SApril.Chin@Sun.COMprintmsg "# height=${m_height}"
260*8462SApril.Chin@Sun.COMprintmsg "# max_mag=${max_mag}"
261*8462SApril.Chin@Sun.COMprintmsg "# stepwidth=${stepwidth}"
262*8462SApril.Chin@Sun.COMprintmsg "# symbollist='${symbollist}'"
263*8462SApril.Chin@Sun.COMprintmsg "# mode=${mode}"
264*8462SApril.Chin@Sun.COM
265*8462SApril.Chin@Sun.COM(( symbollistlen=${#symbollist}-1 ))
266*8462SApril.Chin@Sun.COM
267*8462SApril.Chin@Sun.COM((
268*8462SApril.Chin@Sun.COM	x_max=m_width*stepwidth/2. ,
269*8462SApril.Chin@Sun.COM	x_min=-x_max ,
270*8462SApril.Chin@Sun.COM	y_max=m_height*stepwidth/2. ,
271*8462SApril.Chin@Sun.COM	y_min=-y_max
272*8462SApril.Chin@Sun.COM))
273*8462SApril.Chin@Sun.COM
274*8462SApril.Chin@Sun.COMcase "${mode}" in
275*8462SApril.Chin@Sun.COM	parallel)	loop_parallel	; exit $? ;;
276*8462SApril.Chin@Sun.COM	serial)		loop_serial	; exit $? ;;
277*8462SApril.Chin@Sun.COM	*)		fatal_error $"Unknown mode \"${mode}\"." ;;
278*8462SApril.Chin@Sun.COMesac
279*8462SApril.Chin@Sun.COM
280*8462SApril.Chin@Sun.COMfatal_error "not reached."
281*8462SApril.Chin@Sun.COM# EOF.
282