プラットホーム:IBM 2.8GHz Intel Pentium 4
OS:Windows XP Professional
開発環境:Visual C++ 6.0 SP6
プロジェクト:コンソールアプリケーション
素朴な疑問なのですが足し算の処理速度を知りたいと思い以下のような簡単なコードを作って実験してみました。
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main(void)
{
{
int count1 = GetTickCount();
int j = 0;
for(int i=1;i<=1000000000;i++)
j=j+1;
int count2 = GetTickCount();
printf("int + on 1000000000 loop\n");
printf("%2.3f 秒\n", (count2 - count1)/1000.0);
}
{
int count1 = GetTickCount();
int j = 0;
for(int i=1;i<=2000000000;i++)
{
j=j+1;
}
int count2 = GetTickCount();
printf("int + on 2000000000 loop\n");
printf("%2.3f 秒\n", (count2 - count1)/1000.0);
}
{
int count1 = GetTickCount();
int j = 0;
for(int i=1;i<=1000000000;i++)
{
j=j+1;
j=j+1;
}
int count2 = GetTickCount();
printf("int + & + on 1000000000 loop\n");
printf("%2.3f 秒\n", (count2 - count1)/1000.0);
}
{
int count1 = GetTickCount();
int i = 1;
Jump:
i++;
if(i <= 1000000000)
goto Jump;
int count2 = GetTickCount();
printf("semi for on 1000000000 loop\n");
printf("%2.3f 秒\n", (count2 - count1)/1000.0);
}
{
int count1 = GetTickCount();
for(int i=1;i<=1000000000;i++);
int count2 = GetTickCount();
printf("for on 1000000000 loop\n");
printf("%2.3f 秒\n", (count2 - count1)/1000.0);
}
return 0;
}
結果が以下のようになりました。
int + on 1000000000 loop
2.173 秒
int + on 2000000000 loop
4.367 秒
int + & + on 1000000000 loop
5.227 秒
semi for on 1000000000 loop
1.783 秒
for on 1000000000 loop
1.762 秒
Press any key to continue
このコードで本当に正確な計測ができているのかどうかさえ分からないのですが、結果を見ると「int + on 1000000000 loop」ではfor文と足し算を1000000000回繰り返して2.173秒掛かり、「int + on 2000000000 loop」ではfor文と足し算を2000000000回繰り返して4.367秒掛かることまでは、結果が約2倍となっていて理解できるのですが、「int + & + on 1000000000 loop」ではfor文と足し算ともうひとつ足し算を1000000000回繰り返して5.227秒掛かっています。処理的には「int + on 2000000000 loop」と「int + & + on 1000000000 loop」は同じことを実行しているのに結果が4.367秒と5.227秒となり約1秒も異なってしまいました。いったいなぜ「int + & + on 1000000000 loop」の方がより多くの時間が掛かってしまったのか理由が分からなくて投稿させていただきました。どなたかご教授よろしくお願いします。
またfor文の処理速度はどうなのだろうと思い、一応コードを考えて実行してみました。結果は「for on 1000000000 loop」では1.762秒と出ました。
・「int + on 2000000000 loop」
ループ条件比較処理・・・2000000000回
加算処理・・・2000000000回
カウンタインクリメント・・・2000000000回
・「int + & + on 1000000000 loop」
ループ条件比較処理・・・1000000000回
加算処理1つ目・・・1000000000回
加算処理2つ目・・・1000000000回
カウンタインクリメント・・・1000000000回
後者の方がループ条件比較・カウンタインクリメントそれぞれ1000000000回少ない分、約1秒速くなったのでしょう。
forループのみ1000000000回分の時間1.762秒より少ない時間増ですんでるのは
最適化の関係だと思います。
ご返答ありがとうございます。
>後者の方がループ条件比較・カウンタインクリメントそれぞれ1000000000回少ない分、約1秒速くなったのでしょう。
実は約1秒遅くなってしまっているのですが・・・。
コンパイルはDebugで行った結果は以前のようになったのですが、Releaseで行うと結果がすべて0秒になってしまいました。これも
>最適化の関係
なのでしょうか・・・。
このように結果がばらばらで最適化については考察もできずこれらの応答から足し算の処理速度をどのように算出すればよいのでしょう。
再度ご教授していただけると幸いです。
Release の最適化ルーチンが「ループ内で計算した結果を使わず捨ててる」と判断し、
ループごとごっそり最適化(=削除)しているため0秒になるのでしょう。
しかし最適化なしではデバッグコードが生成されたりとかして、何を計っているか不明になってしまいます。
とまあ、適切なベンチマークプログラムを書く、というのは結構難しいのです。
で、アセンブラは読めるのでしょうか?読める前提で、計りたいのは
1.機械語レベルでの add 命令の速度
2.C/C++ ソースコードレベルでの加算の速度1 (register 変数でよい)
3.C/C++ ソースコードレベルでの加算の速度2 (volatile 変数でよい)
のどれでしょうか?それによってソースコードは変わってくるはずです。
1.なら純粋に加算の速度算出が出来るが、jmp の影響を排除する必要がある。
3.なら変数読み書きのメモリアクセスの影響を受ける。
「加算」にどこまで含めるか、次第ですね。
この手の計測では一般に、測りたい対象コードをごっそり消されるといった最適化を
避けるために、時間計測外で結果を出力するなりして、ちゃんと計算は省略しちゃ駄目
ということをコンパイラに伝える必要があります。
お二方からもご返答をいただくことができてありがとうございます。
>アセンブラは読めるのでしょうか?
本を一通り読んだ程度なのですが。
>1.機械語レベルでの add 命令の速度
>2.C/C++ ソースコードレベルでの加算の速度1 (register 変数でよい)
>3.C/C++ ソースコードレベルでの加算の速度2 (volatile 変数でよい)
>のどれでしょうか?それによってソースコードは変わってくるはずです。
本当は「1.」のaddが計測したかったのですが、ご教授いただいてかなり難しそうな印象を受けました。機械語レベルはVC++の__asmブロックを用いられると独りでは構築できず・・・。
>1.なら純粋に加算の速度算出が出来るが、jmp の影響を排除する必要がある。
>3.なら変数読み書きのメモリアクセスの影響を受ける。
>「加算」にどこまで含めるか、次第ですね。
私にもできることならメモリアクセスの時間やジャンプの時間などを別々で知って後はこれらのデータを単純に線形和すれば予測できるというように思い描いていたのですが、和算一つにしても予想以上の処理をしていると分かって専門でもない私には一筋縄ではうまくいかないですね。和算がいったいどのような処理をしているのか機械語レベルから把握していないと計算できないですよね。
あとは勉強してくださいといわれればそれまでなのですが「1.」のaddが計測できるような方法をご教授いただけると幸いです。
> あとは勉強してくださいといわれればそれまでなのですが「1.」のaddが計測できるような方法をご教授いただけると幸いです。
本当に実測値が必須か?「add 単体(アセンブラ1命令)の速度」がそう環境に依存するとも思えんのだが、これだけなら計測誤差考えたら理論値でも十分だったりしないか?
CPUのマニュアル(Intelサイト行ってPDF探せ)とマシンスペックから理論値がわかると思うがそれじゃだめか?
ご返答ありがとうございます。
言われてみれば理論値でももちろんいいです。インテルのホームページでPDFを見つけることができました。ありがとうございます。
ツイート | ![]() |