view poster/master-lt.html @ 17:d39c452010ea

add poster base.
author koba <koba@cr.ie.u-ryukyu.ac.jp>
date Tue, 15 Feb 2011 18:21:02 +0900
parents
children a5fb2dea1c60
line wrap: on
line source

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<title>master_presentation</title>
<!-- metadata -->
<meta name="generator" content="S5" />
<meta name="version" content="S5 1.1" />
<meta name="presdate" content="20050728" />
<meta name="author" content="Eric A. Meyer" />
<meta name="company" content="Complex Spiral Consulting" />
<!-- configuration parameters -->
<meta name="defaultView" content="slideshow" />
<meta name="controlVis" content="hidden" />
<!-- style sheet links -->
<link rel="stylesheet" href="ui/default/slides.css" type="text/css" media="projection" id="slideProj" />
<link rel="stylesheet" href="ui/default/outline.css" type="text/css" media="screen" id="outlineStyle" />
<link rel="stylesheet" href="ui/default/print.css" type="text/css" media="print" id="slidePrint" />
<link rel="stylesheet" href="ui/default/opera.css" type="text/css" media="projection" id="operaFix" />
<!-- S5 JS -->
<script src="ui/default/slides.js" type="text/javascript"></script>
</head>
<body>

<div class="layout">
<div id="controls"><!-- DO NOT EDIT --></div>
<div id="currentSlide"><!-- DO NOT EDIT --></div>
<div id="header"></div>
<div id="footer">
<h1>[date:11/02/09]</h1>
<h2>Game Framework Cerium を用いたゲームプログラミングにおけるテスト手法の提案</h2>
</div>

</div>


<div class="presentation">

<div class="slide">
<h1>Game Framework Cerium を用いた<br>
    ゲームプログラミングにおける<br>
    テスト手法の提案</h1>
<h3>発表者:小林 佑亮</h3>
<h4>所属:琉球大学 理工学研究科 情報工学専攻 並列信頼研究室</h4>
<h4>指導教員:河野 真治</h4>
</div>

<div class="slide">
<h1>発表内容</h1>
<ol>
<li>序論</li>
<li>CppUnit を用いたゲームプログラムテスト</li>
<li>ゲームプログラミングにおけるテスト</li>
<li>Cell BE と Cerium</li>
<li>テスト対象のシューティングゲーム Super Dandy</li>
<li>構築したテスト環境</li>
<li>テスト環境によるデバッグと検証</li>
<li>まとめ</li>
</ol>
</div>

<div class="slide">
<h1>研究背景</h1>
<font size="4"><ul>
<li>我々は PlayStation3(以下 PS3) 上においてゲーム開発が行えるフレームワーク
 Cerium を開発した。</li>
<li>Cerium ではプログラムを Task という単位に分けて管理し、これを PS3 の 
アーキテクチャである Cell B.E に渡して並列処理を行う。</li>
<li>シーケンシャルなプログラムを Task に分割して並列実行させても、
逐次実行させた時と同じ動作をするとは限らない。</li>
<li>オブジェクト同士のデータの同期や、処理の実行順序など、シーケンシャルな
プログラムに比べて、バグを発生させる要因は多い。</li>
<li>また、ゲームプログラムの特徴はプレイヤーの入力やプログラム内にある乱数
などの非決定的な要素が多いことが挙げられる。</li>
<li>これによってバグの再現性が低下するため、ゲームプログラムのテストは
  一般的なソフトウェアのテストに比べて難しい</li>
</ul></font>
</div>

<div class="slide">
<h1>研究目的</h1>
<font size="4"><ul>
<li>本研究では Task に分割されたゲームプログラムがシーケンシャルなバージョン
と同じ動作である事を確認できるテスト環境の構築を目的とする。</li>
<li>プレイヤーの入力や乱数などの非決定的な要素を固定化し、バグの再現性を
低下させずにテストを行えるようにする。</li>
<li>動作の同一性を確かめるために必要なパラメータの書き出しを行う</li>
<li>高速なテストを行う為、テストに影響しない範囲で実行時間が大きい処理を
排除する。</li>
</ul></font>
</div>

<div class="slide">
<h1>CppUnit</h1>
<ul class="simple">
  <li>xUnit と呼ばれる単体テストのためのフレームワークの内の 1 つ</li>
  <li>単体テストとは関数やメソッドなどの比較的小さな単位で行うテストで、
    モジュールへの入力と出力を調べることでそのモジュールが要求された仕様を
    満たしているかをテストする手法</li>
  <li>CppUnit は 1 つの事象に対して様々なテストケースを同時にテストできる</li>
  <li>羅列したテストケースは一括で実行と結果表示が出来る</li>
  <li>しかしこうした単体テストではゲームプログラムのバグを見つけるのは難しい</li>
</ul>
</div>

<div class="slide">
<h1>ゲームオブジェクトに対するテスト</h1>
<table>
  <tr>
    <td><ul class="simple">
	<li>3 つの SceneGraph ノードを持つ</li>
	<li>本体を tree の root として左右のパーツがその子供になっている。</li>
	<li>オブジェクトの動き(Move)として左右の平行移動をする</li>
	<li>簡単なゲームの例題</li>
    </ul></td>
    <td><img src="images/boss1_SG.png" width=300 height=250></td>
    </tr>
  </table>
</div>

<div class="slide">
<h1>ゲームオブジェクトに対するテスト</h1>
<h2>テスト方法</h2>
<ul class="simple">
	<li>SceneGraph tree の root のアドレスを取得</li>
	<li>そこから tree を辿って各オブジェクトの座標を取得</li>
	<li>初期値を入力してオブジェクトの初期化が正しいか調べる</li>
</ul>
<h2>テスト結果</h2>
<ul class="simple">
  <li>全てのオブジェクトの初期値が正しい事がわかった</li>
  <li>初期化の段階でバグが発生していないことが保証された</li>
</ul>
</div>

<div class="slide">
<h1>ゲームに対する単体テストの欠点</h1>
<ul>
<li>単体テストは瞬間的な値の正しさは調べられる</li>
<li>常にオブジェクトのパラメータが変化するゲームには有効的ではない</li>
<li>ゲームのバグは他のオブジェクトのパラメータとの関係により発生するものが
多い</li>
<li>一般的な単体テストではゲームのバグの発見は難しい</li>
</ul>
</div>

<div class="slide">
<h1>ゲームプログラムの特徴</h1>
<table>
  <tr>
    <td><ul class="simple">
	<li>多数のオブジェクトが存在する</li>
	<li>オブジェクト同士が相互に干渉する</li>
	<li>プレイヤーの入力やゲームの進行によって新たなオブジェクトが生成される</li>
	<li>オブジェクトは他のオブジェクトのパラメータを見て、衝突判定や挙動の変化をする</li>
    </ul></td>
    <td>
      <img src="images/game.png" width=300 height=250/>
    </td>
  </tr>
</table>
</div>

<div class="slide">
<h1>ゲームプログラムの特徴</h1>
<ul class="simple">
  <li>プレイヤーの入力がゲームに影響する</li>
  <li>遷移する状態が膨大</li>
  <li>遷移する状態が仕様の範囲内に収まるかをチェックするテストは向かない</li>
  <li>実際にプレイヤーがゲームをプレイするのが重要なテスト</li>
</ul>
</div>

<div class="slide">
<h1>プレイヤーの入力の不定性</h1>
<ul class="simple">
  <li>プレイヤーの入力は常に非決定的(毎回結果が異なる)</li>
  <li>同じ人間が同じゲームの同じ場面をプレイしても全く同じ入力をする可能性
    は極めて低い</li>
  <li>プレイヤーは制御不能なランダム要素</li>
  <li>テストにおけるバグの再現性を低下させている</li>
</ul>
</div>

<div class="slide">
<h1>ゲームにおける乱数の役割</h1>
<ul class="simple">
  <li>オブジェクトの振る舞いに多様性を持たせる</li>
  <li>ランダムな位置配置に使われる</li>
  <li>乱数のランダム性はデバッグをする上でバグの再現を困難にする</li>
  <li>対処法としては、乱数生成器を無効にするか、定数でシードする</li>
</ul>
</div>

<div class="slide">
<h1>Cell Broadband Engine</h1>
<ul class="simple">
  <li>SCE と 東芝、IBM によって開発されたCPU</li>
  <li>2 thread の PPE(PowerPC Processor Element) と 8 個の 
    SPE(Synergistic Processor Element)を持つ</li>
  <li>各 CPU 間は高速リングバスであるEIB(Element Interface Bus)で
    繋がっている</li>
</ul>
<center>
<img src="images/cell.png" width=350 height=150/>
</center>
</div>

<div class="slide">
<h1>Game Framework Cerium</h1>
<dl>
  <b><dt>SceneGraph</dt></b>
  <dd>オブジェクトのパラメータやポリゴン情報を tree 構造のノードで管理</dd>
  <b><dt>Rendering Engine</dt></b>
  <dd>3 種類の Task によって並列に描画処理を行う</dd>
  <b><dt>TaskManager</dt></b>
  <dd>Task を動的に SPE へ割り振るカーネルとして振舞う</dd>
</dl>
</div>

<div class="slide">
<h1>Task Manager</h1>
<ul class="simple">
  <li>Task と呼ばれる分割されたプログラムを管理する</li>
  <li>Task の単位はサブルーチンまたは関数とする。</li>
  <li>生成された Task を依存関係を考慮しながら SPE に転送したり、実行する</li>
</ul>
</div>

<div class="slide">
<h1>Task 生成時に使用できる API</h1>
<center>
<table border="1" cellspacing="0">
  <tr><th>create_task</th><td>Task を生成する</td>
  <tr><th>set_inData</th><td>Task への入力データのアドレスを追加</td>
  <tr><th>set_outData</th><td>Task からの出力先アドレスを追加</td>
  <tr><th>set_param</th><td>Task に 32 bit の情報を追加</td>
  <tr><th>set_post</th><td>Task が終了した後に PPE 側で実行される関数を登録</td>
</table>
</center>
</div>

<div class="slide">
<h1>シューティングゲーム SuperDandy</h1>
<table>
  <tr>
    <td><ul class="simple">
	<li>我々が PlayStation 上でのゲーム開発を行っていた 1998 年に開発</li>
	<li>タイトルからゲーム本編中の敵機の登場、ステージクリア、エンディングと
	  ゲーム的な要素が多い</li>
	<li>PlayStation, PlayStation2 Linux, OpenGL と伝統的に移植されてきた</li>
    </ul></td>
    <td>
      <img src="images/dandy.png" width=300 height=250/>
    </td>
  </tr>
</table>
</div>

<div class="slide">
<h1>Super Dandy 移植の利点</h1>
<ul class="simple">
  <li>全 5 ステージという、ある程度のボリュームのあるゲーム</li>
  <li>衝突判定やオブジェクト判定、ステージクリアによるシーン切り替えと、基本的なゲームの要素が入っている</li>
  <li>動作結果を過去の環境と比較することによる新たな環境のチューニングができる</li>
</ul>
</div>

<div class="slide">
<h1>Super Dandy Cerium version</h1>
<ul class="simple">
  <li>最初に Cerium に対応したバージョン</li>
  <li>描画処理に Cerium の Rendering Engine を用いており、その箇所のみ
  Task で処理される</li>
  <li>基本的なゲームの処理は変わらない</li>
</ul>
</div>

<div class="slide">
<h1>Task Dandy(Super Dandy Task version)</h1>
<table>
  <tr>
    <td><ul class="simple">
	<li>オブジェクトの Move や Collision を Task 化</li>
	<li>オブジェクトの描画は SceneGraph tree の形成、Rendering Task の
	  生成といった Cerium の描画処理を使用</li>
	<li>できるだけ Super Dandy のコードやデータ構造を流用</li>
    </ul></td>
    <td>
      <img src="images/taskdandy.png" width=300 height=300/>
    </td>
  </tr>
</table>
</div>

<div class="slide">
<h1>Task Dandy のデータ構造</h1>
<dl>
  <b><dt>player</dt></b>
  <dd>プレイヤーの操作する機体。xy 座標、残機数、無敵時間、
    コンテニュー回数などを持つ。</dd>
  <b><dt>CHARACTER</dt></b>
  <dd>敵機や敵の弾。xy 座標とその方向の速さ、体力、倒したときのスコア、
    オブジェクトの種類を表すキャラナンバーを持つ。</dd>
  <b><dt>tama_lv1〜lv3、laser_lv1〜lv3</dt></b>
  <dd>プレイヤーが撃った弾。xy 座標をもつ。プレイヤーが射撃ボタンを押すと
    弾が配列に格納され、敵に当たるか画面外にいくと消滅する。</dd>
</dl>
</div>

<div class="slide">
<h1>データ転送に用いる Property</h1>
<table>
  <tr>
    <td><ul class="simple">
	<li>必要なパラメータをまとめて Property にコピーして set_inData</li>
	<li>複数のデータをまとめることによって Task の inData を簡略化</li>
    </ul></td>
    <td>
      <img src="images/property.png" width=400 height=300/>
    </td>
  </tr>
</table>
</div>

<div class="slide">
<h1>ステートパターン</h1>
<table>
  <tr>
    <td><font size="4"><ul class="simple">
	  <li>オブジェクトの Move と Collision を行う</li>
	  <li>オブジェクトが関数ポインタを持ち、そのポインタが示す関数が
	    Move や Collision の処理を行う</li>
	  <li>関数ポインタのアドレスを他の関数ポインタのアドレスに書き換え、
	    オブジェクトの状態遷移をする</li>
	  <li>しかし、メモリが独立している SPE 上で状態遷移をする場合、
	    ステートパターンで使用した関数ポインタのアドレスは使えない</li>
      </ul></font></td>
    <td>
      <img src="images/state_pattern.png" width=300 height=200/>
    </td>
  </tr>
</table>
</div>

<div class="slide">
<h1>SPE における状態遷移</h1>
<table>
  <tr>
    <td><ul class="simple">
	<li>SPE 上では Task の ID を変更</li>
	<li>PPE 上で変更された ID を見て次に生成する Task の種類を変更</li>
	<li>オブジェクトの状態遷移が成立</li>
    </ul></td>
    <td>
      <img src="images/task_change.png" width=400 height=300/>
    </td>
  </tr>
</table>
</div>

<div class="slide">
<h1>目標とするテスト環境</h1>
<ul class="simple">
  <li>プレイヤーの入力や乱数などの非決定的な要素の固定化</li>
  <li>現在動作中の OpenGL バージョンと Cerium バージョン、そして Task Dandy
    の動作が同一かどうか確認できるテストログの出力</li>
  <li>高速なテスト環境</li>
</ul>
</div>

<div class="slide">
<h1>Capture モードと Trace モード</h1>
<ul class="simple">
  <li>プレイヤーからの入力を 1 フレーム毎に記録する</li>
  <li>記録した入力をバイナリデータとして書き出す</li>
  <li>書き出したファイルを読み込むことで過去のプレイヤー入力を再現できる</li>
  <li>実行ファイルにオプションとファイル名を付けて起動する</li>
  <li>3 つの Super Dandy 全てで使える</li>
  <li>旧バージョンの入力を記録し、新バージョンで読み出すことができる</li>
  <li>入力が同じでも動作が違えばそこにバグが潜んでいると考えられる</li>
</ul>
</div>

<div class="slide">
<h1>入力を記録するバッファのデータ構造</h1>
<ul class="simple">
  <li>単方向リスト型のバッファ</li>
  <li>Capture モードではバッファが足りなくなると新たなバッファを確保する</li>
  <li>Trace モードでは必要なバッファサイズを計算し、あらかじめバッファを確保しておく</li>
</ul>
<center>
  <img src="images/pad_buff.png" width=400 height=150>
</center>
</div>

<div class="slide">
<h1>SPE における乱数生成</h1>
<font size="4"><ul class="simple">
  <li>シーケンシャルプログラムでは 1 つの乱数列から順番に乱数を取得</li>
  <li>Cell における並列プログラムでは各 SPE 内で 独自の乱数列を生成</li>
  <li>SPE に送られた Task は SPE 固有の乱数列を使用</li>
  <li>SPE 内では依存関係を持たない Task は実行順序が不定</li>
  <li>シーケンシャルと並列で異なる結果が出る</li>
</ul></font>
<center>
  <img src="images/spe_random.png" width=400 height=150>
  </center>
</div>

<div class="slide">
<h1>SPE 内での予測可能な乱数の使用</h1>
<table>
  <tr>
    <td><ul class="simple">
	<li>あらかじめ PPE 内で乱数列を生成しておく</li>
	<li>inData として Task に渡す</li>
	<li>Move Task や Collision Task の生成タイミングは Super Dandy の
	Move や Collision のタイミングと同じ</li>
	<li>Super Dandy と同じ乱数が使用できる</li>
    </ul></td>
    <td>
      <img src="images/ppe_random.png" width=400 height=300/>
    </td>
  </tr>
</table>
</div>

<div class="slide">
<h1>並列処理をすることによって発生するバグ</h1>
<table>
  <tr>
    <td><ul>
	<li>Task 間のデータの同期による衝突判定のバグ</li>
	<li>Task の実行順序の違いによる衝突判定のバグ</li>
	<li>Task の実装の違い</li>
	<li>主にオブジェクトの衝突判定でバグが発生</li>
	<li>衝突時のログを見ることでバグを発見する</li>
    </ul></td>
    <td>
      <img src="images/test_log.png" width=350 height=300/>
    </td>
  </tr>
</table>
</div>

<div class="slide">
<h1>出力されるテストログ</h1>
<font size="4"><pre>
F64: CREATE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -128.000000
                                             vx= 0.000000  vy= 4.000000
F85: DELETE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -44.000000
                                             vx= 0.000000  vy= 4.000000
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
</pre></font>
<dl class="simple">
  <b><dt>F64, F85</dt></b>
  <dd>生成、被弾した時の経過フレーム</dd>
  <b><dt>CREATE, DELETE</dt></b>
  <dd>CREATE はオブジェクトの生成、DELETE はオブジェクトの被弾</dd>
  <b><dt>NAME</dt></b>
  <dd>オブジェクトの種類と ID</dd>
<dl>
</div>

<div class="slide">
<h1>出力されるテストログ</h1>
<font size="4"><pre>
F64: CREATE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -128.000000
                                             vx= 0.000000  vy= 4.000000
F85: DELETE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -44.000000
                                             vx= 0.000000  vy= 4.000000
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
</pre></font>
<dl>
  <b><dt>COORD</dt></b>
  <dd>オブジェクトの xy 座標と速度</dd>
  <b><dt>BULLET</dt></b>
  <dd>その瞬間に画面内に存在した弾丸の数。</dd>
</dl>
</div>

<div class="slide">
<h1>Cerium における画面の描画処理</h1>
<table>
  <tr>
    <td><ul class="simple">
	<li>ビデオモードの選択(SDL, OpenGL)</li>
	<li>描画処理を行う画面バッファの領域の確保</li>
	<li>ゲーム処理の実行</li>
	<li>レンダリング Task による画面バッファへの描画</li>
    </ul></td>
    <td>
      <img src="images/video.png" width=300 height=300/>
    </td>
  </tr>
</table>
</div>

<div class="slide">
<h1>本研究のテスト環境における描画処理</h1>
<table>
  <tr>
    <td><ul class="simple">
	<li>プレイヤーの入力の自動化により、プログラムを実行するだけでテストが可能</li>
	<li>描画処理が不要となる</li>
	<li>描画用 Task の生成を行わない事により、テストの高速化ができる</li>
	<li>また、画面バッファの確保も不要</li>
    </ul></td>
    <td>
      <img src="images/video2.png" width=300 height=300/>
    </td>
  </tr>
</table>
</div>

<div class="slide">
<h1>描画処理を行わないモード</h1>
<ul class="simple">
  <li>ビデオモードの選択時に選ぶ</li>
  <li>Task を生成する処理をスルーしてゲーム処理を実行</li>
</ul>
<center>
  <img src="images/video_none.png" width=200 height=150/>
</center>
</div>

<div class="slide">
<h1>本研究のテスト環境におけるバグの検出方法</h1>
<ul class="simple">
  <li>OpenGL バージョンを Capture モードでプレイし、入力を記録</li>
  <li>Cerium バージョン、Task Dandy を Trace モードで実行</li>
  <li>各バージョンで得られたテストログを比較、考察</li>
  <li>テストログの違いにより、バグの発生している箇所を特定</li>
</ul>
</div>

<div class="slide">
<h1>OpenGL と Cerium のテストログの比較</h1>
<center>
<table border="1" cellspacing="0">
  <tr><td></td><th>大きさ</th><th>行数</th><th>単語数</th></tr>
  <tr><th>OpenGL</th><td>349486 byte</td><td>3411</td><td>37194</td></tr>
  <tr><th>Cerium</th><td>349471 byte</td><td>3411</td><td>37195</td></tr>
</table>
</center>
<ul class="simple">
  <li>Cerium バージョンは描画を行わないモードで実行</li>
  <li>エンディングまでプレイした入力データを仕様</li>
  <li>テストログのデータに unix コマンドの wc(word count) コマンドを実行して検証</li>
  <li>各バージョンで得られたテストログを比較、考察</li>
</ul>
</div>

<div class="slide">
<h1>OpenGL と Cerium のテストログの比較</h1>
<center>
<table border="1" cellspacing="0">
  <tr><td></td><th>大きさ</th><th>行数</th><th>単語数</th></tr>
  <tr><th>OpenGL</th><td>349486 byte</td><td>3411</td><td>37194</td></tr>
  <tr><th>Cerium</th><td>349471 byte</td><td>3411</td><td>37195</td></tr>
</table>
</center>
<ul class="simple">
  <li>2 つのログに大きな差は無い</li>
  <li>Super Dandy をエンディングまでプレイしたときに得られるテストログの大きさ
  は約 350 KB</li>
  <li>単語数と大きさに僅かな差</li>
</ul>
</div>

<div class="slide">
<h1>diff によるテストログの比較</h1>
<font size="4"><pre>
% diff log/demo_log log/dandy_log
1a2
> Use Joystick
3410,3411c3411,3412
< 83.308451 FPS
< move: average:49usec, peak:1091usec
---
> 0.000000 FPS
> game end
</pre></font>
<ul class="simple">
  <li>表示されているメッセージは OpenGL や Cerium 依存のメッセージ</li>
  <li>0.000000 FPS は Cerium 側のメッセージで描画を行わないビデオモードにより
  正しく FPS の計算ができなかったため</li>
  <li>wc の単語数はスペース区切りで判別するため、Cerium=6,OpenGL=5</li>
  <li>よって両バージョンの動作は同じである</li>
</ul>
</div>

<div class="slide">
<h1>OpenGL バージョンと Task Dandy の比較</h1>
<font size="4"><pre>
super dandy(OpenGL) >>
F64: CREATE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -128.000000 ...
F85: DELETE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -44.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F96: CREATE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -128.000000 ...
F96: CREATE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= -128.000000 ...
F109: DELETE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -24.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F117: DELETE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= 40.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0

<< task dandy
F64: CREATE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -128.000000 ...
F85: DELETE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -44.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F96: CREATE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -128.000000 ...
F96: CREATE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= -128.000000 ...
F109: DELETE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -24.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F109: DELETE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= -24.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
</pre></font>
</div>

<div class="slide">
<h1>ログからのバグの洗い出し</h1>
<font size="4"><pre>
super dandy(OpenGL) >>
F109: DELETE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -24.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F117: DELETE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= 40.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0

<< task dandy
F109: DELETE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -24.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F109: DELETE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= -24.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
</pre></font>
<ul class="simple">
  <li>OpenGL では別フレームで死んだ 2 つの敵オブジェクトが Task Dandy では
  同フレームで死亡</li>
  <li>この時の弾丸の数が一致</li>
  <li>片方が死んだ後、弾丸のオブジェクトの除去がされてない</li>
  <li>弾丸データが取れていない、という仮説を立てた</li>
</ul>
</div>

<div class="slide">
<h1>Collision Task 間でのデータの同期</h1>
<table>
  <tr>
    <td><ul class="simple">
	<li>Collision Task を同じ CPU に送る</li>
	<li>予め衝突判定に必要なパラメータの領域を確保する</li>
	<li>その領域のパラメータで衝突判定を行う</li>
	<li>SPE 内で変更されたパラメータをメインメモリ側に反映させる</li>
    </ul></td>
    <td>
      <img src="images/collision_reflect.png" width=300 height=300/>
    </td>
  </tr>
</table>
</div>

<div class="slide">
<h1>Collision Task の改良後の比較</h1>
<font size="4"><pre>
super dandy>>
F64: CREATE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -128.000000 ...
F85: DELETE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -44.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F96: CREATE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -128.000000 ...
F96: CREATE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= -128.000000 ...
F109: DELETE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -24.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F117: DELETE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= 40.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0

<< task dandy
F64: CREATE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -128.000000 ...
F85: DELETE  [NAME]enemy_greenclab_0  [COORD]x= 120.000000  y= -44.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F96: CREATE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -128.000000 ...
F96: CREATE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= -128.000000 ...
F109: DELETE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -24.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F117: DELETE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= 40.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
</pre></font>
</div>

<div class="slide">
<h1>Collision Task の改良後の比較</h1>
<font size="4"><pre>
super dandy(OpenGL) >>
F109: DELETE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -24.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F117: DELETE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= 40.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0

<< task dandy
F109: DELETE  [NAME]enemy_greenclab_1  [COORD]x= 56.000000  y= -24.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
F117: DELETE  [NAME]enemy_greenclab_2  [COORD]x= 184.000000  y= 40.000000 ...
             [BULLET]tlv1 = 2, tlv2 = 0 llv1 = 0
</pre></font>
<ul class="simple">
  <li>2 つのバージョンのログがフレーム単位で同じ</li>
  <li>Collision Task のデータ同期が有効に働いている</li>
</ul>
</div>

<div class="slide">
<h1>Task への乱数受け渡しの検証</h1>
<ul class="simple">
  <li>多数の隕石オブジェクトが生成されるステージで全ての隕石オブジェクトが
  生成されるのを観察</li>
  <li>隕石オブジェクトの初期配置は乱数によるランダム配置</li>
  <li>隕石オブジェクト生成後の座標と速度を出力</li>
</ul>
</div>

<div class="slide">
<h1>隕石オブジェクトの実装</h1>
<font size="4"><pre>
  int sf;

  sf = random() % 4;
  if((sf == 0) || (sf == 1))
    {
      p->x = -35;
      p->y = random() % (120 - 35);
      p->vx = (random() % 4 + 1);
      p->vy = random() % 3 + 1;
      p->state = chara_state23;
    }
  if((sf == 2))
    {
      p->x = random() % 290;
      p->y = -30;
      p->vx = random() % 3 - 1;
      p->vy = (random() % 4 + 1);
      p->state = chara_state23;
    }
  if(sf == 3)
    {
      .....
</pre></font>
</div>

<div class="slide">
<h1>Task Dandy 側の実装</h1>
<font size="4"><pre>
    int rand1 = (int)smanager->get_param(0);
    int rand2 = (int)smanager->get_param(1);
    int rand3 = (int)smanager->get_param(2);
    int rand4 = (int)smanager->get_param(3);

    CHARACTER *p = (CHARACTER*)smanager->get_input(rbuf, 0);

      int sf = rand1 % 4;
      if((sf == 0) || (sf == 1))
      {
         p->x = -35;
	  p->y = rand2 % (120 - 35);
	  p->vx = (rand3 % 4 + 1);
	  p->vy = rand4 % 3 + 1;
      }
      if((sf == 2))
      {
	  p->x = rand2 % 290;
	  p->y = -30;
	  p->vx = rand3 % 3 - 1;
	  p->vy = (rand4 % 4 + 1);
          .....
</pre></font>
</div>

<div class="slide">
<h1>実行結果</h1>
<font size="4"><pre>
demolog >>
[COORD]x= 320.000000  y= 66.000000  vx= -2.000000  vy= 0.000000
[COORD]x= -35.000000  y= 20.000000  vx= 3.000000  vy= 1.000000
[COORD]x= -35.000000  y= 36.000000  vx= 3.000000  vy= 2.000000
[COORD]x= 89.000000  y= -30.000000  vx= 1.000000  vy= 3.000000
[COORD]x= -35.000000  y= 81.000000  vx= 1.000000  vy= 2.000000
[COORD]x= 320.000000  y= 8.000000  vx= -4.000000  vy= -1.000000
[COORD]x= 220.000000  y= -30.000000  vx= 1.000000  vy= 4.000000
....

<< tdandylog
[COORD]x= 320.000000  y= 66.000000  vx= -2.000000  vy= 0.000000
[COORD]x= -35.000000  y= 20.000000  vx= 3.000000  vy= 1.000000
[COORD]x= -35.000000  y= 36.000000  vx= 3.000000  vy= 2.000000
[COORD]x= 89.000000  y= -30.000000  vx= 1.000000  vy= 3.000000
[COORD]x= -35.000000  y= 81.000000  vx= 1.000000  vy= 2.000000
[COORD]x= 320.000000  y= 8.000000  vx= -4.000000  vy= -1.000000
[COORD]x= 220.000000  y= -30.000000  vx= 1.000000  vy= 4.000000
....

% diff demolog tdandylog
%
</pre></font>
</div>

<div class="slide">
<h1>乱数受け渡しによる実行結果の検証</h1>
<ul class="simple">
  <li>生成された隕石オブジェクトのパラメータが両バージョンで一致している</li>
  <li>Task への乱数受け渡しによるバグの再現性の低下防止は有効である</li>
</ul>
</div>

<div class="slide">
<h1>ビデオモードによる実行時間の比較</h1>
<ul class="simple">
  <li>実行時間の計測には unix の time コマンドを使用</li>
  <li>3 バージョンの描画無しモードを使用(OpenGL は 1x1)</li>
  <li>描画ありバージョンは 1200x800 で統一して計測</li>
</ul>
</div>

<div class="slide">
<h1>実行結果</h1>
<table border="1" cellspacing="0">
  <tr><td></td><th>OpenGL(w=1,h=1)</th><th>Cerium(no video)</th><th>Task(no video)</th><th>OpenGL</th><th>Cerium</th><th>Task</th></tr>
  <tr><th>実行時間</th><td>335.06 sec</td><td>334.21 sec</td><td>385.17 sec</td><td>336.09 sec</td><td>5066.11 sec</td><td>6643.16 sec</td></tr>
</table>
<ul class="simple">
  <li>OpenGL バージョンと Cerium バージョンではほとんど差がない</li>
  <li>描画処理を除けば 2 つのバージョンには殆ど差がない為と考えられる</li>
  <li>TaskDandy では Cerium における Task の処理が発生したため、実行時間が大きく増加したと考えられる</li>
</ul>
</div>

<div class="slide">
<h1>実行結果</h1>
<table border="1" cellspacing="0">
  <tr><td></td><th>OpenGL(w=1,h=1)</th><th>Cerium(no video)</th><th>Task(no video)</th><th>OpenGL</th><th>Cerium</th><th>Task</th></tr>
  <tr><th>実行時間</th><td>335.06 sec</td><td>334.21 sec</td><td>385.17 sec</td><td>336.09 sec</td><td>5066.11 sec</td><td>6643.16 sec</td></tr>
</table>
<ul class="simple">
  <li>OpenGL では描画無しバージョンとの差がほとんど無い</li>
  <li>Cerium バージョンや Task バージョンは劇的に処理時間が増加</li>
  <li>描画処理の Task の処理時間が非常に大きいと考えられる</li>
  <li>描画処理の Task に比べればゲームの Task は処理が小さい</li>
</ul>
</div>

<div class="slide">
<h1>結論</h1>
<h2>本研究では並列環境におけるゲームプログラムのテスト手法を提案した</h2>
<ul class="simple">
  <li>衝突判定時のテストログ出力によるデバッグは OpenGL バージョンと Task 
    Dandy の実行結果が同じであることから、効果的であった</li>
  <li>Task への乱数受け渡しによるバグの再現性は 同様にして有効であることが
    わかった</li>
  <li>描画をしないビデオモードによるテスト時間の高速化は、描画をする場合に
  比べて 非常に効果があった</li>
</ul>
</div>

<div class="slide">
<h1>今後の課題</h1>
<ul class="simple">
  <li>描画処理におけるバグの修正</li>
  <li>Cerium におけるメモリアロケータの実装</li>
</ul>
</div>

</div>
</body>
</html>