1 |
#!/usr/bin/env sh |
2 |
|
3 |
############################################################################## |
4 |
# |
5 |
# Copyright (c) 2003-2016 by The University of Queensland |
6 |
# http://www.uq.edu.au |
7 |
# |
8 |
# Primary Business: Queensland, Australia |
9 |
# Licensed under the Apache License, version 2.0 |
10 |
# http://www.apache.org/licenses/LICENSE-2.0 |
11 |
# |
12 |
# Development until 2012 by Earth Systems Science Computational Center (ESSCC) |
13 |
# Development 2012-2013 by School of Earth Sciences |
14 |
# Development from 2014 by Centre for Geoscience Computing (GeoComp) |
15 |
# |
16 |
############################################################################## |
17 |
|
18 |
# Escript wrapper for python |
19 |
# Sets LD_LIBRARY_PATH and PYTHONPATH and then runs either python or the MPI |
20 |
# launcher. |
21 |
|
22 |
# Extra paths can be configured about a page further down |
23 |
# Search for EXTRA_PATH="" |
24 |
|
25 |
# set to 1 if this is part of a packaged build (.deb) and files will be |
26 |
# installed in standard locations rather than everything in a single directory |
27 |
STDLOCATION=0 |
28 |
|
29 |
# Now we find the location of this script |
30 |
# Note that this location should be absolute but does not need to be unique |
31 |
scriptdir="" |
32 |
CURDIR=$(pwd) |
33 |
|
34 |
# Environment vars which control operations: |
35 |
# ESCRIPT_NUM_NODES, ESCRIPT_NUM_PROCS, ESCRIPT_NUM_THREADS, ESCRIPT_HOSTFILE, ESCRIPT_CREATESTDFILES |
36 |
|
37 |
HOSTFILE=/tmp/escript.$USER.$$ |
38 |
|
39 |
die () { |
40 |
echo "Error: $@" 1>&2 |
41 |
exit 1 |
42 |
} |
43 |
|
44 |
#Begin finding ESCRIPT_ROOT |
45 |
if [ $STDLOCATION -ne 0 ] |
46 |
then |
47 |
#Package building scripts will replace this line |
48 |
ESCRIPT_ROOT=/usr/lib/python-escript |
49 |
else |
50 |
# We don't know the escript root so we need to work it out from the invocation |
51 |
# Need to match if the name contains / |
52 |
if $(echo $0|grep -q /) |
53 |
then |
54 |
# We are not using the PATH to find the script |
55 |
cd "$(dirname $0)" |
56 |
scriptdir=$(pwd) |
57 |
cd "$CURDIR" |
58 |
else |
59 |
# name does not contain / therefore we are using |
60 |
tscriptdir=$(which $0) |
61 |
if [ $? -ne 0 ] |
62 |
then |
63 |
die "Unable to determine script directory!" |
64 |
fi |
65 |
scriptdir=$(dirname $tscriptdir) |
66 |
fi |
67 |
|
68 |
cd "$scriptdir/.." |
69 |
ESCRIPT_ROOT=$(pwd) |
70 |
cd .. |
71 |
ESCRIPT_PARENT=$(pwd) |
72 |
cd "$CURDIR" |
73 |
|
74 |
fi |
75 |
##### End finding ESCRIPT_ROOT ######## |
76 |
|
77 |
# if possible please express paths relative to $ESCRIPT_ROOT unless |
78 |
# they are in an unrelated location |
79 |
|
80 |
EXTRA_DYLD_LIBRARY_PATH="" |
81 |
EXTRA_PATH=$ESCRIPT_ROOT/bin |
82 |
EXTRA_PYTHONPATH=$ESCRIPT_ROOT |
83 |
|
84 |
if [ $STDLOCATION -eq 1 ] |
85 |
then |
86 |
EXTRA_LD_LIBRARY_PATH=$ESCRIPT_ROOT/lib |
87 |
else |
88 |
EXTRA_LD_LIBRARY_PATH=$ESCRIPT_ROOT/lib |
89 |
fi |
90 |
|
91 |
BUILDINFO_FILE="$ESCRIPT_ROOT/lib/buildvars" |
92 |
if [ ! -r "$BUILDINFO_FILE" ]; then |
93 |
if [ "$1" = "-e" ]; then |
94 |
echo "export LD_LIBRARY_PATH=$EXTRA_LD_LIBRARY_PATH:\$LD_LIBRARY_PATH" |
95 |
echo "export PYTHONPATH=$EXTRA_PYTHONPATH:\$PYTHONPATH" |
96 |
echo "export PATH=$EXTRA_PATH:\$PATH" |
97 |
if [ "$(uname)" = "Darwin" ] |
98 |
then |
99 |
echo "export DYLD_LIBRARY_PATH=$EXTRA_DYLD_LIBRARY_PATH:$EXTRA_LD_LIBRARY_PATH:\$DYLD_LIBRARY_PATH" |
100 |
fi |
101 |
exit 0 |
102 |
fi |
103 |
die "Unable to read escript build information!" |
104 |
fi |
105 |
|
106 |
get_buildvar () { |
107 |
echo $(grep "^$1=" "$BUILDINFO_FILE" |cut -d= -f2) |
108 |
} |
109 |
|
110 |
PYTHON_MPI_NULL="$ESCRIPT_ROOT/lib/pythonMPI" |
111 |
PYTHON_MPI_REDIRECT="$ESCRIPT_ROOT/lib/pythonMPIredirect" |
112 |
PYTHON_CMD=$(get_buildvar python) |
113 |
|
114 |
HELP_TEXT=" |
115 |
Usage: run-escript [options] script.py [arguments...] |
116 |
-n nn number of nodes to use |
117 |
-p np number of MPI processes to spawn per node |
118 |
-t nt number of OpenMP threads to use |
119 |
-f file name of MPI hostfile |
120 |
-c print compile information for escript and exit |
121 |
-V print escript version and exit |
122 |
-i interactive mode |
123 |
-b do not invoke python (run non-python programs) |
124 |
-e print export statements for environment and exit |
125 |
-o redirect output from MPI to files |
126 |
-v print diagnostics |
127 |
-x run in new xterm instance |
128 |
-m tool run with valgrind {tool=m[emcheck]/c[allgrind]/[cac]h[egrind]} |
129 |
script.py Your python script |
130 |
arguments... The optional command-line arguments to your script |
131 |
" |
132 |
|
133 |
if [ "$1" = "--help" ]; then |
134 |
echo "$HELP_TEXT" |
135 |
exit 0 |
136 |
fi |
137 |
#============================================================================== |
138 |
|
139 |
# Parse the command-line options |
140 |
while getopts 'bn:p:t:f:echim:oVvx' option |
141 |
do |
142 |
case "$option" in |
143 |
"b") DO_BINARY=y |
144 |
;; |
145 |
"m") DO_VALGRIND=$OPTARG |
146 |
;; |
147 |
"n") ESCRIPT_NUM_NODES=$OPTARG |
148 |
;; |
149 |
"p") ESCRIPT_NUM_PROCS=$OPTARG |
150 |
;; |
151 |
"t") ESCRIPT_NUM_THREADS=$OPTARG |
152 |
;; |
153 |
"f") ESCRIPT_HOSTFILE=$OPTARG |
154 |
;; |
155 |
"c") cat "$BUILDINFO_FILE" |
156 |
exit 0 |
157 |
;; |
158 |
"V") echo "escript-development(build "$(get_buildvar svn_revision)")" |
159 |
exit 0 |
160 |
;; |
161 |
"h") echo "$HELP_TEXT" |
162 |
exit 0 |
163 |
;; |
164 |
"i") DO_INTERACTIVE=y |
165 |
;; |
166 |
"e") echo "export LD_LIBRARY_PATH=$EXTRA_LD_LIBRARY_PATH:\$LD_LIBRARY_PATH" |
167 |
echo "export PYTHONPATH=$EXTRA_PYTHONPATH:\$PYTHONPATH" |
168 |
echo "export PATH=$EXTRA_PATH:\$PATH" |
169 |
if [ "$(uname)" = "Darwin" ] |
170 |
then |
171 |
echo "export DYLD_LIBRARY_PATH=$EXTRA_DYLD_LIBRARY_PATH:$EXTRA_LD_LIBRARY_PATH:\$DYLD_LIBRARY_PATH" |
172 |
fi |
173 |
exit 0 |
174 |
;; |
175 |
"o") ESCRIPT_CREATESTDFILES=y |
176 |
;; |
177 |
"v") ESCRIPT_VERBOSE=y |
178 |
;; |
179 |
"x") DO_XTERM=y |
180 |
;; |
181 |
?) echo "$HELP_TEXT" |
182 |
exit 1 |
183 |
;; |
184 |
esac |
185 |
done |
186 |
shift $(($OPTIND - 1)) |
187 |
|
188 |
vlog () { |
189 |
if [ ! -z $ESCRIPT_VERBOSE ]; then |
190 |
echo "$@" |
191 |
fi |
192 |
} |
193 |
|
194 |
#============================================== |
195 |
# |
196 |
# Read MPI_FLAVOUR and WITH_OPENMP from the buildvars |
197 |
# |
198 |
MPI_FLAVOUR=$(get_buildvar mpi) |
199 |
WITH_OPENMP=$(get_buildvar openmp) |
200 |
|
201 |
vlog "MPI flavour is $MPI_FLAVOUR." |
202 |
if [ "$WITH_OPENMP" = "1" ]; then |
203 |
vlog "OpenMP enabled." |
204 |
else |
205 |
vlog "OpenMP disabled." |
206 |
fi |
207 |
|
208 |
# |
209 |
# Add VisIt paths if required |
210 |
# |
211 |
WITH_VISIT=$(get_buildvar visit) |
212 |
if [ "$WITH_VISIT" = "1" ]; then |
213 |
VISIT_BIN=$(which visit 2>/dev/null) |
214 |
if [ $? -eq 0 ]; then |
215 |
VISIT_PY_PATH=$($VISIT_BIN -env | grep LIBPATH | cut -d= -f2) |
216 |
EXTRA_PYTHONPATH=$EXTRA_PYTHONPATH:$VISIT_PY_PATH |
217 |
EXTRA_LD_LIBRARY_PATH=$EXTRA_LD_LIBRARY_PATH:$VISIT_PY_PATH |
218 |
else |
219 |
vlog "Warning: VisIt module enabled but VisIt not in path!" |
220 |
fi |
221 |
fi |
222 |
|
223 |
# |
224 |
# extend path variables |
225 |
# |
226 |
export PATH=$EXTRA_PATH:$PATH |
227 |
export LD_LIBRARY_PATH=$EXTRA_LD_LIBRARY_PATH:$LD_LIBRARY_PATH |
228 |
export PYTHONPATH=$EXTRA_PYTHONPATH:$PYTHONPATH |
229 |
EXPORT_ENV="PATH,LD_LIBRARY_PATH,PYTHONPATH" |
230 |
if [ "$(uname)" = "Darwin" ] |
231 |
then |
232 |
export DYLD_LIBRARY_PATH=$EXTRA_DYLD_LIBRARY_PATH:$EXTRA_LD_LIBRARY_PATH:$DYLD_LIBRARY_PATH |
233 |
EXPORT_ENV="$EXPORT_ENV,DYLD_LIBRARY_PATH" |
234 |
fi |
235 |
vlog "PATH = $PATH |
236 |
LD_LIBRARY_PATH = $LD_LIBRARY_PATH |
237 |
PYTHONPATH = $PYTHONPATH" |
238 |
if [ ! -z $DYLD_LIBRARY_PATH ]; then |
239 |
vlog "DYLD_LIBRARY_PATH = $DYLD_LIBRARY_PATH" |
240 |
fi |
241 |
|
242 |
#============================================== |
243 |
# |
244 |
# Ensure the variables have sensible values |
245 |
# |
246 |
if [ "$MPI_FLAVOUR" = "none" ] |
247 |
then |
248 |
if [ ! -z "$ESCRIPT_NUM_NODES" ]; then |
249 |
if [ $ESCRIPT_NUM_NODES -gt 1 ]; then |
250 |
echo "Warning: MPI disabled but number of nodes set. Option ignored." |
251 |
fi |
252 |
fi |
253 |
if [ ! -z "$ESCRIPT_NUM_PROCS" ]; then |
254 |
if [ $ESCRIPT_NUM_PROCS -gt 1 ]; then |
255 |
echo "Warning: MPI disabled but number of processors per node set. Option ignored." |
256 |
fi |
257 |
fi |
258 |
if [ ! -z "$ESCRIPT_HOSTFILE" ] |
259 |
then |
260 |
echo "Warning: MPI disabled but host file is given. Option ignored." |
261 |
fi |
262 |
ESCRIPT_NUM_NODES=1 |
263 |
ESCRIPT_NUM_PROCS=1 |
264 |
else |
265 |
# use the PBS_NODEFILE if not otherwise specified |
266 |
if [ ! -z "$PBS_NODEFILE" ] && [ -z "$ESCRIPT_HOSTFILE" ] |
267 |
then |
268 |
ESCRIPT_HOSTFILE=$PBS_NODEFILE |
269 |
fi |
270 |
|
271 |
if [ ! -z "$ESCRIPT_HOSTFILE" ] |
272 |
then |
273 |
if [ -f "$ESCRIPT_HOSTFILE" ] |
274 |
then |
275 |
sort -u "${ESCRIPT_HOSTFILE}" > $HOSTFILE |
276 |
HOSTLIST=$(awk 'BEGIN{S=""}{if (S == "") { S = $0 } else {S = S "," $0}}END{print S}' "$HOSTFILE") |
277 |
|
278 |
NUM_HOSTS=$(cat "$HOSTFILE" | wc -l) |
279 |
if [ ! -z $ESCRIPT_NUM_NODES ] |
280 |
then |
281 |
if [ $NUM_HOSTS -lt $ESCRIPT_NUM_NODES ] |
282 |
then |
283 |
die "Number of requested nodes must not exceed the number of entries selected in the host file $ESCRIPT_HOSTFILE. You asked for $ESCRIPT_NUM_NODES from $NUM_HOSTS." |
284 |
fi |
285 |
else |
286 |
ESCRIPT_NUM_NODES=$NUM_HOSTS |
287 |
fi |
288 |
else |
289 |
die "Cannot find hostfile $ESCRIPT_HOSTFILE!" |
290 |
fi |
291 |
else |
292 |
echo "localhost" > $HOSTFILE |
293 |
HOSTLIST="localhost" |
294 |
fi |
295 |
|
296 |
if [ -z $ESCRIPT_NUM_NODES ] |
297 |
then |
298 |
ESCRIPT_NUM_NODES=1 |
299 |
fi |
300 |
|
301 |
if [ -z $ESCRIPT_NUM_PROCS ] |
302 |
then |
303 |
ESCRIPT_NUM_PROCS=1 |
304 |
fi |
305 |
|
306 |
vlog "ESCRIPT_NUM_NODES = $ESCRIPT_NUM_NODES\nESCRIPT_NUM_PROCS = $ESCRIPT_NUM_PROCS" |
307 |
fi |
308 |
|
309 |
if [ "$WITH_OPENMP" = "1" ] |
310 |
then |
311 |
if [ -z $ESCRIPT_NUM_THREADS ] |
312 |
then |
313 |
ESCRIPT_NUM_THREADS=$OMP_NUM_THREADS |
314 |
if [ -z $ESCRIPT_NUM_THREADS ] |
315 |
then |
316 |
ESCRIPT_NUM_THREADS=1 |
317 |
fi |
318 |
fi |
319 |
vlog "ESCRIPT_NUM_THREADS = $ESCRIPT_NUM_THREADS" |
320 |
else |
321 |
if [ ! -z $ESCRIPT_NUM_THREADS ] && [ $ESCRIPT_NUM_THREADS != 1 ] |
322 |
then |
323 |
echo "Warning: OpenMP is disabled but number of threads requested is $ESCRIPT_NUM_THREADS!=1. Option ignored." |
324 |
fi |
325 |
ESCRIPT_NUM_THREADS=1 |
326 |
fi |
327 |
|
328 |
# |
329 |
# Now we compute total number of Processes |
330 |
# |
331 |
TOTPROC=$((ESCRIPT_NUM_NODES * ESCRIPT_NUM_PROCS)) |
332 |
if [ $? -ne 0 ] #Some compute error |
333 |
then #This could happen if the args were not a number |
334 |
die "Expression of total number of processors = $ESCRIPT_NUM_NODES * $ESCRIPT_NUM_PROCS is not numerical!" |
335 |
fi |
336 |
|
337 |
# set up thread binding if unset -- disabled by default because it interfers |
338 |
# with MPI binding |
339 |
#if [ "$OMP_PROC_BIND" = "" ]; then |
340 |
# #Force OpenMP binding for Intel (and GCC, though GCC is on by default) |
341 |
# export OMP_PROC_BIND=true |
342 |
#fi |
343 |
#if [ "$KMP_AFFINITY" = "" ]; then |
344 |
# #Set the style of binding (overrides OMP_PROC_BIND in many cases) |
345 |
# export KMP_AFFINITY=verbose,compact |
346 |
#fi |
347 |
|
348 |
# |
349 |
# Test to ensure people aren't trying to combine interactive and multi-process |
350 |
# |
351 |
if ([ ! -z $DO_INTERACTIVE ] || [ $# -eq 0 ]) && ([ $TOTPROC -gt 1 ]) |
352 |
then |
353 |
die "Interactive mode cannot be used with more than one process!" |
354 |
fi |
355 |
|
356 |
if [ $TOTPROC -gt 1 ] |
357 |
then |
358 |
if [ "$ESCRIPT_CREATESTDFILES" = "y" ] |
359 |
then |
360 |
PYTHON_MPI=$PYTHON_MPI_REDIRECT |
361 |
else |
362 |
PYTHON_MPI=$PYTHON_MPI_NULL |
363 |
fi |
364 |
else |
365 |
PYTHON_MPI=$PYTHON_MPI_NULL |
366 |
fi |
367 |
#============================================================================== |
368 |
# Must have at least one command-line arg: the python script |
369 |
if [ $# -eq 0 ] |
370 |
then |
371 |
if [ ! -z $DO_BINARY ] |
372 |
then |
373 |
die "No program to run was specified!" |
374 |
else |
375 |
DO_INTERACTIVE=y |
376 |
fi |
377 |
fi |
378 |
|
379 |
#============================================================================== |
380 |
|
381 |
if [ ! -z $DO_XTERM ] |
382 |
then |
383 |
EXEC_CMD="xterm -e" |
384 |
else |
385 |
EXEC_CMD="" |
386 |
fi |
387 |
|
388 |
if [ ! -z "$DO_VALGRIND" ] |
389 |
then |
390 |
VALGRIND_BIN=$(which valgrind 2>/dev/null) |
391 |
if [ $? -eq 0 ]; then |
392 |
LOGDIR=$ESCRIPT_ROOT/valgrind_logs |
393 |
[ -d $LOGDIR ] || mkdir $LOGDIR |
394 |
VG_TOOL=$(echo $DO_VALGRIND | awk '{ s=substr($0,1,1);print s;}') |
395 |
if [ $VG_TOOL = "c" ]; |
396 |
then |
397 |
# run callgrind |
398 |
LOGFILE=${LOGDIR}/callgrind.%p.xml |
399 |
VALGRIND="valgrind --tool=callgrind --callgrind-out-file=$LOGFILE" |
400 |
EXEC_CMD="$EXEC_CMD $VALGRIND" |
401 |
elif [ $VG_TOOL = "h" ]; |
402 |
then |
403 |
# run cachegrind |
404 |
LOGFILE=${LOGDIR}/cachegrind.%p.xml |
405 |
VALGRIND="valgrind --tool=cachegrind --cachegrind-out-file=$LOGFILE" |
406 |
EXEC_CMD="$EXEC_CMD $VALGRIND" |
407 |
else |
408 |
# run memcheck by default |
409 |
LAST_N=$(ls -1 $LOGDIR|grep "^memcheck"|tail -1|cut -d. -f2) |
410 |
NEW_N=$(printf "%04d" $((LAST_N + 1))) |
411 |
LOGFILE=${LOGDIR}/memcheck.${NEW_N}.%p.xml |
412 |
VALGRIND="valgrind --tool=memcheck --xml=yes --show-reachable=yes --error-limit=no --suppressions=$ESCRIPT_ROOT/scripts/escript.supp --leak-check=full --xml-file=$LOGFILE" |
413 |
EXEC_CMD="$EXEC_CMD $VALGRIND" |
414 |
fi |
415 |
else |
416 |
die "Execution with valgrind requested but valgrind not in path!" |
417 |
fi |
418 |
fi |
419 |
|
420 |
if [ ! -z $DO_BINARY ] |
421 |
then |
422 |
EXEC_CMD="$EXEC_CMD $@" |
423 |
else |
424 |
# Check to see if the python version we were compiled with matches the |
425 |
# one of PYTHON_CMD. |
426 |
compfull=$(get_buildvar python_version) |
427 |
compversion=$(echo $compfull | cut -d. -f1,2) |
428 |
compmajor=$(echo $compfull | cut -d. -f1) |
429 |
if [ "$PYTHON_CMD" = "python" ] # if people have customised the command they |
430 |
then # might not want us changing it |
431 |
if [ "$compmajor" = "3" ] |
432 |
then |
433 |
PYTHON_CMD=python3 |
434 |
fi |
435 |
fi |
436 |
intversion=$($PYTHON_CMD -c 'from __future__ import print_function;import sys;print("%d.%d"%(sys.version_info[0], sys.version_info[1]))') |
437 |
if [ "$compversion" != "$intversion" ] |
438 |
then |
439 |
die "Python versions do not match. Escript was compiled for '$compversion'. |
440 |
Current version of Python appears to be '$intversion'." |
441 |
fi |
442 |
if [ "$MPI_FLAVOUR" = "none" ] |
443 |
then |
444 |
if [ ! -z $DO_INTERACTIVE ] |
445 |
then |
446 |
EXEC_CMD="$EXEC_CMD $PYTHON_CMD -i $@" |
447 |
else |
448 |
EXEC_CMD="$EXEC_CMD $PYTHON_CMD $@" |
449 |
fi |
450 |
else |
451 |
if [ ! -z $DO_INTERACTIVE ] |
452 |
then |
453 |
EXEC_CMD="$EXEC_CMD $PYTHON_MPI -i $@" |
454 |
else |
455 |
EXEC_CMD="$EXEC_CMD $PYTHON_MPI $@" |
456 |
fi |
457 |
fi |
458 |
fi |
459 |
vlog "Command to be executed is \"$EXEC_CMD\"" |
460 |
#============================================================================== |
461 |
# |
462 |
# now we start to spawn things: |
463 |
# |
464 |
if [ "$WITH_OPENMP" = "1" ] |
465 |
then |
466 |
export OMP_NUM_THREADS=$ESCRIPT_NUM_THREADS |
467 |
EXPORT_ENV="$EXPORT_ENV,OMP_NUM_THREADS" |
468 |
fi |
469 |
|
470 |
if [ "$MPI_FLAVOUR" = "OPENMPI" ] |
471 |
then |
472 |
if [ -z `which rsh``which ssh` ] |
473 |
then |
474 |
AGENTOVERRIDE="--gmca plm_rsh_agent /bin/false" |
475 |
fi |
476 |
fi |
477 |
|
478 |
vlog "Pre-launch command: \"@@PRELAUNCH\"" |
479 |
@@PRELAUNCH |
480 |
vlog "Launch command: \"@@LAUNCH\"" |
481 |
@@LAUNCH |
482 |
EXIT_CODE=$? |
483 |
vlog "Post-launch command: \"@@POSTLAUNCH\"" |
484 |
@@POSTLAUNCH |
485 |
|
486 |
if [ ! -z "$DO_VALGRIND" ]; then |
487 |
echo "Valgrind log file written to ${LOGFILE}" |
488 |
fi |
489 |
|
490 |
rm -f $HOSTFILE |
491 |
|
492 |
exit $EXIT_CODE |
493 |
|