view paper/chapter4.tex @ 41:17d6daf672bc

add result of experiment
author kazz <kazz@cr.ie.u-ryukyu.ac.jp>
date Sat, 11 Feb 2012 23:45:03 +0900
parents a9f30ac5820d
children
line wrap: on
line source

\chapter{分散フレームワーク Alice の評価} \label{chapter:chapter4}
前章までは、 Alice の設計と実装について示した。
本章では、 Alice を用いた実験方法等についてまとめ、先行研究である Federated Linda との性能比較を行い、 Alice を評価する。

\section{TORQUE Resource Manager を用いた実験方法}
Alice の性能を実験する際に、学科にある共用のブレードサーバーを用いた。
共用のブレードサーバーを利用するため、実験を行う際は、自身の実験の正確さと、他の利用者の実験の邪魔をしないためにも、他の利用者とリソースが競合しないようにする必要がある。つまり、ジョブスケジューラーを利用しなくてはならない。

今回の実験では、 TORQUE Resource Manager (\url{http://www.adaptivecomputing.com/products/torque.php}) を利用した。

\subsection {TORQUE Resource Manager}
TORQUE は、クラスター等の分散コンピューティング環境を複数名で共有する場合に有効である。

TORQUE は、1台のマスターと複数台のスレーブで構成される。(図 \ref{fig:torque})
スレーブは、マスターへ現在の自身のリソースの利用状況を報告する。

\begin{figure}[htbp]
  \begin{center}
    \includegraphics[width=80mm]{./images/torque.pdf}
  \end{center}
  \caption{TORQUE の構成}
  \label{fig:torque}
\end{figure}

ユーザーは、マスターにリモートログインして TORQUE を利用する。

ユーザーは、ジョブをシェルスクリプトを用いて記述し、ジョブスケジューラーへと投入する。
その時、利用したいマシン数、 CPU コア数等を詳細にオプションで指定する事ができる。

ユーザーからのジョブを受け取った TORQUE は、利用可能な状態にあるマシンが揃い次第、受け取ったジョブを実行する。

\subsection{TORQUE のジョブの書き方}
TORQUE のジョブは、シェルスクリプトを用いて記述する。

TORQUE のジョブは実行されたときに、いくつかの実験に関する環境変数を得る。

\begin{itemize}
\item {\ttfamily PBS\_NODEFILE}\\
すべての参加マシンが列挙されているファイルへのパス
\item {\ttfamily PBS\_NUM\_NODES}\\
全ての参加マシン数
\item{\ttfamily PBS\_NUM\_PPN}\\
参加マシン一台あたりのコア数
\end{itemize}

{\ttfamily PBS\_NODEFILE} に記述されているマシン名に順番に、それぞれ走らせたいコマンドを ssh で記述していく。(ソースコード \ref{src:torque1})

\begin{lstlisting}[label=src:torque1, caption=割り当てられたマシンにログインして hostname コマンドを走らせる例]
function run() {
    while read node
    do
        ssh $node hostname < /dev/null
    done
    wait
}
run < $PBS_NODEFILE
\end{lstlisting}

ジョブを投入するには、 qsub コマンドを用いる。(ソースコード \ref{src:torque2})

\begin{lstlisting}[label=src:torque2, caption=10台(1台あたり1コア)で走らせる例]
qsub -l nodes=10:ppn=1 job.sh
\end{lstlisting}

しかし、複数のコアを持つマシン上で、1マシン1プロセスで分散プログラムを動かしたい場合、問題が発生する。
例えば、4コアのマシンは4つリソースがあると計算されるので重複して割り当てられるのである。

そこで、正確に1マシン1プロセスの実験を行うには、1プロセスに4コア分だけリソースを割り当てないといけない。(ソースコード \ref{src:torque3})

\begin{lstlisting}[label=src:torque3, caption=10台(1台あたり4コア)で走らせる例]
qsub -l nodes=10:ppn=4 job.sh
\end{lstlisting}

しかしこの場合、{\ttfamily PBS\_NODEFILE} の中に含まれるマシンは4つずつ重複して登録されている。({\ttfamily PBS\_NUM\_NODES} は重複していない)

そのため、 uniq コマンド等でマシンリストの重複を除いてから ssh コマンドを実行していかなくてはならない。(ソースコード \ref{src:torque4})

\begin{lstlisting}[label=src:torque4, caption=ノードファイルからマシンの重複を除く]
uniq $PBS\_NODEFILE /tmp/nodes
\end{lstlisting}

\begin{lstlisting}[label=src:torque5, caption=Alice でリングトポロジーの実験に使ったジョブ]
#!/bin/bash
#
# Alice Ring Topology
#
#PBS -q dque
#PBS -N AliceRingTopology
#PBS -l walltime=00:05:00

alicepath=/home/mass/student/k108572/test
node_num=`expr $PBS_NUM_NODES - 1` # TopologyManager の分を1引く
port=10000    # 利用するポート番号
count=100     # リングを回る回数
size=4096     # リングを回すメッセージのサイズ

function run() {
    read serv
    ssh $serv "ruby $alicepath/ring.rb $node_num > /tmp/ring.dot" < /dev/null
    ssh $serv killall java < /dev/null
    ssh $serv java -cp $alicepath/Alice.jar alice.topology.manager.TopologyManager -p $port -conf /tmp/ring.dot -log $alicepath/log/manager.log -level info < /dev/null &
    cnt=0
    while read node
    do
      ssh $node killall java < /dev/null
      ssh $node java -cp $alicepath/Alice.jar alice.test.topology.ring.RingTopology -host $serv -port $port -p $port -log $alicepath/log/ring${cnt}.log -log -level info -count $count -size $size -nodeNu
m $node_num < /dev/null &
      cnt=`expr $cnt + 1`
    done
    wait
}

uniq $PBS_NODEFILE /tmp/nodes
run < /tmp/nodes
\end{lstlisting}

\begin{lstlisting}[label=src:torque6, caption=5台から45台までを1刻みで実行するシェルスクリプト]
#!/bin/sh
count=6
while [ $count -le 46 ];
do
    qsub -l nodes=$count:ppn=4 ring.sh
    count=`expr $count + 1`
done
\end{lstlisting}

\section{Federated Linda との性能比較}

続いて、 Alice と Federated Linda の性能比較を行う。
実験内容は、 Federated Linda がかつて実験したリングトポロジーによる実験を、 Alice 上で再現した。

\subsection{実験環境}
今回はブレードサーバー(表 \ref{tb:blade})上の仮想マシン(表 \ref{tb:virtual})による仮想クラスタ環境を用いて実験した。

\begin{table}[htbp]
\caption{ブレードサーバーの詳細}
\label{tb:blade}
\begin{center}
\begin{tabular} {|l|l|}
  \hline
  {\bf マシン台数}&8台\\
  \hline
  {\bf CPU}&Intel(R) Xeon(R) X5650 @ 2.67GHz\\
  \hline
  {\bf 物理コア数}&12\\
  \hline
  {\bf 論理コア数}&24\\
  \hline
  {\bf CPU キャッシュ}&12MB\\
  \hline
  {\bf Memory}&132GB\\
  \hline
\end{tabular}
\end{center}
\end{table}

\begin{table}[htbp]
\caption{仮想クラスタの詳細}
\label{tb:virtual}
\begin{center}
\begin{tabular} {|l|l|}
  \hline
  {\bf マシン台数}&48台\\
  \hline
  {\bf CPU}&Intel(R) Xeon(R) X5650 @ 2.67GHz\\
  \hline
  {\bf 物理コア数}&2\\
  \hline
  {\bf 仮想コア数}&4\\
  \hline
  {\bf CPU キャッシュ}&12MB\\
  \hline
  {\bf Memory}&8GB\\
  \hline
\end{tabular}
\end{center}
\end{table}

\subsection{実験概要}
リングのトポロジーを構成し、メッセージが 100 周する時間を計り、1周あたりの平均時間を求める実験である。(図 \ref{fig:topologyring})

\begin{figure}[htbp]
  \begin{center}
    \includegraphics[width=110mm]{./images/topologyring.pdf}
  \end{center}
  \caption{100周にかかる時間を計測し、1周あたりの平均時間を求める}
  \label{fig:topologyring}
\end{figure}

パケットのサイズは、 10 bytes の比較的軽いデータから、 4096 bytes の比較的重いファイルを用いて実験した。

今回の実験では、トポロジーの構築時間は実験に含めてはいない。純粋な API の実行速度のみで比較している。



\subsection{実験結果}
実験結果は以下のようになった。(図 \ref{fig:ring10B})(図 \ref{fig:ring4KB})

これらに更に追加して、 10KB のデータを送信した時と 100KB のデータを送信した時の時間も測った。(図 \ref{fig:ring10KB})(図 \ref{fig:ring100KB})

\begin{figure}[htbp]
  \begin{center}
    \includegraphics[width=110mm]{./images/ring10B.pdf}
  \end{center}
  \caption{10 bytes のデータを100周させたときの1周にかかる平均時間}
  \label{fig:ring10B}
\end{figure}

\begin{figure}[htbp]
  \begin{center}
    \includegraphics[width=110mm]{./images/ring4KB.pdf}
  \end{center}
  \caption{4096 bytes のデータを100周させたときの1周にかかる平均時間}
  \label{fig:ring4KB}
\end{figure}

\begin{figure}[htbp]
  \begin{center}
    \includegraphics[width=110mm]{./images/ring10KB.pdf}
  \end{center}
  \caption{10 Kbytes のデータを100周させたときの1周にかかる平均時間}
  \label{fig:ring10KB}
\end{figure}

\begin{figure}[htbp]
  \begin{center}
    \includegraphics[width=110mm]{./images/ring100KB.pdf}
  \end{center}
  \caption{100 Kbytes のデータを100周させたときの1周にかかる平均時間}
  \label{fig:ring100KB}
\end{figure}

このように、 45 台で実験した場合、 12 ms 程、Alice が遅いことが分かる。

また、 Code Segment のスレッドプールを使用せずに、そのまま実行した場合の実験も行った。(図 \ref{fig:ringnothread})

\begin{figure}[htbp]
  \begin{center}
    \includegraphics[width=110mm]{./images/ring_notp_10b.pdf}
  \end{center}
  \caption{Code Segment のスレッドプールを使用せずに、 10 bytes のデータを回した時の実験結果}
  \label{fig:ringnothread}
\end{figure}

この場合、スレッドプールを使用しないほうが速いことが分かる。

\subsection{考察}

今回の結果により、 Alice は本研究室で長年チューニングされてきた Federated Linda にはまだ勝てていないことが分かった。

しかし、図 {fig:ringnothread} の結果を見ると、 Code Segment の並列化を断ったほうが、結果が良くなっている。今回の実験は、リングを1周させるという、同時に複数のタスクが走らない実験であった。これは全てシングルスレッドで作成されている Federated Linda が得意なシーケンシャルな実験だったので、こうなったことが分かる。

最後に、今回の実験において Alice が実行する処理の段階をまとめてみた。(図 \ref{fig:ringdiagram}) 赤い部分がスレッドで走る部分である。また、太い矢印が、 LinkedBlockingQueue による、データの中継地点である。

\begin{figure}[htbp]
  \begin{center}
    \includegraphics[width=110mm]{./images/ring_diagram.pdf}
  \end{center}
  \caption{リングの実験において 1 台の Alice が実行する処理の段階}
  \label{fig:ringdiagram}
\end{figure}

このように、複数のスレッド分けを行なっているが、それらが直列的に実行されている事がわかる。なので、この実験では Alice のスレッド分けした実装が逆に悪影響を与えている事がわかる。

Federated Linda に勝てるような実験は、もっと多数のマシンからアクセスが同時に行われるような実験をしたほうがよい。