rksoftware

Visual Studio とか C# とかが好きです

プログラミング言語 Swift (6) - Swift チュートリアル

Swift とは JVM 上で動くスクリプト言語だという事は知っています。
非常に有名なプログラミング言語であるにも関わらず、しかし事前知識はそれだけで他のことは全く知りませんでした。

こんな有名なプログラミング言語を知らないなんて、それは少し恥ずかしいな思い立って、プログラミング言語 Swift を調べてみます。少しずついくつかの記事にかに分けて調べていってみようと思います。

目次はこちら

rksoftware.hatenablog.com

■ 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 完全に理解したつもりになりました!
(実際にはまだチュートリアル動かしていませんが、手順は動かすだけなので今のところはこれで良いでしょう)