Mercurial > hg > Papers > 2011 > kaito-master
view paper/cerium.tex @ 10:f07976c75b7e
cerium not yet.
author | tkaito |
---|---|
date | Tue, 25 Jan 2011 16:19:21 +0900 |
parents | 19d1ef61a0d5 |
children | 4d67bd445a1d |
line wrap: on
line source
\chapter{Cerium} \label{chapter:cerium} \section{Cell 用の Fine-Grain Task Manager} Cerium \cite{gongo} は Cell 用の Fine-Gerain Task Manager として同研究室の宮國が実装した。 本章ではその実装について説明し、改良された点を紹介する。 \section{Cerium の概要} Cerium は、我々が提案したゲーム開発のフレームワークで、TaskManager (\ref{sec:cerium_taskmanager}), SceneGraph (\ref{sec:cerium_scenegraph}) と Rendering Engine (\ref{sec:cerium_renderingengine}) の 3つの要素から構成されており、PS3, Mac OS X, Linux 上でゲームフレームワークとして動作する。ゲーム中の オブジェクトの振る舞いやルールは SceneGraph で管理し、それらの動きや Rendering の処理を動的に SPE に 割り振るカーネルとして、TaskManager が用いられる。PS3 の Graphics Engine の仕様は公開されておらず、 Cerium は独自の Rendering Engine を有している。 \subsection{Task Manager} \label{sec:cerium_taskmanager} Task Manager は、 Task と呼ばれる、分割された各プログラムを管理する。 Task の単位は サブルーチンまたは関数として、 Task 同士の依存関係を考慮しながら実行していく。 先行研究において実装されていた TaskManager の API を \tabref{old_taskmanager_api} に示す。 \begin{table}[htb] \caption{旧Task Manager API} \label{tab:old_taskmanager_api} \hbox to\hsize{\hfil \begin{tabular}{c|l} \hline \hline create\_task & Task を生成する \\ \hline run & 実行 Task Queue の実行 \\ \hline allocate & 環境のアライメントを考慮した allocator \\ \hline \hline add\_inData & Task への入力データのアドレスを追加 \\ \hline add\_outData & Task からのデータ出力先アドレスを追加 \\ \hline add\_param & Task のパラメータ (32 bits) \\ \hline wait\_for & Task の依存関係の考慮 \\\hline set\_cpu & Task を実行する CPU の設定 \\ \hline set\_post & Task が終了したら PPE 側で実行される関数の登録 \\ \hline spawn & Task を実行 Task Queue に登録する \\ \hline \end{tabular}\hfil} \end{table} \subsection{Cerium における Task} Task は TaskManager を使って生成する。 Task を生成する際に、以下のような様相が設定可能 である。 \begin{enumerate} \item input data \item output data \item parameter \item cpu type \item dependency \end{enumerate} input, output, data, parameter は関数でいうところの引数に価する。cpu type は Task が PPE または SPE のどちらで実行されるかを示している。 dependency は他の Task との 依存関係を示している。依存関係の情報は PPE 側が持っており、 SPE, PPE の Task が終了 すると、Task の終了が通知され、その通知に従って PPE が依存関係を処理していく(例: Task A の終了通知を受け、 PPE は Task B を実行可能状態にする)。Task の依存関係の 処理を図を用いて説明する。\\ Task B は Task A の終了を待っている。他の Task の終了を待っている Task は、Wait Queue に、 Task を待っていない Task は Active Queue に入れる。この時点で Task A が先頭にあるので Task A が SPE に送られる(\figref{task-dependency1})。 \begin{figure}[htb] \begin{center} \includegraphics[scale=0.68]{./images/task-dependency1.pdf} \end{center} \caption{Task dependency 1} \label{fig:task-dependency1} \end{figure} \newpage そして、SPE に送られた Task A は SPE で処理が行われる(\figref{task-dependency2})。 \begin{figure}[htb] \begin{center} \includegraphics[scale=0.68]{./images/task-dependency2.pdf} \end{center} \caption{Task dependency 2} \label{fig:task-dependency2} \end{figure} Task A の処理が終了すると mail で Task B へ通知される。Task B はその通知を受け取ると 待ち状態が解除される(\figref{task-dependency3})。 \begin{figure}[htb] \begin{center} \includegraphics[scale=0.68]{./images/task-dependency3.pdf} \end{center} \caption{Task dependency 3} \label{fig:task-dependency3} \end{figure} 待ち状態が解除された Task B は、Active Queue に追加され、 この図(\figref{task-dependency4})では、Task C 終了後に SPE に送られ処理が行われる。 \begin{figure}[htb] \begin{center} \includegraphics[scale=0.68]{./images/task-dependency4.pdf} \end{center} \caption{Task dependency 4} \label{fig:task-dependency4} \end{figure} \newpage \subsection{Task のスケジューリング} SPE は、Task を一つずつ受け取るのではなく、ある程度まとめて受け取る。それを TaskList と呼んでいる。 TaskList に沿って Task を実行していき、 Task 毎に実行完了の Mail を送る。 TaskList の Task をすべて実行すると、次の TaskList を要求する Mail を PPE 側に送る。 \subsection{新しい API} \label{sec:taskarray} 以下に新しく追加した API 、仕様の変更があった API を \tabref{new_taskmanager_api} に示す。 \begin{table}[htb] \caption{Task Manager API} \label{tab:new_taskmanager_api} \hbox to\hsize{\hfil \begin{tabular}{c|l} \hline \hline create\_task\_array & Task Array を生成する \\ \hline \hline set\_inData & add\_inData から変更 \\ \hline set\_outData & add\_outData から変更 \\ \hline set\_param & add\_param から変更 \\ \hline next\_task\_array & Task Array 内の Task の実行順を設定する\\ \hline spawn\_task\_array & Task Array を実行 Task Queue に登録する \\ \hline \end{tabular}\hfil} \end{table} 以下に Task Array を用いた記述例を示す。このプログラムは Task Array に複数の同一 Task を 登録して、まとめて実行するというプログラムである。各 API の詳細は後述する。 \begin{verbatim} void hello_init(TaskManager *manager) { /** * Create Task * create_task(Task ID); */ /*うしろ3つ param/inData/outData の数を指定する*/ HTask *twice_main = manager->create_task_array(Hello,task_num,data_count, data_count,data_count); Task *t = 0; for(int i = 0;i<task_num;i++) { t = twice_main->next_task_array(Hello, t); } twice_main->spawn_task_array(t->next()); twice_main->set_cpu(SPE_ANY); twice_main->spawn(); } static int run(SchedTask *s,void *rbuf, void *wbuf) { s->printf("Hello World\n"); return 0; } // 実行結果 % ./hello -task 6 Hello World Hello World Hello World Hello World Hello World Hello World \end{verbatim} プログラムに用いられてる新しい API について説明する。\\ \begin{description} \item[create\_task\_array: ] 同一の Task を複数持つことのできる Task Array を生成する。 Task Arrayについては\ref{sec:taskarray}節で詳しく説明する。 \item[next\_task\_array: ] Task Array に Task を実行順序を定める。実行順序は next\_task\_array を行った順になる。 \item[spwan\_task\_array: ] Task Array の中のすべての Task が書きこまれたかどうかをチェックする。 \end{description} また、仕様変更になった Task に引き渡すデータを管理する API (set\_inData, set\_outData, set\_param) について 説明する。\\ これまで Task のデータは add\_inData, add\_outData, add\_param された順に read\/write buffer に書きこまれていた。 しかし、これではデータ数が多くなった場合に管理するのが難しくなる恐れが出てきた。例えば、100個のデータをadd\_inData した場合、特定のデータを取り出す際にそのデータが何番目にadd\_inDataされたのかを知らなければならない。この問題を解決するために、 in\/outのData と param を buffer の任意の場所に書き込めるように仕様を変更した。これは規模の大きな例題を作成するようになって 分かった問題の一つである。 \subsection{Task Array} 新しく追加された Task 「 Task Array 」について説明する。 WordCount の場合、対象となるファイルによって大量の Task が生成される。PPE 側で実行される Task もあるなかで、 大量の Task を一つ一つの Task 毎に依存関係を処理していては、SPE からの TaskList 要求への反応が遅れ、 SPE の 待ち時間が生じてしまうと考えられる。この問題を解決するために、我々は Task Array を提案、実装した。 Task Array は、複数の Task をまとめて扱うことが出来る。Task Array に登録した順番で 依存関係を設定しているので、PPE で解決する Task の数が減り、 SPE からの TaskList 要求に応答しやすくなる。 また、一度に多くの Task を TaskList に登録できるため、 SPE 側からの TaskList 要求の回数が減り、待ち時間が 生じる可能性が減る。さらに Task Array の処理時間が長くなれば、DMA の転送時間を隠すことにも繋がる。Word Count と Rendering Engine において、Task Array の効果を検証した\cite{jssst-yutaka}。 \subsection{Task Array 化による検証} \subsubsection{Word Count の Task} まずは例題の Word Count の Task について説明する。 Word Count の Task は以下の二つである。 \begin{enumerate} \item WordCountTask \item PrintTask \end{enumerate} WordCountTask は、 input で与えられた data を word count し、 output data に書きだす Task である。PrintTask は すべての WordCountTask の実行完了を待ち、 output へ書き出された値を集計し出力する Task である。一度に SPE に 送信できるデータ容量は DMA の仕様上 16Kbyte が限界である。また、転送するデータは 16 の倍数 byte である必要がある。 \subsubsection{WordCountTask の Task Array 化} Task Array 一つに、64 個 の Task を入れ、 Word Count 対象は 166MB のテキストファイルとした。 Task Array を 適用した場合と、そうでない場合で比較する。 6 個の SPE を使用し、実行にかかった時間を time, SPE 稼働時間における DMA 転送待ち時間の割合を dma wait, SPE 稼働時間における次の TaskList の mail 待ち時間の割合を mail wait とする。 以下に表で示す( \tabref{wc-taskarray-compare} )。割合に SPE 6 個の平均で示している。この時の Task 数は約 1 万である。 \begin{table}[htb] \begin{center} \caption{Word Count の Task Array 化による比較} \label{tab:wc-taskarray-compare} \begin{tabular}{|c|c|c|c|} \hline & Task & Task Array & 向上率\\ \hline \hline time & 2.184s & 2.109s & 3.5\% \\ \hline dma wait & 18\% & 12\% & 6\% \\ \hline mail wait & 5\% & 8\% & -3\%\\ \hline \end{tabular} \end{center} \end{table} 表に示した結果より、著しい Task Array の効果は見られなかった。この結果は Word Count においては誤差の範囲内である。 効果が見られなかった原因はおそらく Word Count の場合は PPE 皮の Task が無いので、依存関係の処理にほとんど待ち時間が 発生しなかったからだと考えられる。また、Word Count ではファイルをメモリにマッピングするので、ファイルの容量が 大きい場合に大量にメモリを消費してしまう。その結果スワップが起きやすくなり、DMA 転送待ち時間が長くなっている 可能性がある。この解決策として、一度にファイルをすべてマッピングするのではなく、切り分けてマッピングするのが 良い。Word Count が終わった領域に、次の Word Count に必要な領域を入れ替えて使うことでメモリを節約でき、 スワップを減らすことができる。その結果メモリアクセスが高速になり、DMA 転送の待ち時間も削減できる。 \subsubsection{Rendering Engine の Task} Rendering Engine は主に CreatePolygon, CreateSpan, DrawSpan という三つの Task から構成されている。 Rendering Engine の詳しい説明は後述する( \ref{sec:renderingengine} )。 \subsubsection{Rndering Engine の Task Array 化} Rendeing Engine の中で、最も数が多く生成される DrawSpanTask を Task Array 化した。 地球と月を表示する例題を対象に効果を検証した(\tabref{rendering-taskarray-compare})。 FPS(Frame Per Second) は、一秒間に 表示できる Frame 数のことである。 \begin{figure}[htb] \begin{center} \includegraphics[scale=0.8]{./images/universe.pdf} \end{center} \caption{地球と月を表示する例題} \label{fig:universe} \end{figure} \begin{table}[htb] \begin{center} \caption{Word Count の Task Array 化による比較} \label{tab:rendering-taskarray-compare} \begin{tabular}{|c|c|c|c|} \hline & Task & Task Array & 向上率\\ \hline \hline FPS & 3.94 & 4.32 \% & 9.6\%\\ \hline dma wait & 0.06\% & 0.07\% & 0.01\%\\ \hline mail wait & 55\% & 42\% & -13\% \\ \hline \end{tabular} \end{center} \end{table} 結果から DrawSpanTask を Task Array 化すると、FPS が上昇し、mail の wait 時間が減ったことが分かる。 Rendering Engine では、 PPE 側でも処理をするべき Task があり、常に PPE が稼動している状態になって いる。そのため mail を処理する時間が遅れ、SPE のmail 待ちが発生していると考えられる。 Task Array 化 で Task をまとめることで SPE が一つの TaskList で多くの Task を実行できるようになったため、 TaskList を要求する回数が減って、待ち時間が発生する回数も減少した。また、それは SPE からの mail の数が減った ということなので、PPE 側の mail 処理の時間短縮になったと考えられる。 \subsection{Task Array 化による検証の結果} Task Array の効果が表れるのは、PPE 側に実行すべき Task があり、PPE が常に稼動している場合ということが 分かった。 Word Count では、PPE 側の Task がなく、mail 待ちがほとんど起きていなかったので Task Array の 効果が無かった。大量のファイルをマッピングし、メモリを多く消費するのでメモリアクセスに時間がかかり、DMA 転送に待ち時間が発生したと考えられる。それによって、Task Array を用いても DMA 転送時間を覆い隠すことが できなかった。また、複数の SPE が同時にメインメモリにアクセスする際に、それぞれ離れた \begin{comment} \\ ###########################途中############################\\ \end{comment} ・Task を1種類に戻したい ・spu側からmailを送ったときにキューに溜まるようにした ・getsegmentを入れた理由 ・bussy rate ・queue info ・tasklistのdependencyが変わってる ・waitlistが残ってるのはdead lock deteption \subsection{SceneGraph} \label{sec:scenegraph} ・sgidの追加 \subsection{Rendering Engine} \label{sec:renderingengine} ・DrawSpan は常に動いているようにしたいー>pipelineの見直しが絶対に必要 ・pipelineに関連して double buffering の見直しも。 ・CreatePolygonFromSceneGraph ・検証よりもpipelineでちゃんと動くところを見せたほうがいい