コンテナクラスへのデータ登録のあれこれ
仕事でC++のSTLを用いて、vector<データ>みたいな定義をやっているソースで、「こいつのpush_backって構造体(やクラス)の大きさによっては。オーバーヘッドって結構大きいよなぁ~」思いながら、「C#でゲームを作っている場合で構造体を定義した場合はどれ位マズイんだろ?」と、最近フト思いました。
C++のSTLのコンテナクラスの場合は、データの内容によりpush_backは、そのデータのコピーとなるので、速度を考慮するゲームを作る場合は、必ず"データのポインタを登録"すると思います。
(ちなみに私のC++のサンプルソースのタスク管理でもそうしています)
vector::push_backを例に取って普通に考えると、"クラスをデータ"としてコンテナクラスに登録するだけで単純に
【1.クラスをデータとして登録】
1.登録のためのデータの領域の生成が走る。
2.データ(クラス)のためのコピー(コンストラクタ)が走る。
3.データが登録される(内部ポインタとして管理される)。
ので、この「1.」と「2.」の処理のオーバーヘッドが大きければ大きい程、実行時間がかかる訳です。
これがデータのポインタとなると、
【2.ポインタをデータとして登録】
1.データが登録される(内部ポインタとして管理される)。
だけなので、データの大きさやデータが基本データ型(intやfloat)の配列であろうが、構造体であろうが、クラスであろうが全て同じとなります(ただし演算子のオーバーロードとかしていたら、もしかして話が違うかもしれませんが)。
ようするに、「ポインタでないと、前者のように登録の際にデータはコピーされてしまい、場合によっては構築のための関数も呼び出される」という事が発生する訳です。
C#は好か不幸か、クラスのインスタンス管理はガベージコレクタのお仕事なので、コンテナクラス(この場合はListクラス)の場合に、クラス登録をする場合は、自然と後者の流れになりますが、Vector3のような「構造体」の場合は前者になります。
Windows上の.NET Framework(Xbox 360上のXNAでもいいや)の内部処理の部分が見えないので、憶測の域を出れない上に、クラスにあるVテーブルのような話を端折った上で、少しいい加減に書いて行きますが、XNAでよく使うVector3のような単純な構造体を例に考えると、Vector3はfloatのXYZを3つをメンバとして内包しています。
floatを32ビット環境で考えると4バイトであり、3つメンバがいるので、計12バイトのコピーが走ります。更にC#の仕様で構造体の初期化コードが走ると思うので、メンバをクリアする処理が走ります。
更にMatrixで考えるとfloatが16個あるので、Listにしてリアルタイムに登録なんてゾッとします。特にモーション処理にはMatrixの演算用に作成などはザラなので、ゾゾゾゾッとなりますね。
ネットで検索してみると、C#でオーバーヘッドを計測している方をちらほらと見受けられますが(素晴らしいですね)、16バイト程がこの辺りの境界になっているみたいです。
(あくまで推論のようですが)
この素晴らしい推論を鵜呑みにして検討した場合、Vector3程度の構造体はオーバーヘッドはそれほどでもないようにも感じられます。
わざわざVector3の構造体をクラス化して、Listに登録などはしなくても良いのかもしれません。
Vector3の演算はそこらじゅうで行うので、クラス化してその度にnewをするような処理が入った方が、かえってガベージコレクタがヒィヒィいって、とんでもない事になりそうです。
ナーバスになるのであれば、以前書いた「処理速度稼ぎのあれこれ (関数呼び出しの引数)」の方に注力を向ける方が賢そうです。
しかし、Matrix構造体は微妙ですね。ループ処理内などでMatrix構造体をnewする分には関数開始時にスタックに64バイト作られるだけで、後は生成されないと思いますが、「Listクラスへの登録」となると、ちょっとよくないような気がしないでもないです。Listクラス内への登録はスタックでもないくヒープにコピーが行われると思うので、これの生成と初期化コードが走ると思うと、完全に前者に近いノリになります。
とまぁ、想像を色々としてみましたが、結局のところ検証しないと、どの程度のものなのかは分らないのですけどね…
この辺りはCPUのパイプラインの性能もありますし、Vector3を描画のための頂点情報としてXNAの関数に渡すとなると、また別の次元の話にもなってきますし…(といっても、XNAの関数がListクラスを用いたGPUの処理のための最適化を行っているとは思えません)
でもまぁ、大した表現をしないゲームを今後ハイスペックになるであろうコンピュータで奏でる分には、「処理が間に合えば勝ち」な訳なので、とりあえず私の場合は現時点では気にしないことにします。
という感じで、ダラしないオチでした。(^^ゞ
(ちなみに私のC++のサンプルソースのタスク管理でもそうしています)
vector::push_backを例に取って普通に考えると、"クラスをデータ"としてコンテナクラスに登録するだけで単純に
【1.クラスをデータとして登録】
1.登録のためのデータの領域の生成が走る。
2.データ(クラス)のためのコピー(コンストラクタ)が走る。
3.データが登録される(内部ポインタとして管理される)。
ので、この「1.」と「2.」の処理のオーバーヘッドが大きければ大きい程、実行時間がかかる訳です。
これがデータのポインタとなると、
【2.ポインタをデータとして登録】
1.データが登録される(内部ポインタとして管理される)。
だけなので、データの大きさやデータが基本データ型(intやfloat)の配列であろうが、構造体であろうが、クラスであろうが全て同じとなります(ただし演算子のオーバーロードとかしていたら、もしかして話が違うかもしれませんが)。
ようするに、「ポインタでないと、前者のように登録の際にデータはコピーされてしまい、場合によっては構築のための関数も呼び出される」という事が発生する訳です。
C#は好か不幸か、クラスのインスタンス管理はガベージコレクタのお仕事なので、コンテナクラス(この場合はListクラス)の場合に、クラス登録をする場合は、自然と後者の流れになりますが、Vector3のような「構造体」の場合は前者になります。
Windows上の.NET Framework(Xbox 360上のXNAでもいいや)の内部処理の部分が見えないので、憶測の域を出れない上に、クラスにあるVテーブルのような話を端折った上で、少しいい加減に書いて行きますが、XNAでよく使うVector3のような単純な構造体を例に考えると、Vector3はfloatのXYZを3つをメンバとして内包しています。
floatを32ビット環境で考えると4バイトであり、3つメンバがいるので、計12バイトのコピーが走ります。更にC#の仕様で構造体の初期化コードが走ると思うので、メンバをクリアする処理が走ります。
更にMatrixで考えるとfloatが16個あるので、Listにしてリアルタイムに登録なんてゾッとします。特にモーション処理にはMatrixの演算用に作成などはザラなので、ゾゾゾゾッとなりますね。
ネットで検索してみると、C#でオーバーヘッドを計測している方をちらほらと見受けられますが(素晴らしいですね)、16バイト程がこの辺りの境界になっているみたいです。
(あくまで推論のようですが)
この素晴らしい推論を鵜呑みにして検討した場合、Vector3程度の構造体はオーバーヘッドはそれほどでもないようにも感じられます。
わざわざVector3の構造体をクラス化して、Listに登録などはしなくても良いのかもしれません。
Vector3の演算はそこらじゅうで行うので、クラス化してその度にnewをするような処理が入った方が、かえってガベージコレクタがヒィヒィいって、とんでもない事になりそうです。
ナーバスになるのであれば、以前書いた「処理速度稼ぎのあれこれ (関数呼び出しの引数)」の方に注力を向ける方が賢そうです。
しかし、Matrix構造体は微妙ですね。ループ処理内などでMatrix構造体をnewする分には関数開始時にスタックに64バイト作られるだけで、後は生成されないと思いますが、「Listクラスへの登録」となると、ちょっとよくないような気がしないでもないです。Listクラス内への登録はスタックでもないくヒープにコピーが行われると思うので、これの生成と初期化コードが走ると思うと、完全に前者に近いノリになります。
とまぁ、想像を色々としてみましたが、結局のところ検証しないと、どの程度のものなのかは分らないのですけどね…
この辺りはCPUのパイプラインの性能もありますし、Vector3を描画のための頂点情報としてXNAの関数に渡すとなると、また別の次元の話にもなってきますし…(といっても、XNAの関数がListクラスを用いたGPUの処理のための最適化を行っているとは思えません)
でもまぁ、大した表現をしないゲームを今後ハイスペックになるであろうコンピュータで奏でる分には、「処理が間に合えば勝ち」な訳なので、とりあえず私の場合は現時点では気にしないことにします。
という感じで、ダラしないオチでした。(^^ゞ
コメント
コメントの投稿
« 昔のゲームの想い出 [0083] 「ハイウェイスター」 [スクウェア] [1987] [ファミリーコンピュータ] l Home l 昔のゲームの想い出 [0082] 「サンダーフォースIII」 [テクノソフト] [1990] [メガドライブ] »