Pentanium Reactor Blog

ゲーム、アニメ、CG、プログラミング

でObjective-Cって遅いの?

2010年09月12日 05時11分48秒 | プログラミング
iswebが10月末で無料サービス終了らしいのでwebページどうしようかと考え中の今日この頃。

さて、先日ちょっとObjective-CとCの速度差というのを見かけて気になったので実験してみた。
とりあえず元のソースを見ると、このCのバージョンをObjective-Cに移植するとしてこう書くか?と思えた代物なのでちょっと変更。
まずは
@interface Surface : NSObject
{
	float x;
	float y;
}
@property (nonatomic, readwrite) float x;
@property (nonatomic, readwrite) float y;
@end

@implementation Surface
@synthesize x;
@synthesize y;
@end

こんなクラスを用意して
lineArray = [[NSMutableArray alloc] init];

for (int i = 0; i < size.width + 1; i++) {
	Surface *tmp = [[[Surface alloc] init] autorelease];
	tmp.x = i;
	tmp.y = 0;
	[lineArray addObject:tmp];
}

って初期化して
for (int i = 0; i < screenWidth; i++) {
	Surface *tempSurface = [lineArray objectAtIndex:i];
	if (tempSurface.x > screenWidth) {
		tempSurface.x = 0;
	} else {
		tempSurface.x += 2;
	}

	CGFloat y = 8.0f * cosf(i / 60.0f * 3.14);
	ccDrawLine( ccp(screenWidth - tempSurface.x, 40 + y), ccp(screenWidth - tempSurface.x, -screenHeight) );
}

って描画するのでどうかなと。
そして残念ながら私はiPhone4を持っていないので3Gsでテストしてみると、結果は惨敗。
あまり改善しなかった。
それじゃとりあえず試しに
int i = 0;
for ( Surface *tempSurface in lineArray ) {
	if (tempSurface.x > screenWidth) {
		tempSurface.x = 0;
	} else {
		tempSurface.x += 2;
	}

	CGFloat y = 8.0f * cosf(i / 60.0f * 3.14);
	ccDrawLine( ccp(screenWidth - tempSurface.x, 40 + y), ccp(screenWidth - tempSurface.x, -screenHeight) );
	++i;
}

こうしてみる。Fast Enumuration。
これで意外と改善して、惜しくも60fpsに届かず50台という感じに。
それじゃお次は
@interface Surface : NSObject
{
	@public
	float x;
	float y;
}
@property (nonatomic, readwrite) float x;
@property (nonatomic, readwrite) float y;
@end

と@publicをくっつけて
int i = 0;
for ( Surface *tempSurface in lineArray ) {
	if (tempSurface->x > screenWidth) {
		tempSurface->x = 0;
	} else {
		tempSurface->x += 2;
	}

	CGFloat y = 8.0f * cosf(i / 60.0f * 3.14);
	ccDrawLine( ccp(screenWidth - tempSurface->x, 40 + y), ccp(screenWidth - tempSurface->x, -screenHeight) );
	++i;
}

と->でメンバにアクセスしてみる。
メソッド呼び出しを減らそうという寸法。
これでぎりぎり60fpsという感じ。
最後に
for (int i = 0; i < screenWidth; i++) {
	Surface *tempSurface = [lineArray objectAtIndex:i];
	if (tempSurface->x > screenWidth) {
		tempSurface->x = 0;
	} else {
		tempSurface->x += 2;
	}

	CGFloat y = 8.0f * cosf(i / 60.0f * 3.14);
	ccDrawLine( ccp(screenWidth - tempSurface->x, 40 + y), ccp(screenWidth - tempSurface->x, -screenHeight) );
}

としてみると、上でFast Enumrationにしただけのものと大体同じくらい。
Fast Enumrationが速いというよりはメソッド呼び出しのキャッシングとかの影響が大きいんでしょうか?
よく知らずに適当に書いてますけど。

結論としては、メソッド呼び出しはやっぱり少しコストがかかる。とはいえ使い方次第、かな?

ちなみにこのサンプル、画面をスリスリすればCバージョンでも40fpsくらいになる。
一方で遅いObjective-Cバージョンでさらに落ちるかというと、そんなことはなくほとんど変わらず。
なので、そこまで気にしなくても良いんじゃないかな、なんて気もしました。