view paper/final_main/chapter3.tex @ 29:a7dbce3eeaa3

fix
author suruga
date Tue, 20 Feb 2018 16:55:34 +0900
parents b02a8d6a4e9c
children
line wrap: on
line source

\chapter{評価実験}
本研究は、Jungleの分散環境上での性能を正しく評価するための実験を行う。
本章では実験の概要について述べる。
まず、本研究の目的について述べ、
次に、分散フレームワーク Aliceによる、本研究の分散機構を構成する方法について述べる。
次に、木構造上に立ち上げたJungleへ投入するタスクを制御するジョブスケジューラー、TORQUEについて述べる。
最後に、本実験の測定用プログラムについて述べる。
\section{実験目的}
Jungleは現在、Javaで実装されたものと、Huskellで実装されたものがある。
Java版は、処理速度が早く、よりスケーラビリティの高いデータベースの実装を目的に開発された。
対してHuskell版は、モダンな型システムと、型推論と型安全という特徴を生かし、信頼性の高データベースの実装を目的に開発された。
そして、これまでの研究で、Java版とHaskell版のJungleの分散性能を測定する実験が行われている。
分散性能測定実験では、それぞれJetty,Wrapというwebサーバーをフロントエンドに用いたWeb掲示板サービスを使用している。
Java版とHuskell版のWeb掲示板サービスをブレードサーバー上で実行される。
計測方法は、掲示板に対して読み込みと書き込みを行い、ネットワークを介してweighhttpで負荷をかける。
weighthttpの設定は、1スレッドあたり100並列のリクエストを、10スレッド分投入し、合計100万のリクエストを処理させる。
Java と Haskell の測定結果が表\ref{tab:compare}のようになった。

\begin{table}[!htbp]
\begin{center}
\begin{tabular}{|c||r|r|} \hline
  測定 & Haskell & Java \\ \hline \hline
  読み込み & 16.31 s & 53.13 s \\ \hline
  書き込み & 20.17 s & 76.4 s \\ \hline
\end{tabular}
\end{center}

\caption{HaskellとJavaの比較}
\label{tab:compare}
\end{table}

Huskell 版は、 Java 版と比較して、読み込みで3,25倍、書き込みで 3.78倍 の性能差がでている結果となってしまった。
処理速度においてはHuskellよりも高いことを予想されていたのにもかかわらず、Java版がHuskell版よりも遅くなってしまった原因は、
測定時のWeb掲示板サービスのフロントエンドに、どちらもWebサーバーを用いているということが考えられる。しかも、その際は言語の問題から、異なる種類のWebサーバーを使用している。
これでは、この性能結果が、異なる言語で実装されたJungleの性能差によるものなのか、Webサーバーの性能差によるものなのかがわからない。
そこで、本研究ではJava版のJungleにおいて、Webサーバーを取り除いた、純粋なJungleの分散性能を測定するプログラムを実装した。
\section{実験概要}
Jungleの分散性能を測定するにあたり、複数台のJungleを通信させ、JungleからJungleに対する書き込みにかかる時間を計測する。複数台のJungleを分散させる為に、学内共用の仮想マシンを32台使用した。分散したJungle同士の通信部分には、当研究室で開発している分散フレームワークAliceの機能であるTopologyManagerを使用する。TopologyManagerの起動には、仮想マシン32台のうちの1台を使用する。
学科の仮想マシン31台上でそれぞれ1台ずつJungleを立ち上げ、ツリー型のトポロジーを構成する。そのうち16台のJungleに対して100回ずつデータを書き込む。子ノードのJungleは、他のJungleで書き込まれたデータを自身に書かれたデータとmergeしていく。全ての子ノードのJungleでmergeされたデータは、最終的に親ノードのJungleのデータへmergeされていく。
本実験では、複数の子ノードにJungleに書き込まれたデータが最終的にルートノードのJungleのデータへmergeされ、書き込まれた時間を計測し、平均を取る。図\ref{fig:gaiyou} は本実験を図で表したものであり、31 台中 16 台の Jungle から書き込まれた データがルートノードの Jungle へ書き込まれる、一回あたりの時間を計測する。
  \begin{figure}[htbp]
    \begin{center}
        \includegraphics[width=100mm]{./pic/gaiyou.pdf}
    \end{center}
        \caption{複数のjungleに書き込まれたデータがrootのjungleへ到達する時間を計測する}
         \label{fig:gaiyou}
\end{figure}

\section{実験環境}
学科のKVM上の仮想マシンによる仮想クラスタ環境を用いて実験を行った。
分散環境上での実験を行うにあたり、他の利用者とリソースが競合しないよう、TORQUEジョブスケジューラーを利用している。
KVMと仮想マシンの性能はそれぞれ表\ref{tab:kvm}、表\ref{tab:vm}である。
\begin{table}[htbp]
\begin{center}
\begin{tabular}{|c||r|r|} \hline
  マシン台数 & Haskell  \\ \hline 
  CPU & 16.31 s  \\ \hline
  物理コア数 & 20.17 s  \\ \hline
  論理コア数 &   \\ \hline
  CPUキャッシュ & \\ \hline
  Memory & \\ \hline
\end{tabular}
\end{center}

\caption{KVMの詳細}
\label{tab:kvm}
\end{table}

\begin{table}[htbp]
\begin{center}
\begin{tabular}{|c||r|r|} \hline
  マシン台数 & Haskell  \\ \hline 
  CPU & 16.31 s  \\ \hline
  物理コア数 & 20.17 s  \\ \hline
  仮想コア数 &   \\ \hline
  CPUキャッシュ & \\ \hline
  Memory & \\ \hline
\end{tabular}
\end{center}

\caption{仮想クラスタの詳細}
\label{tab:vm}
\end{table}

\section{TORQUE Resource Manager}
分散環境上でのJungleの性能を測定するにあたり、VM31台にJungleを起動させた後、16台のJungleに対し、データを書き込むプログラムを動作させる。プログラムを起動する順番やタイミングは、TORQUE Resource Managerというジョブスケジューラーによって管理する。

TORQUE Resource Manager は、ジョブを管理・投下・実行する3つのデーモンで構成されており、
ジョブの管理・投下を担うデーモンが稼働しているヘッダーノードから、ジョブの実行を担うデーモンが稼働している計算ノードへジョブが投下される(図\ref{fig:torque} )。
  \begin{figure}
    \begin{center}
        \includegraphics[width=100mm]{./pic/torque.pdf}
    \end{center}
        \caption{TORQUEの構成}
         \label{fig:torque}
\end{figure}

ユーザーはジョブを記述したシェルスクリプトを用意し、スケジューラーに投入する。その際に、利用したいマシン数やCPUコア数を指定する。TORQUEは、ジョブに必要なマシンが揃い次第、受け取ったジョブを実行する。

今回作成した、ジョブに投入するためのシェルスクリプトを以下(ソースコード\ref{src:LogupdateTest.pl})に示す。

\begin{lstlisting}[frame=lrbt,label=src:LogupdateTest.pl,caption=本実験で投入するジョブスクリプト,numbers=left]
#!/bin/sh
#PBS -q jungle
#PBS -N LogUpdateTest
#PBS -l nodes=16,walltime=00:08:00

cd /mnt/data/jungle_workspace/Log  
/usr/bin/perl /mnt/data/jungle_workspace/scripts/LogupdateTest.pl
\end{lstlisting}
6行目で指定されたディレクトリに移動し、7行目ではそのディレクトリで、指定した別の階層にあるperlスクリプトを実行している。

\newpage


\section{分散フレームワーク Alice による分散環境の構築}
分散させたJungleの通信部分を担うのが、当研究室で開発している並列分散フレームワークAlice[1]である。Aliceは、ネットワーク上の複数のサーバーノードにトポロジーを形成させ、通信する機能を提供する。今回扱うサーバーノードに学科の仮想マシン(VM)を用いる。
本研究では、分散環境上でのJungleの性能を確認する為、VM32台分のサーバーノードを用意し、それぞれで1台ずつJungle起動することで、分散させる。
%Jungleを起動したサーバーノード間の通信部分を、当研究室で開発している並列分散フレームワークAlice[1]にて再現する。

Aliceには、ネットワークのトポロジーを構成するTopologyManager[2]という機能が備わっている。TopologyManagerは以下のソースコード\ref{src:topologymanager}のように起動する。
\begin{lstlisting}[frame=lrbt,label=src:topologymanager,caption=TopologyManagerの起動方法,numbers=left]
% java -cp ../../build/libs/logupdateTest-1.1.jar alice.topology.manager.TopologyManager -conf ../../scripts/tree.dot -p 10000
\end{lstlisting}
-p オプションはトポロジーマネージャーが開くポートの番号、-conf オプションには  トポロジーファイルであるtree.dotのパスを渡している。トポロジーファイルとは、どのようにトポロジーノードをつなげるかを記述したファイルである。AliceのTopologyManagerを使用する際は、どのようなトポロジーを形成したいかを決め、あらかじめトポロジーファイルを作成する必要がある。今回、31台のサーバーノードでツリートポロジーを形成するdotファイルを以下のソースコード\ref{src:treedot}のように記述した。
\begin{lstlisting}[frame=lrbt,label=src:treedot,caption=作成したトポロジーファイル,numbers=left]
digraph test {
	node0 -> node1 [label="child1"]
	node0 -> node2 [label="child2"]
	node1 -> node0 [label="parent"]
	node1 -> node3 [label="child1"]
	node1 -> node4 [label="child2"]
	node2 -> node0 [label="parent"]
	node2 -> node5 [label="child1"]
	node2 -> node6 [label="child2"]
	node3 -> node1 [label="parent"]
	node3 -> node7 [label="child1"]
	node3 -> node8 [label="child2"]
	node4 -> node1 [label="parent"]
	node4 -> node9 [label="child1"]
	node4 -> node10 [label="child2"]
	node5 -> node2 [label="parent"]
	node5 -> node11 [label="child1"]
	node5 -> node12 [label="child2"]
	node6 -> node2 [label="parent"]
	node6 -> node13 [label="child1"]
	node6 -> node14 [label="child2"]
	node7 -> node3 [label="parent"]
	node8 -> node3 [label="parent"]
	node9 -> node4 [label="parent"]
	node10 -> node4 [label="parent"]
	node11 -> node5 [label="parent"]
	node12 -> node5 [label="parent"]
	node13 -> node6 [label="parent"]
	node14 -> node6 [label="parent"]
}
\end{lstlisting}
また、31台のサーバーノードで形成するトポロジーファイルを自動で生成するプログラムを作成した。以下のソースコード\ref{src:treedot.rb}に示す。
\begin{lstlisting}[frame=lrbt,label=src:treedot.rb,caption=本実験で使用するトポロジーファイルを生成するプログラム,numbers=left]
def create_nodes(node_num)
  (0..node_num - 1).map { |i|
    i = "node" + i.to_s
  }
end

def print_dot(connections)
  puts "digraph test {"
  connections.each { |connection|
    print "\t"
    print connection[0]
    print " -> "
    print connection[1]
    print ' [label="' + connection[2] + '"]'
    puts
  }
  puts "}"
end

node_num = ARGV[0].to_i
nodes = create_nodes(node_num)
connections = Array.new
nodes.each_with_index { |node, i|
  parent = (i - 1) / 2;
  child1 = 2 * i + 1;
  child2 = 2 * i + 2;
  if parent >= 0 then
    connections << [nodes[i], nodes[parent], "parent"]
  end
  if child1 < node_num then
    connections << [nodes[i], nodes[child1], "child1"]
  end
  if child2 < node_num then
    connections << [nodes[i], nodes[child2], "child2"]
  end
}
print_dot(connections)
\end{lstlisting}
%ここにrubyの説明を入れてもいい
 TopologyManagerは、参加表明をしたサーバーノード(以下TopologyNode)を、トポロジーファイルの内容に従ってトポロジーを構成する。
 TopologyManagerへの参加表明は、TopologyNode起動時に、TopologyManagerのIPアドレスとポート番号を指定すれば良い。
 
TopologyNodeはTopologyManagerに、誰に接続を行えばよいかを尋ねる。TopologyManagerは尋ねてきたTopologyNodeに順番に、接続先のTopologyNodeのIPアドレス、ポート番号、接続名を送り、受け取ったTopologyNodeはそれらに従って接続する。
この時、TopologyManager自身はVM0を用いて立ち上げる。
よって、TopologyManagerはJungleをのせたVM1からVM32、計VM31台分のサーバーノードを、木構造を形成するように采配する(図\ref{fig:topologymanager} )。

\begin{figure}[H]
    \centering
    \includegraphics[width=90mm]{pic/topologymanager5.pdf}
    \caption{AliceによるJungleの木構造トポロジーの形成}
    \label{fig:topologymanager}
\end{figure}
図\ref{fig:topologymanager}の矢印の流れを以下に示す。
\begin{enumerate}
 \item TopologyManagerがトポロジーファイルを読み込む。
 \item TopologyNodeがTopologyManagerに接続先を尋ねる。
 \item 接続先のTopologyNodeのIPアドレス、ポート番号、接続名を送り返す。
 \item 受け取った接続先の情報を元に、トポロジーを形成する。
\end{enumerate}
%TopologyManagerによって構成されたトポロジーのサーバーノードには、それぞれ自分自身を示す文字列であるキーが存在する。
各ノードは自身を示すnodeName[3]を持ち、このnodeNameを指定することで他ノードとの通信を行う。
nodeNameは自身のサーバーノードがデータを受け取る際に指定する必要がある。

たとえば、servernode0,servernode1,servernode2により、図\ref{fig:LogupdateTree}のように木構造が構成されたとする。
\begin{figure}[H]
    \centering
    \includegraphics[width=100mm]{pic/LogupdateTree.pdf}
    \caption{トポロジーの形成}
    \label{fig:LogupdateTree}
\end{figure}
この時、servernode0はservernode1、servernode2に対して親にあたる。逆に、servernode1,servernode2はservernode0に対して子にあたる。よって、図\ref{fig:LogupdateTree}に矢印の隣にかかれている文字列"parent","child 1","child 2"のようにキーを指定している。
servernode0からservernode1へデータを送りたい場合、”child 1”というnodeNameを追加すればいい。
このように、データアクセスしたいサーバーノードのnodeNameを追加することで、そのサーバノードのDataSegmentへデータアクセスすることができる。
他のサーバーノードのDataSegmentへデータアクセスする際には、アクセス先のサーバーノードのnodeNameを追加すればいい。

%TreeOperationLog
トポロジー構成後、Jungle間の通信でのデータ形式にはTreeOperationLogを利用する。TreeOperationLogは、Jungleによるノードの編集の履歴などの情報が入っている。TreeOperationLogは、AliceのDataSegmentでも扱えるようシリアライズ化されたデータである。
%Aliceのトポロジー形成と他のサーバのデータへアクセスする機構を用いるためには、Aliceが提供するプログラミングスタイルに沿わなければならない。それはDataSegmentとCodeSegmentである。よって、Jungleのログの実態であるTreeOperationLogは、DataSegmentで扱えるようシリアライズされている。
各サーバーノードには、データを受け取る部分であるDataSegmentが備わっている。よって、Aliceによって構成されたネットワークトポロジーのサーバノード間でのデータのアクセスが可能になっている。
TreeOperationLogをAliceによって他のJungleへ送る。送信先のJungleでは、送られてきたTreeOperationLogを参照して送信元のJungleと同じノード編集を行う。こうして、Jungle間でのデータの同期を可能にしている。
%DataSegment CodeSegment
Aliceのトポロジー形成と他のサーバのデータへアクセスする機構を用いるためには、Aliceが提供するプログラミングスタイルに沿わなければならない。それはDataSegmentとCodeSegmentである。よって、Jungleのログの実態であるTreeOperationLogは、DataSegmentで扱えるようシリアライズされている。
Aliceはタスクを行うCodeSegmentと、CodeSegmentで使用するデータを扱うDataSegmentによってプログラムを行うスタイルを取る。
CodeSegmentはDataSegmentが必要なデータを受け取り次第、タスクを行う。DataSegmentがデータを受け取る為には、そのDataSegmentを示すキーが必要である。
\newpage

\section{データ書き込みプログラムの実装}
これまで、本実験の概要、測定環境について説明し、次にTORQUEによるJungleへのプログラム投下方法と、Aliceによる分散通信部分の構築方法について説明した。ここでは、本実験の手順と合わせて、今回実装した部分である、Jungleにデータを書き込むための機能について解説する。
本実験において、木構造を形成した32台のうち、16台のJungleへデータを100回書き込むプログラムを作成した。
以下のソースコード \ref{Logupdate}は、実装したテストプログラムの起動部分である。

\lstinputlisting[frame=lrbt, label=Logupdate, caption=測定用プログラムの起動部分,numbers=left]{./plsource.txt}

1行目で本実験のネットワークトポロジーを形成するためtopokogymanagerの起動を行なっている。\$nodesはVM0~VM31台の、合計32台の仮想マシンを表し、TopologyManagerはVM0に起動する。

-p オプションはTopologyManagerが開くポートの番号、-confオプションには dot ファイルのパスを渡している。ポート番号はAliceのより記述された並列分散プログラムの起動時に渡す必要がある。

dot ファイルには、トポロジーをどのように構成するかが書かれている。dotファイルを読み込んだAliceのTopologyManagerに対して、サーバーノードは誰に接続を行えばよいかを尋ねる。TopologyManagerは尋ねてきたサーバーノードに対してノード番号を割り振り、dotファイルに記述している通りにサーバーノードが接続を行うように指示をだす。

-showTime オプションは、今回Aliceに実装した機能である。--showTime オプションをつけることで、出力される結果に、子ノードのJungleからの書き込みがrootノードのJungleへ到達し、書き込みが終了したときの時間が表示されるようになる。

4行目では、Jungleを起動している。このとき、-host でTopologyManagerのIPアドレスを渡し、-portでTopologyManagerのポート番号をしている。TopologyManagerのIPアドレスとポート番号を渡すことで、TopologyManagerへ参加表明をしている。

10行目では、4行目と同様Jungleを起動しているが、今回実装した-writeオプションと-countオプションをつけている。

-writeオプションは、Jungleにデータを書き込む機能をつけることができる。

-countオプションは、何回データを書き込むかを指定することができる。隣に引数をつけることで、回数を設定できる。本実験では、16台のJungleで、100回データを書き込むよう設定する。
すなわち、TopologyManagerに1台、writeモードで立ち上げるJungleに16台使た後、残りの15台はそのままJungleを起動させている。

このスクリプトは、TORQUEによって各サーバーノードへ投入され、実行される。
%データを複数書き込む機能は、Jungleを立ち上げる際に-writeオプションと-countオプションをつけることで搭載される。
%Aliceのコードを参照する限り、TopologyManagerが起動した時から、終了するまでの間で時間を取得している。
%この図だと末端の子ノードからのみ書き込まれているように見える。実際は1~16の様々な場所にあるノードから書き込む。
\section{時間計測プログラムの実装}
前節ではツリートポロジーを形成した子ノードのJungleへデータを書き込む部分、及び実験手順について解説した。複数の子ノードにデータをそれぞれ書き込み、最終的にrootノードへデータを書き込んでいく時間を計測する為の機能を、新たにAliceに実装した。
ここではAliceに実装した時間計測プログラムについて解説する。

以下のソースコード \ref{src:alipro}は、実装したテストプログラムの起動部分である。
\lstinputlisting[frame=lrbt, label=src:alipro, caption=Aliceに実装した時間計測プログラムのプログラムの起動部分,numbers=left]{./alitopo.txt}

%また、実際のプログラムをソースコード \ref{src:ConfigWaiter.java}のように記述した。
%\lstinputlisting[frame=lrbt, label=src:ConfigWaiter.java, caption=Aliceに実装した時間計測プログラムのプログラムの起動部分,numbers=left]{./ConfigWaiter.txt}


%ソースコード \ref{src:StartTopologyManager.java}。
%\lstinputlisting[frame=lrbt, label=src:StartTopologyManager.java, caption=Aliceに実装した時間計測プログラムのプログラムの起動部分,numbers=left]{./StartTopologyManager.txt}

ソースコード \ref{src:StartTopologyManager.java}
\begin{lstlisting}[frame=lrbt,label=src:StartTopologyManager.java,caption=Aliceに実装したtimestamp部分,numbers=left]
package alice.topology.manager;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;

import org.apache.log4j.Logger;

import alice.codesegment.CodeSegment;
import alice.topology.HostMessage;
import alice.topology.fix.ReceiveDisconnectMessage;

import com.alexmerz.graphviz.ParseException;
import com.alexmerz.graphviz.Parser;
import com.alexmerz.graphviz.objects.Edge;
import com.alexmerz.graphviz.objects.Graph;
import com.alexmerz.graphviz.objects.Node;

public class StartTopologyManager extends CodeSegment {

    TopologyManagerConfig conf;
    Logger logger = Logger.getLogger(StartTopologyManager.class);

    public StartTopologyManager(TopologyManagerConfig conf) {
        this.conf = conf;
    }

    @Override
    
   public void run() {
   
        new CheckComingHost();
   
        ods.put("absCookieTable", new HashMap<String, String>());
   
        ods.put("config", conf );



        if (!conf.dynamic) {

            LinkedList<String> nodeNames = new LinkedList<String>();

            HashMap<String, LinkedList<NodeInfo>> topology = new HashMap<String, 
           
            LinkedList<NodeInfo>>();
           
            int nodeNum = 0;
           
            try {
           
                FileReader reader = new FileReader(new File(conf.confFilePath));
           
                Parser parser = new Parser();
           
                parser.parse(reader);
           
                ArrayList<Graph> graphs = parser.getGraphs();
           
                for (Graph graph : graphs) {
           
                    ArrayList<Node> nodes = graph.getNodes(false);
           
                    nodeNum = nodes.size();
           
                    for (Node node : nodes) {
           
                        String nodeName = node.getId().getId();
           
                        nodeNames.add(nodeName);
           
                        topology.put(nodeName, new LinkedList<NodeInfo>());
           
                    }
           
                    ArrayList<Edge> edges = graph.getEdges();
           
                    HashMap<String, NodeInfo> hash = new HashMap<String, NodeInfo>();
           
                    for (Edge edge : edges) {
           
                        String connection = edge.getAttribute("label");
           
                        String source = edge.getSource().getNode().getId().getId();
           
                        String target = edge.getTarget().getNode().getId().getId();
           
                        LinkedList<NodeInfo> sources = topology.get(target);
           
                        NodeInfo nodeInfo = new NodeInfo(source, connection);
           
                        sources.add(nodeInfo);
           
                        hash.put(source + "," + target, nodeInfo);
           
                    }
           
                    for (Edge edge : edges) {
           
                        String connection = edge.getAttribute("label");
           
                        String source = edge.getSource().getNode().getId().getId();
           
                        String target = edge.getTarget().getNode().getId().getId();
           
                        NodeInfo nodeInfo = hash.get(target + "," + source);
           
                        if (nodeInfo != null) {
           
                            nodeInfo.reverseName = connection;
           
                        }
           
                    }
           
                }



            } catch (FileNotFoundException e) {

                logger.error("File not found: " + conf.confFilePath);

                e.printStackTrace();

            } catch (ParseException e) {

                logger.error("File format error: " + conf.confFilePath);

                e.printStackTrace();

            }


            // for recode topology information
            
            // cookie List


            ods.put("running", false);

            ods.put("resultParse", topology);

            ods.put("nodeNames", nodeNames);



            new IncomingHosts();



            ConfigWaiter cs3 = new ConfigWaiter(nodeNum);

            cs3.done.setKey("local", "done");



        } else {

            ods.put("running", true);



            HashMap<String, HostMessage> nameTable = new HashMap<String, HostMessage>();



            if (conf.type == TopologyType.Tree) {

                int cominghostCount = 0;

                ParentManager manager = new ParentManager(conf.hasChild);

                ods.put("parentManager", manager);

                ods.put("nameTable", nameTable);

                ods.put("hostCount", cominghostCount);

                new ComingServiceHosts();

                new ReceiveDisconnectMessage();

            }

        }



        ods.put("topology", new HashMap<String, LinkedList<HostMessage>>());

        ods.put("createdList", new LinkedList<String>());

        new CreateHash();



        TopologyFinish cs2 = new TopologyFinish();

        cs2.finish.setKey("local", "finish");

        cs2.config.setKey("config");

        cs2.startTime.setKey("startTime");

    }



}
\end{lstlisting}

ソースコード\ref{src:TopologyFinish.java}
\begin{lstlisting}[frame=lrbt,label=src:TopologyFinish.java,caption=Aliceに実装したtimestamp部分,numbers=left]
package alice.topology.manager;

import alice.codesegment.CodeSegment;
import alice.datasegment.CommandType;
import alice.datasegment.Receiver;

public class TopologyFinish extends CodeSegment {
    public Receiver finish = ids.create(CommandType.TAKE);
    public Receiver config = ids.create(CommandType.PEEK);
    public Receiver startTime = ids.create(CommandType.TAKE);
    @Override
    public void run() {
        TopologyManagerConfig conf = config.asClass(TopologyManagerConfig.class);
        long start = startTime.asClass(Long.class);
        if (conf.showTime) {
            System.out.println("TopologymanagerTime = "+ (System.currentTimeMillis()-start));
        }
        System.exit(0);
    }

}
\end{lstlisting}

ソースコード \ref{src:StartTopologyManager.java}はTopologyManagerを開始するコードであり、ソースコード\ref{src:TopologyFinish.java}はTopologyManagerの終了部分のコードである。
本実験において、子ノードのJungleからrootノードのJungleへデータのmergeが終了する時間を計るために、TopologyManagerの開始時、終了時の時間を取得している。ソースコード\ref{src:TopologyFinish.java}の最後では、取得した終了時の時間から、開始時の時間を差し引いた時間を出力している。
前の説で解説した、データ書き込みプログラム()が投入されると、TopologyManagerが起動し、Jungleへのデータの書き込みが始まる。そしてrootノードのJungleへデータが書き込み終わると共にTopologyManagerが終了するので、TopologyManagerの終了時から開始時を差し引いた時間が、今回の測定範囲となる。

ソースコード\ref{src:TopologyFinish.java}の最後にある、currentTimeMillis()はTopologyManagerが終了した現時点の時間である。TopologyManagerの開始時の時間は、以下のソースコード \ref{src:ConfigWaiter.java}で示す。

\begin{lstlisting}[frame=lrbt,label=src:ConfigWaiter.java,caption=Aliceに実装したtimestamp部分,numbers=left]
package alice.topology.manager;

import org.msgpack.type.ValueFactory;

import alice.codesegment.CodeSegment;
import alice.datasegment.CommandType;
import alice.datasegment.Receiver;

public class ConfigWaiter extends CodeSegment {

    public Receiver done = ids.create(CommandType.TAKE);
    public int count;

    public ConfigWaiter(int nodeNum) {
        this.count = nodeNum;
    }

    @Override
    public void run() {
        count--;
        if (count == 0) {
            ods.put("local", "start", ValueFactory.createNilValue());
            ods.put("startTime",System.currentTimeMillis());
            ods.update("running", true);
            return;
        }
        ConfigWaiter cs3 = new ConfigWaiter(count);
        cs3.done.setKey("local", "done");
    }

}
\end{lstlisting}
ソースコード \ref{src:ConfigWaiter.java}では、Jungleの起動時につけた-count オプションの引数を取得している。
ここでは、DataSegmentであるstartTimeに、現在の時間を入れている。この時間が、TopologyManagerの開始時のデータとなる。

\begin{lstlisting}[frame=lrbt,label=src:TopologyManagerConfig.java,caption=Aliceに実装したtimestamp部分,numbers=left]
package alice.topology.manager;

import alice.daemon.Config;

public class TopologyManagerConfig extends Config {

    public boolean showTime = false;
    public String confFilePath;
    public boolean dynamic = false;
    public TopologyType type = TopologyType.Tree;
    public int hasChild = 2;

    public TopologyManagerConfig(String[] args) {
        super(args);
        for (int i = 0; i < args.length; i++) {
            if ("-conf".equals(args[i])) {
                confFilePath = args[++i];
            } else if ("--Topology".equals(args[i])) {
                String typeName = args[++i];
                if ("tree".equals(typeName)) {
                    type = TopologyType.Tree;
                }
            } else if ("--Child".equals(args[i])) {
                hasChild = Integer.parseInt(args[++i]);
            } else if ("--showTime".equals(args[i])) {
                showTime = true;
            }
        }

        if (confFilePath == null)
            dynamic = true;
    }

}
\end{lstlisting}
ソースコード\ref{src:TopologyManagerConfig.java}では、データ書き込みプログラムを投入時、TopologyManagerの起動部分でつけた -showTime オプションの有無を判断している。オプションが存在していれば、実行結果にrootのJungleに書き込まれた時間が表示される。