前回はtexSubImage2Dを高速化したのですが、今回はString.splitを削減してみました。従来は、JavaScriptから投げたディスプレイリストのコマンドをパースする際に単純にdl.split(";")としていたんですが、これをやってしまうと、ものすごい数のStringオブジェクトが新規確保されてしまいます。最近の端末で一番コストの高い処理はメモリ確保なので、これだけでペナルティが随分大きかったのです。

どれぐらいペナルティが大きかったかというと、全体の20%をsplit関数だけに費やしてしまうぐらい重かったのです。そこで、ディスプレイリストをパースするクラスを作って、
public int pop_int()
{
if(m_pos>=m_len)
return 0;
// Check for a sign.
int num = 0;
int sign = -1;
final char ch = m_p_dl.charAt( m_pos );
m_pos++;
if ( ch == '-' )
sign = 1;
else
num = '0' - ch;
// Build the number.
while ( m_pos < m_len ){
char c=m_p_dl.charAt( m_pos );
m_pos++;
if(c==';'){
break;
}
num = num*10 + '0' - c;
}
return sign * num;
}
のように、charAtを使用してパースするように変更しました。これで、メモリの新規確保が発生しなくなるので、劇的に速くなります。

最適化結果がこれです。ゲームコアの実行後にあったsplitがごっそり無くなって、バランスのいい処理負荷になっています。これで、オブジェクト数が増えても大分実用的な速度になってきます。
iOSはObjectiveC、AndroidはJAVA、WindowsPhone7はC#と、言語がばらばらすぎるので、ゲームコアをJavaScriptにして、ライブラリ部だけをネイティブで書く実装は今後増えてくるのかなと思っています。その際の高速化のポイントは、
(1)HttpリクエストではなくStringでまとめて命令をネイティブに渡す
(2)GLUtilのtexSubImage2Dは縦幅が指定できないので、
copyPixelToBufferを挟んだ上で、GL10.glTexSubImage2Dを使う
(3)Stringのsplitは遅すぎるのでメモリ確保の発生しないcharAtベースの自作パーサを使う
の三点になりそうです。

どれぐらいペナルティが大きかったかというと、全体の20%をsplit関数だけに費やしてしまうぐらい重かったのです。そこで、ディスプレイリストをパースするクラスを作って、
public int pop_int()
{
if(m_pos>=m_len)
return 0;
// Check for a sign.
int num = 0;
int sign = -1;
final char ch = m_p_dl.charAt( m_pos );
m_pos++;
if ( ch == '-' )
sign = 1;
else
num = '0' - ch;
// Build the number.
while ( m_pos < m_len ){
char c=m_p_dl.charAt( m_pos );
m_pos++;
if(c==';'){
break;
}
num = num*10 + '0' - c;
}
return sign * num;
}
のように、charAtを使用してパースするように変更しました。これで、メモリの新規確保が発生しなくなるので、劇的に速くなります。

最適化結果がこれです。ゲームコアの実行後にあったsplitがごっそり無くなって、バランスのいい処理負荷になっています。これで、オブジェクト数が増えても大分実用的な速度になってきます。
iOSはObjectiveC、AndroidはJAVA、WindowsPhone7はC#と、言語がばらばらすぎるので、ゲームコアをJavaScriptにして、ライブラリ部だけをネイティブで書く実装は今後増えてくるのかなと思っています。その際の高速化のポイントは、
(1)HttpリクエストではなくStringでまとめて命令をネイティブに渡す
(2)GLUtilのtexSubImage2Dは縦幅が指定できないので、
copyPixelToBufferを挟んだ上で、GL10.glTexSubImage2Dを使う
(3)Stringのsplitは遅すぎるのでメモリ確保の発生しないcharAtベースの自作パーサを使う
の三点になりそうです。
コメント