忍者ブログ

2024
05
03

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

2024/05/03 (Fri.)

2012
05
27

値渡しとポインタ渡しで実行速度比較(C言語)

「C言語には値渡ししかないんだよ」みたいな突っ込みは置いておいて、
会社でCの関数書いてるときにどうでもいいローカル変数(関数先で値を変えない)を
値渡しにするか、constつけてポインタ渡しにして渡すかで速度変わるのかなーとか
ぼんやり考えていたから実際に試してみた。
(実験プログラムでは、関数の引数でポインタとしている仮引数にconstを付けていないが、
関数先で値を変わってくることを期待していない変数であればconstをつけたほうがよいと思います。)

実験1 関数内で渡した変数に何もしない

/* pointer-test_none.c */
#define TRIAL_COUNT 100000000

void numeric(int a);
void pointer(int *a);

int main(void)
{
	int i, num = 1;
	for (i = 0; i < TRIAL_COUNT; i++) {
#if defined(POINTER)
		pointer(&num);
#else
		numeric(num);
#endif
	}
	return 0;
}

void numeric(int i)
{
	;
}

void pointer(int *i)
{
	;
}

実験1のコンパイル&結果

gcc -w -Wall -DPOINTER -o pointer-test_none pointer-test_none.c # コンパイル
time ./pointer-test_none # 実行
./pointer-test_none  0.30s user 0.00s system 102% cpu 0.292 total
./pointer-test_none  0.29s user 0.00s system 99% cpu 0.291 total
./pointer-test_none  0.30s user 0.00s system 102% cpu 0.292 total
./pointer-test_none  0.30s user 0.00s system 102% cpu 0.292 total
./pointer-test_none  0.30s user 0.00s system 102% cpu 0.294 total

gcc -w -Wall -o pointer-test_none pointer-test_none.c # コンパイル
time ./pointer-test_none # 実行
./pointer-test_none  0.32s user 0.00s system 100% cpu 0.318 total
./pointer-test_none  0.32s user 0.00s system 100% cpu 0.317 total
./pointer-test_none  0.32s user 0.00s system 100% cpu 0.318 total
./pointer-test_none  0.32s user 0.00s system 100% cpu 0.318 total
./pointer-test_none  0.32s user 0.00s system 100% cpu 0.317 total

# 結果
値渡しのほうが、関数内で使う仮引数に値を一度コピーしているんだっけか、
速度がポインタ渡しのほうが速い結果となった。

実験2 関数内で渡した変数に10回アクセスする

/* pointer-test_sum.c */
#define TRIAL_COUNT 100000000
#define ACCESS_COUNT 10

void numeric(int a);
void pointer(int *a);

int main(void)
{
	int i, num = 1;
	for (i = 0; i < TRIAL_COUNT; i++) {
#if defined(POINTER)
		pointer(&num);
#else
		numeric(num);
#endif
	}
	return 0;
}

void numeric(int a)
{
	int i, sum = 0;
	for (i = 0; i < ACCESS_COUNT; i++) {
		sum += a;
	}
}

void pointer(int *a)
{
	int i, sum = 0;
	for (i = 0; i < ACCESS_COUNT; i++) {
		sum += *a;
	}
}

実験2のコンパイル&結果

gcc -w -Wall -DPOINTER -o pointer-test_sum pointer-test_sum.c # コンパイル
time ./pointer-test_sum # 実行
./point-test_sum  2.56s user 0.00s system 100% cpu 2.557 total
./point-test_sum  2.57s user 0.00s system 100% cpu 2.570 total
./point-test_sum  2.56s user 0.00s system 100% cpu 2.558 total
./point-test_sum  2.56s user 0.00s system 100% cpu 2.557 total
./point-test_sum  2.56s user 0.00s system 100% cpu 2.557 total

gcc -w -Wall -o pointer-test_sum pointer-test_sum.c # コンパイル
time ./pointer-test_sum # 実行
./point-test_sum  2.44s user 0.00s system 100% cpu 2.438 total
./point-test_sum  2.44s user 0.00s system 100% cpu 2.432 total
./point-test_sum  2.44s user 0.00s system 100% cpu 2.432 total
./point-test_sum  2.42s user 0.01s system 99% cpu 2.431 total
./point-test_sum  2.44s user 0.00s system 100% cpu 2.434 total


# 結果
ポインタ渡しをして、ポインタ介して変数の値をいちいち参照しているのか、
何度もアクセスすると、速度が値渡しのほうが速い結果となった。

実験3 関数内で渡した複数の変数に10回アクセスする

/* pointer-test_sum_many.c */
#define TRIAL_COUNT 100000000
#define ACCESS_COUNT 10

void numeric(int a, int b, int c);
void pointer(int *a, int *b, int *c);

int main(void)
{
	int i, num1 = 1, num2 = 2, num3 = 3;
	for (i = 0; i < TRIAL_COUNT; i++) {
#if defined(POINTER)
		pointer(&num1, &num2, &num3);
#else
		numeric(num1, num2, num3);
#endif
	}

	return 0;
}

void numeric(int a, int b, int c)
{
	int i, sum = 0;
	for (i = 0; i < ACCESS_COUNT; i++) {
		sum += (a + b + c);
	}
}

void pointer(int *a, int *b, int *c)
{
	int i, sum = 0;
	for (i = 0; i < ACCESS_COUNT; i++) {
		sum += (*a + *b + *c);
	}
}

実験3のコンパイル&結果

gcc -w -Wall -DPOINTER -o pointer-test_sum_many pointer-test_sum_many.c # コンパイル
time ./pointer-test_sum_many # 実行
./point-test_sum_many  3.21s user 0.00s system 100% cpu 3.208 total
./point-test_sum_many  3.21s user 0.00s system 100% cpu 3.206 total
./point-test_sum_many  3.21s user 0.00s system 100% cpu 3.208 total
./point-test_sum_many  3.21s user 0.00s system 99% cpu 3.211 total
./point-test_sum_many  3.20s user 0.02s system 100% cpu 3.214 total
./point-test_sum_many  3.15s user 0.08s system 100% cpu 3.226 total

gcc -w -Wall -o pointer-test_sum_many pointer-test_sum_many.c # コンパイル
time ./pointer-test_sum_many # 実行
./point-test_sum_many  2.68s user 0.02s system 100% cpu 2.696 total
./point-test_sum_many  2.70s user 0.00s system 100% cpu 2.699 total
./point-test_sum_many  2.70s user 0.00s system 100% cpu 2.693 total
./point-test_sum_many  2.69s user 0.01s system 100% cpu 2.698 total
./point-test_sum_many  2.70s user 0.00s system 100% cpu 2.696 total

# 結果
コピーする仮引数の数が増えればとポインタ渡しのほうが速くなるかなと思ったが、
ポインタ介して変数の値を参照する回数のほうが今回の実験では影響大なためか
値渡しのほうが速い結果となった。

実験4 関数内で渡した複数の変数に10回アクセスする (ローカル変数に一度コピー)

本末転倒だが、ポインタで渡した変数の中身を、ローカル変数に一度コピーして
実験してみた。
/* pointer-test_sum_many2.c */
#define TRIAL_COUNT 100000000
#define ACCESS_COUNT 10

void numeric(int a, int b, int c);
void pointer(int *a, int *b, int *c);

int main(void)
{
	int i, num1 = 1, num2 = 2, num3 = 3;
	for (i = 0; i < TRIAL_COUNT; i++) {
#if defined(POINTER)
		pointer(&num1, &num2, &num3);
#else
		numeric(num1, num2, num3);
#endif
	}

	return 0;
}

void numeric(int a, int b, int c)
{
	int i, sum = 0;
	for (i = 0; i < ACCESS_COUNT; i++) {
		sum += (a + b + c);
	}
}

void pointer(int *a, int *b, int *c)
{
	int i, sum = 0;
	int aa = *a, bb = *b, cc = *c;    /* <- koko!! */
	for (i = 0; i < ACCESS_COUNT; i++) {
		sum += (aa + bb + cc);
	}
}

実験4のコンパイル&結果

gcc -w -Wall -DPOINTER -o pointer-test_sum_many2 pointer-test_sum_many2.c # コンパイル
time ./pointer-test_sum_many2 # 実行
./point-test_sum_many2  2.97s user 0.00s system 100% cpu 2.967 total
./point-test_sum_many2  2.97s user 0.00s system 100% cpu 2.963 total
./point-test_sum_many2  2.97s user 0.00s system 100% cpu 2.964 total

gcc -w -Wall -o pointer-test_sum_many2 pointer-test_sum_many2.c # コンパイル
time ./pointer-test_sum_many2 # 実行
./point-test_sum_many2  2.69s user 0.00s system 100% cpu 2.689 total
./point-test_sum_many2  2.70s user 0.00s system 100% cpu 2.692 total
./point-test_sum_many2  2.69s user 0.00s system 100% cpu 2.688 total

# 結果
ポインタ介してアクセスする回数が減ったけども、ローカル変数に一度コピーする
ことが影響しているのか、ただ値渡しにするよりもポインタ渡しのほうが遅い結果となった。

実験のまとめ

・関数内で引数で渡してきた変数の中身に何度もアクセスしないのであれば、
ポインタ渡しのほうが速い(仮引数を作りコピーする処理がないため)
※冒頭でも書きましたが、上記の場合はconstをつけたほうが見る人は、
「この変数は関数の先で変わってくることを期待していないんだな」とわかるので、
つけたほうがいいと思います。
・逆に何度もアクセスするのであれば、値渡しにしてしまったほうが速い
(ポインタ介して値を引っ張ってくるため(であってる?))

検索用タグ C言語 実行速度

拍手[3回]

PR

2012/05/27 (Sun.) Comment(0) C言語

Comments

名前
メールアドレス
URL
コメント
PASS  Vodafone絵文字 i-mode絵文字 Ezweb絵文字

ブログ内検索

最新記事

カテゴリー

アーカイブ

フリーエリア





プロフィール

HN:
nex2t
年齢:
8
性別:
男性
誕生日:
2016/01/01
職業:
開発エンジニア(ソフト)
趣味:
ラグビー 犬 将棋 ラーメン サーフィン(ネット)
自己紹介:
入社2年目の組込みエンジニア
好きな言語:C言語
エディタ:emacs
シェル:zsh
ディストリ:Scientific Linux, Ubuntu
略歴
お仕事のほう
2011/3 調布にある大学卒業
2011/4~6月 研修
2011/7~12月? 10GのLANドライバをがんばる
2012/1~2012/4月? VDCPデーモンを作る
2012/5~2012/10月? genlockデーモンを作る
~(現在) 装置テストなど

趣味などのほう
~2012年4月 自由気ままに。仕事の勉強など。歯医者に時間を取られる。
2012年4月~2012年6月 機動力が増す(バイクの免許&バイク(125ccの原付をゲットする)
2012年6月~2012年8月 将棋のネットゲームを作る(引きこもる)((こころざし半ば)
2012年7月~2012年8月 通勤途中にバイクでこけて('自損)、1か月チャリ通の刑になる
2012年9月~現在(2013年3月) DDRばかりする(主にDP)

(↑2013/3/10更新)

DDRのほう
------------------------------------------
・199?年 小学校高学年。
よく遊ぶ友達内でDDRが流行る。
3rdが家にあり、家庭用マットもあったが、ゲーセンでプレイすることは皆無。
(コロコロコミックとガブリチュウを買うと小遣いがなくなるぐらいしかお金がない)
Burtyfly、DAM DARIRAMとかの誰でも聞いたことあるような曲、DEAD END、Paranoia Rebirth、AFRONOVAとかちょっと難しい曲、
BUMBLE BEE、End of the Centuryとかいい感じで印象に残っている。
GRADIUSIC CYBERが当時意味不明で難しいなと思っていた。
ハンドクラップの他にもメトロノームとかついてた気がする。
スコアとかを気にしたことはなかった。
------------------------------------------
・199?年 中学。
4thを中古で購入。半年に1回ぐらいプレイしてた?(手でやるだけ)。
ワンダ・古畑・HERO・ピンクダイナソー・オリオン・DROP OUT(当時とても速かった)とかが印象に残っている。
---------------------------------------------
・200?年 高校。
MAXを中古で買って、たまにやっていた。ゲーセンに1クレだけ踏みに行ったりしてた。
SO DEEP、天ヒー、象さん、ウィッチドクター、トワイライトゾーン、MAX300が印象に残っている。
この頃、MAX300 SPのリズム(ダンダン ダダンダ(ry)が体に染みついた模様笑。
なおMAXは友人に貸したままの模様。
------------------------------------------
・200?年 大学。
数か月に1回、ストレス発散がてら踏んでいた。確かXとかX2だった気がする。
踏むのは決まって8分でけっこう踏んだ気になる、AFRONOVA、天ヒー、象さん。
Aランクとか出せたことがなかった。
---------------------------------------------
・2012年9月 社会人 X3
コミケ準備のため引きこもっていた反動で、外出ばかりする。
ゲーセンで久々にプレイするととても楽しい(画面もきれいでパネルの反応も良い)。
今まで適当にやってきたが、少しシステムとかスコアを気にし始める。
自分のお金ということもあり、ゲーセンで千円単位でお金を使うことが自然になり、
真面目にDDRをするようになる。
------------------------------------------
・2012年12月 X3
SPしかやったことがなかったが、当時よく通ったゲーセンがDPする人が多く、
楽しそうだったので、DPをやり始める、足の裏の皮がむける。
---------------------------------------------
・2013年4月? X3終了。 DDR2013へ
X3はSP足鳳凰、DP足龍で終了。DPは足12以下の好きな曲のみフルコンができるような具合だった。
------------------------------------------
・2013年7月 ついったーで記録をつけるようになる。
8月4日 足10以下の激譜面AA埋め達成。鬼鯖初クリア
8月10日 足11以下の激譜面AA埋め達成。
8月24日 DDR2013 1000クレ行く。
9月8日 足12以下の激譜面AA埋め達成。
10月   (私用でドタバタする。)
11月2日 Skill pointが1000行く。
11月3日 岐阜のDDR大会 DPノンバー部門参加(予選通過ならず)
11月16日 DP足鳳凰。(エレクリDDPフルコン)
11月22日 足13以下の激譜面AA埋め達成。
11月24日 DP足紙さま?。(苺プリンDDPフルコン、鬼鯖810k同時だった)
Double AA Line 14になる。
現在~  足14のAA埋め、足15のA取得、足13の鳥取りを頑張り中。
------------------------------------------
(↑2013/11/28追加)

最新CM

[06/01 履歴書の書き方]

カウンター