Computer K 創夢作業書 - crest-cassia/CrowdWalk GitHub Wiki

作業項目

京における Java 実行環境の調査とソースコードの分析

京へのログイン

京にログインするためには、HPCI アカウントの発行、フロントエンド Web へのログイン、SSH 公開鍵の登録が必要となる。手順は以下の通り。

  • HPCI アカウント取得
  • HPCI アカウントのクライアント証明書の復号(電話にてパスワード連絡あり)
  • クライアント証明書をブラウザに登録し、利用者ポータル(※)に接続
  • 京にログインするための SSH の公開鍵と秘密鍵を作成
  • Web インタフェースから SSH 公開鍵を登録
  • 京のフロントエンドマシンに SSH でログインして利用

https://k.aics.riken.jp

詳細は、「利用手引き書」に記述があるが、利用者ポータルへログイン後しか参照できない。「利用手引き書」は、ログイン後に[ドキュメント] → [利用手引き書]とアクセスすることで参照可能。 利用者ポータルは CGI で作成されており、REST になっていないため、メニューをたどっていかないと目的のページにたどりつけない構造になっている。

  • 各種マニュアル: ログイン後に[ドキュメント] → [マニュアル]とアクセスすることで参照可能。

  • インストールされているオープンソース情報: ログイン後に[メイン] → [オープンソースソフト]とアクセスすることで参照可能。

ログインノードの環境

  • 環境: 通常の環境と同様に、ログインして開発・テストの作業が可能。
  • OS: Red Hat Enterprise Linux Server release 6.5 (Santiago)
  • Java
klogin4$ java -version
Picked up _JAVA_OPTIONS: -Xmx200m
java version "1.7.0_67"
Java(TM) SE Runtime Environment (build 1.7.0_67-b01)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)

Java の実行には、ヒープ最大使用量(-Xmx)の指定が必要なので注意が必要。~/.bashrc に以下の記述を行っておくと、意識することなく実行できる。 例)export _JAVA_OPTIONS="-Xmx200m"

計算ノードの環境

  • 環境: ログイン不可で、ログインノードからジョブ実行して結果を受領する。
  • OS: Sparc/専用 OS
  • Java: OpenJDK 1.7.0_45

ソースコードの分析

ソースコードを確認する限りでは、Java 8から Java 6/7への移植に必要な作業はラムダ式の展開のみである。ただし、ラムダ式を利用しているのは、GUI 部分のみなので、ソースコードについては、大幅な改変は必要ない。 ただし、ライブラリについては gradle で自動的にバイナリをダウンロードする形となっている。Java の場合、コンパイル時のオプションで Java のバージョンを指定できるが、opencsv のライブラリのみ Java 7以降でコンパイルされているため、Java 6への移植に際してはライブラリの変更等が必要となる(京の環境は Java 7であったため、完全には実施していない。 Java のプログラムとして気になるのは、HashMap や ArrayList を継承しているコードの存在である。一般的に、同一パッケージ内のクラスや、継承を前提にしているクラス以外は継承することを推奨されていない。これは、変更が明文化されない可能性があり、動作がバージョンにより変わる可能性があるためである。確認した限りでは、以下のクラスが Java の基本クラスを継承しているが、継承するのではなく、ArrayList や HashMap をメンバー変数として保持して捜査する方が安全である。

nodagumi.ananPJ.misc.AgentGenerationFile extends ArrayLis
nodagumi.ananPJ.NetworkMap.OBNodeTable extends ArrayList
nodagumi.Itk.UniqIdObjectTable extends HashMap

プログラム移植作業

ソースコード

ソースコード一式は、https://github.com/crest-cassia/CrowdWalk.git に納めている。

  • ブランチ:

    • Java 7 : fork
    • Java 6 : fork-work 変更点の詳細は、java6.diff および、java7.diff を参照。
  • 納品ソースコード

    • Java 7 バージョンを、CrowdWalk-fork.zip として納品。 ディレクトリ構成は以下の通り。新規に追加したのは result ディレクトリで、結果ファイルを格納している。
  • CrowdWalk/crowdwalk/ ベースディレクトリ

  • .settings/gradle gradle 設定ファイル

  • doc ドキュメント

  • result 結果ファイル(新規追加)

  • sample 設定ファイル

  • src/main ソースコード

  • tools ツール群

gradle

  • build.gradle 基本的には targetCompatibility と sourceCompatibility をターゲットバージョンに合わせるのみでよい。ただし Java 6の場合は、opencsv が動作しない問題があるため、dependencies から外す必要がある。また、compileJava 箇所は、options.compilerArgs を変更する必要がある。

  • gradle.properties 京の環境に合わせて、cui=true に変更している。

Java 7

ラムダ式を利用した箇所以外は、変更の必要なし。ただし、GUI 箇所にしかラムダ式は出てこないので、guild.gradle の変更のみで対応可能。

Java 6

Java 7の修正に加え、opencsv を利用できない問題を修正する必要がある。opencsv の バイナリファイルは Java 7以上でコンパイルされており、利用できない。ソースコードも、Laungage を取得するために Java 7以降の機能をのみ利用しているため、コードの改造なしには利用不可。 現状は、opencsv の改造した箇所のみコミットしているが、オープンソースの修正になるため好ましくない。Java 6で動作するライブラリを用意し、ラッパーにより切り替える処理が必要となる。検討した実装方法は、Factory Method パターンを利用する方法で、以下の通り。

  1. CSV の読み書きを行うラッパークラスを作成
  2. 動作している Java のバージョンをチェック
// JREのバージョン
System.out.println(System.getProperty("java.version"));
// JREの仕様バージョン
System.out.println(System.getProperty("java.specification.version"));
// JVMの実装バージョン
System.out.println(System.getProperty("java.vm.version"));
// Javaクラスの形式のバージョン番号
System.out.println(System.getProperty("java.class.version"));

3.実行環境が Java7 以降であれば、ラッパークラスが opencsv の インスタンスを生成、JDK6の場合は、独自クラスのインスタンスを生成

京における動作確認

ログインノード

ログインノードでは、通常の Linux 環境と同様に gradle でコンパイルと jar を作成し、CrowdWalk/crowdwalk/src/main/java/nodagumi/Itk で以下のコマンドを実行してログを出力する。

make run3gt00a_cui

ログインノードでは、ヒープ最大使用量を指定しておく必要があるため、 export _JAVA_OPTIONS="-Xmx200m" をあらかじめ実行しておく必要がある。

計算ノード

計算ノードへは、ログインノードから pjsub コマンドを利用してジョブ実行する。ジョブを実行するためには、pjsub コマンドに実行する sh を指定する。sh には、pjsub コマンドに対する指令をコメントの形式で記述し、計算ノードの環境変数や実行するコマンドを指定する。実行するファイルは、ログインノードのディレクトリ構造で指定する。

--- sh サンプル(compute.sh) ---
#!/bin/bash
#PJM -L "node=8"
#PJM -L "elapse=00:05:00"
#PJM -j
#PJM -o "comput.stdout"
#PJM --mpi "proc=1"

cd ~/workspace/CrowdWalk/crowdwalk/src/main/java/nodagumi/Itk
export JAVA_HOME=/opt/klocal/openjdk7u45
export PATH=${JAVA_HOME}/bin:$PATH
export CLASSPATH=.:${JAVA_HOME}/jre/lib:${JAVA_HOME}/lib:${JAVA_HOME}/lib/tools.jar

make run3gt00a_cui
--- sh サンプル(compute.sh) ---

pjsub に指定するコマンドは、「利用者ガイド」に記述がある。elapse が短すぎると、実行完了する前に終了し、異常終了してしまうので注意が必要。

以下のコマンドを実行すると、計算ノードにジョブが投入される。

pjsub --interact -s -j ./compute.sh

動作確認

  • 比較方法 ログとして出力される log_individual_pedestrians.csv を以下の環境で比較する。 ログは pedestrianID, current_time の2つのキーでソートする必要があるため、Linux 環境で、
sort -k 1,16 {ファイル名}

を実行して、結果を正規化したファイルを利用して比較する。

  • 比較結果
Ubuntu 16.04(x86/x64) + Java 8 : Ubuntu 12.04(x86/x64) + Java 7 = 同一
Ubuntu 16.04(x86/x64) + Java 8 : 京 ログインノード(x86/x64) + Java 7 = 同一
Ubuntu 16.04(x86/x64) + Java 8 : 京 計算ノード(Sparc) + Java 7 = 差違あり
  • 差違 京の計算ノードのみ差違が発生しているが、差違は非常に小さいため、Java の問題ではなく、CPU が違いにより生じる浮動小数点の丸め方の違いが原因と考えられる。

  • 結果ファイルと比較プログラム fork ブランチの CrowdWalk/crowdwalk/result/ に各種ファイルを置いている

compute_node    計算ノードの結果
local_1.7       Ubuntu 12.04(x86/x64) + Java 7の結果
local_1.8       Ubuntu 16.04(x86/x64) + Java 8の結果
login_node      京 ログインノードの結果
diff.csv        差違の発生した環境の比較結果
diff.php        差違を CSV 形式で出力するためのプログラム
diff.xlsx       差違の発生した環境の比較結果(Excel バージョン)