Swift とは JVM 上で動くスクリプト言語だという事は知っています。
非常に有名なプログラミング言語であるにも関わらず、しかし事前知識はそれだけで他のことは全く知りませんでした。
こんな有名なプログラミング言語を知らないなんて、それは少し恥ずかしいな思い立って、プログラミング言語 Swift を調べてみます。少しずついくつかの記事にかに分けて調べていってみようと思います。
目次はこちら
■ Swift のチュートリアル
色々寄り道をしましたがようやくチュートリアルです。チュートリアルを修めて Swift を完全に理解しましょう。
公式サイトのページはこちらです。
swift-lang.org
■ Swift のインストールフォルダ
チュートリアルでの (というか標準のインストール手順でも) 準備として Swift コマンドのあるフォルダを PATH に追加するように書かれています。
けれどもどうも、追加しなくても良さそうなのでそのまま進めていきましょう。今回は Swift コマンドは
/mnt/c/Swift/cmd/bin/swift
に置きました。
■ まずはバージョンの確認
まずはチュートリアルの動作のバージョンが設定されているとのことで、バージョンの確認方法が書かれています。
$ swift -version
チュートリアルの動作バージョンは java 1.7 以上と swift-0.96 とのことです。チュートリアルには書いていませんが、せっかくなので Java と Swift 両方のバージョンを見てみましょう。
$ java --version openjdk 17.0.6 2023-01-17 LTS OpenJDK Runtime Environment Microsoft-7209853 (build 17.0.6+10-LTS) OpenJDK 64-Bit Server VM Microsoft-7209853 (build 17.0.6+10-LTS, mixed mode, sharing)
$ /mnt/c/Swift/cmd/bin/swift --version Swift 0.96.2 git-rev: b9611649002eecd640fc6c58bbb88cb35ce03539 heads/release-0.96-swift 6287
問題なさそうですね。
■ チュートリアルのリソースをダウンロード
チュートリアル用のリソースを段ロードします。git から clone するか zip をダウンロードするか、どちらも良いとのこと。今回は作ったばかりの環境で git も整えていなので、zip をダウンロードしてみます。
git の場合の取得元
https://github.com/swift-lang/swift-tutorial.git
zip の場合の取得元
https://github.com/swift-lang/swift-tutorial/archive/master.zip
zip 取得のコマンド
zip 取得は次のコマンドが案内されています。
wget https://github.com/swift-lang/swift-tutorial/archive/master.zip unzip master.zip mv swift-tutorial-master swift-tutorial cd swift-tutorial
このコマンド、最初の 1 行目がダウンロードで、2 行目が zip の展開です。この 1 行目は成功しますが、2 行目は失敗してしまいました。
Command 'unzip' not found, but can be installed with: sudo apt install unzip
*unzip** コマンドをインストールせよと。今回は面倒なので Windows で展開しました。( WSL でやっているので、ファイルをそれなりに色々と整った Windows から操作できる環境でやっています )
展開した後の 3 行目でフォルダのリネームをしているのですが、Windows 標準の展開でチュートリアルの想定をフォルダ構成が変わったので、この辺りも整えて続けていきます。
4 行目でディレクトリを移動して次のステップへ進みます。
mv swift-tutorial-master swift-tutorial cd swift-tutorial
■ チュートリアルのセットアップ
ここで Swift の環境構築とは別にチュートリアルのセットアップが必要とのこと。次のコマンドです。
source setup.sh
ちょっと setup.sh の中を見てみましょう。
######################### CONFIGS ########################### export BEAGLE_USERNAME="" export BEAGLE_PROJECT="" export MIDWAY_USERNAME="" export AWS_CREDENTIALS_FILE="" export URL_OF_AD_HOC_MACHINE_1="" export AD_HOC_1_USERNAME="" export AD_HOC_N_USERNAME="" export OSG_USERNAME="" export OSG_PROJECT="" export BLUES_USERNAME="" export CLOUD_HEADNODE="http://HEADNODE_ADDRESS:50010" ############################################################# # ensure that this script is being sourced if [ ${BASH_VERSINFO[0]} -gt 2 -a "${BASH_SOURCE[0]}" = "${0}" ] ; then echo ERROR: script ${BASH_SOURCE[0]} must be executed as: source ${BASH_SOURCE[0]} exit 1 fi # Setting scripts folder to the PATH env var. TUTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" if [ _$(which cleanup 2>/dev/null) != _$TUTDIR/bin/cleanup ]; then echo Adding $TUTDIR/bin:$TUTDIR/app: to front of PATH PATH=$TUTDIR/bin:$TUTDIR/app:$PATH else echo Assuming $TUTDIR/bin:$TUTDIR/app: is already at front of PATH fi # Set PATH for specific hosts if hostname | grep bridges; then module load java # Get Oracle Java 1.8.x SWIFT=/home/wilde/swift/rev/swift-0.96.2 PATH=$SWIFT/bin:$JAVA:$PATH module unload mpi/intel_mpi module load mpi/gcc_mvapich export CC="mpicc" echo "modules adjusted: unloaded mpi/intel_mpi; loaded mpi/gcc_mvapich" echo "This list should should show mpi/gcc_mvapich as only MPI:" module list elif hostname -f | grep "edison" ; then echo "Configuring for Edison" module swap PrgEnv-intel PrgEnv-gnu export PATH=$PWD/part07:$PATH export CC="cc" pushd . cd part07/ ; make clean ; make popd pushd . cd part08/ ; rm hipi make clean ; make popd elif hostname -f | grep "ncsa.illinois.edu" ; then # BW does not have a clearly identifiable hostname on the login nodes module load java # Oracle java java/jdk1.8.0_51 module unload PrgEnv-cray/5.2.82 module load PrgEnv-gnu/5.2.82 SWIFT=~wilde/scratch/swift/rev/swift-0.96.2 PATH=$SWIFT/bin:$PATH export CC="cc" elif hostname | grep comet; then JAVA=/oasis/scratch/comet/xdtr1/temp_project/jdk1.8.0_91/bin SWIFT=/oasis/scratch/comet/xdtr1/temp_project/swift/swift-0.96.2/bin PATH=$SWIFT:$JAVA:$PATH elif hostname | grep workflow.iu; then SWIFT=/opt/swift/swift-0.96.2/bin JAVA=$(echo /opt/swift/jdk1.*/bin) PATH=$SWIFT:$JAVA:$PATH export X509_USER_PROXY=/tmp/x509.$USER.$RANDOM elif [ -d /usr/local/bin/swift-trunk ] && [ -d /usr/local/bin/jdk1.7.0_51 ]; then JAVA=/usr/local/bin/jdk1.7.0_51/bin SWIFT=/usr/local/bin/swift-trunk/bin PATH=$JAVA:$SWIFT:$PATH elif [ -d /opt/swift/swift-0.96.1 ] && [ -d /opt/swift/jdk1.7.0_51 ] then export SWIFT=/opt/swift/swift-0.96.1/bin export JAVA=/opt/swift/jdk1.7.0_51/bin export PATH=$SWIFT:$JAVA:$PATH export X509_USER_PROXY=/tmp/x509.$USER.$RANDOM fi echo "Swift version is $(swift -version)" return
重い。あと .sh ファイルなので当然ですが、Windows で動かす気ありませんね? チュートリアルの動作条件に書いてないようですが。Swift 自体はマルチプラットドームで Windows でも動作する言っていただけに少し残念です。いいんですけど。WSL あるし。
■ チュートリアルの概要
チュートリアルは何かを書いて動かしていくスタイルではなく、用意されたプログラムを解説を読みながら実行していくスタイルです。先ほど取得したリソースにもチュートリアルのステップごとにフォルダが用意されています。
$ ls -l /mnt/c/Swift/swift-tutorial/ total 56 -rwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 10 Dec 14 2016 README.asc drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 app drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 bin drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 doc -rwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 23795 Dec 14 2016 ec2.asc -rwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 441 Dec 14 2016 local.conf drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 mandelbrot drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 mpi -rwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 6079 Dec 14 2016 nersc.conf drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 part01 drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 part02 drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 part03 drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 part04 drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 part05 drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 part06 drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 part07 drwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 4096 Feb 12 17:07 part08 -rwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 2979 Dec 14 2016 setup.sh -rwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 14509 Dec 14 2016 swift.conf -rwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 1842 Dec 14 2016 test_all.sh -rwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 8052 Dec 14 2016 xsede.conf
part01 ~ part10 のディレクトリですね。参考に一つ目 part01 の中を見てみましょう。
l$ ls -l /mnt/c/Swift/swift-tutorial/part01/ total 0 -rwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 113 Dec 14 2016 p1.swift -rwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 13 Dec 14 2016 swift.conf
Swift のプログラムと .conf ファイルが入っています。それぞれ見てみましょう。
p1.swift
type file; app (file o) simulation () { simulate stdout=filename(o); } file f <"sim.out">; f = simulation();
swift.conf
../local.conf
p1.swift は simulate コマンドを実行して sim.out ファイルに書き込むプログラムですね。
swift.conf は別の .conf ファイルを読んでいます。こちらも見てみましょう。
../local.conf
sites: [localhost] site.localhost { execution { type: "local" URL : "localhost" } staging : direct workDirectory : "/tmp/"${env.USER}"/swiftwork" maxParallelTasks : 20 initialParallelTasks: 20 app.ALL { executable: "*" } } TCPPortRange: "50000,51000" lazyErrors: false executionRetries: 0 keepSiteDir: true providerStagingPinSwiftFiles: false alwaysTransferWrapperLog: true
どうも .conf はリモート実行の設定をするようですね。今回のこれはローカル実行みたいですね。
■ simulate コマンド
ここで simulate コマンドとは? というところですが、 .sh ファイルのようです。チュートリアルのリソースの app フォルダの中にいます。このフォルダは先の setup.sh でパスに追加される手筈のようですね。
環境のコマンドをそのまま実行できてしまう。Swift なかなか便利そうですね。
$ ls -l /mnt/c/Swift/swift-tutorial/app/simulate.sh -rwxrwxrwx 1 XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX 3076 Dec 14 2016 /mnt/c/Swift/swift-tutorial/app/simulate.sh
simulate.sh
#! /bin/bash sleep 1 printparams() { printf "\nSimulation parameters:\n\n" echo bias=$bias echo biasfile=$biasfile echo initseed=$initseed echo log=$log echo paramfile=$paramfile echo range=$range echo scale=$scale echo seedfile=$seedfile echo timesteps=$timesteps echo output width=$width } log() { printf "\nCalled as: $0: $cmdargs\n\n" printf "Start time: "; /bin/date printf "Running as user: "; /usr/bin/id printf "Running on node: "; /bin/hostname printf "Node IP address: "; /bin/hostname -I printparams printf "\nEnvironment:\n\n" printenv | sort } addsims() { while read f1 ; do read -u 3 f2 if [ _$f1 = _ ]; then f1=$lastf1; fi if [ _$f2 = _ ]; then f2=$lastf2; fi printf "%${width}d\n" $(($f1+$f2)) lastf1=$f1 lastf2=$f2 done <$1 3<$2 } # set defaults bias=0 biasfile=none initseed=none log=yes paramfile=none range=100 scale=1 seedfile=none timesteps=0 nvalues=1 width=8 cmdargs="$*" usage() { echo $0: usage: cat <<END -b|--bias offset bias: add this integer to all results -B|--biasfile file of integer biases to add to results -l|--log generate a log in stderr if not null -n|--nvalues print this many values per simulation -r|--range range (limit) of generated results -s|--seed use this integer [0..32767] as a seed -S|--seedfile use this file (containing integer seeds [0..32767]) one per line -t|--timesteps number of simulated "timesteps" in seconds (determines runtime) -x|--scale scale the results by this integer -h|-?|?|--help print this help END } # FIXME: NOT YET IMPLEMENTED: # -p|--paramfile take these parameters (in form param=value) from this file # -p|--paramfile) paramfile=$2 ;; while [ $# -gt 0 ]; do case $1 in -b|--bias) bias=$2 ;; -B|--biasfile) biasfile=$2 ;; -l|--log) log=$2 ;; -n|--nvalues) nvalues=$2 ;; -s|--seed) initseed=$2 ;; -S|--seedfile) seedfile=$2 ;; -t|--timesteps) timesteps=$2 ;; -r|--range) range=$2 ;; -w|--width) width=$2 ;; -x|--scale) scale=$2 ;; -h|-?|--help|*) usage; exit ;; esac shift 2 done # process initial seed if [ $initseed != none ]; then RANDOM=$initseed fi # process file of seeds if [ $seedfile != none ]; then seed=0 while read $seedfile s; do seed=$(($seed+$s)) done <$seedfile RANDOM=$seed fi # run for some number of "timesteps" sleep $timesteps # emit N (nvalues) "simulation results" scaled and biased by argument values simout=$(mktemp simout.XXXX) for ((i=0;i<$nvalues;i++)); do # value=$(( (($RANDOM)*(2**16))+$RANDOM )) value=$(( (($RANDOM)*(2**48)) + (($RANDOM)*(2**32)) + (($RANDOM)*(2**16)) + $RANDOM )) printf "%${width}d\n" $(( ($value%range)*scale+bias)) done >$simout # process file of biases if [ $biasfile != none ]; then addsims $simout $biasfile else cat $simout fi rm $simout # log environmental data if [ $log != off ]; then log 1>&2 fi
■ 前半と後半
という事で、用意された Swift コードファイルを順次実行することでチュートリアルが進んでいきます。チュートリアルの説明にもありますが、part 1 ~ 3 ではローカルの並列実行をためして、part 4 ~ 6 ではリモート実行を試す内容になっています。重い。
リモート実行では、大学や研究機関、パブリッククラウドなどのサイトでの実行が試せる内容になっているようです。実際のところ動かしても体感として分かりませんが。でもコンピュータリソースをデフォルトで分散共有できるのは素晴らしいと思います。
■ 完全に理解した!
というわけで Swift 完全に理解したつもりになりました!
(実際にはまだチュートリアル動かしていませんが、手順は動かすだけなので今のところはこれで良いでしょう)