最近の、ヴァーチャルマシン系の処理系は、実行時最適化が頭がいいから、場合によってはネイティブコンパイラより速い事がある、という議論をしたので、本当かどうか試してみました。
自作の単純なプログラムで、どっちが速いか確認してみたのです。
やってみようと思ったのが実家に帰省していたときだったので、Visual Studio 2008がインストールされていたネットブックのちょっとだけマシなやつ(Cerelon SU2300搭載)で試したのと、自宅に帰ってからVisual Studio 2010 がインストールされているCore i7で試しました。
Visual C++ 2008の最適化がかなりエゲツナイことをしていそうだ、というのも見えてきました。
また、性能の比較は、「一概に言えない」んだな、ということも判りました。
ターゲット環境での実際比較、が必要ですね。
実行時最適化の進歩もすごいんですが、ネイティブコンパイラの新プロセッサに対する最適化もまたすごい、んでしょうね。
namespace ConsoleApplication1CSharp
{
class Program
{
uint fooOne(uint loopCount)
{
uint acc = 0;
for (uint i = 0; i < loopCount; i++)
{
for (uint j = 0; j < loopCount; j++)
{
acc = (i * 3 + 123) / 65 + acc / 1000 + j;
}
}
return acc;
}
double fooTwo(uint loopCount)
{
double acc = 0.0;
for (uint i = 0; i < loopCount; i++)
{
for (uint j = 0; j < loopCount; j++)
{
acc = (i * 3.5 + 123.1) / 65.7 + acc / 1000.9 + j;
}
}
return acc;
}
static void Main(string[] args)
{
Program p = new Program();
// JITにコンパイルさせる
p.fooOne(1);
p.fooTwo(1);
// ここから本番
DateTime begin = DateTime.Now;
uint ui = p.fooOne(20000);
DateTime endInt = DateTime.Now;
double d = p.fooTwo(20000);
DateTime endDouble = DateTime.Now;
TimeSpan tsInt = endInt - begin;
TimeSpan tsDouble = endDouble - endInt;
Console.WriteLine("Integer time: " + tsInt.TotalMilliseconds.ToString());
Console.WriteLine("Integer value: " + ui.ToString());
Console.WriteLine("Double time: " + tsDouble.TotalMilliseconds.ToString());
Console.WriteLine("Double value: " + d.ToString());
Console.WriteLine("Press Enter to Exit");
Console.ReadLine();
}
}
}
#include "stdafx.h"
#include "windows.h" // この形式なのは、HTML化したときタグとして反応しないように
#include "mmsystem.h"
unsigned int fooOne(unsigned int loopCount)
{
unsigned int acc = 0;
for (unsigned int i = 0; i < loopCount; i++)
{
for (unsigned int j = 0; j < loopCount; j++)
{
acc = (i * 3 + 123) / 65 + acc / 1000 + j;
}
}
return acc;
}
double fooTwo(unsigned int loopCount)
{
DWORD fooTwoBegin = timeGetTime();
double acc = 0.0;
for (unsigned int i = 0; i < loopCount; i++)
{
for (unsigned int j = 0; j < loopCount; j++)
{
acc = (i * 3.5 + 123.1) / 65.7 + acc / 1000.9 + j;
}
}
DWORD fooTwoEnd = timeGetTime();
// (ページ下部の注参照)
printf("Double time in fooTwo: %u\n", fooTwoEnd - fooTwoBegin);
return acc;
}
int _tmain(int argc, _TCHAR* argv[])
{
// 意味はないが一応C#と等価にするため
fooOne(1);
fooTwo(1);
timeBeginPeriod(1);
// ここから本番
DWORD begin = timeGetTime();
unsigned int ui = fooOne(20000);
DWORD endInt = timeGetTime();
double d = fooTwo(20000);
DWORD endDouble = timeGetTime();
DWORD tsInt = endInt - begin;
DWORD tsDouble = endDouble - endInt;
printf("Integer time: %d\n", tsInt);
printf("Integer value: %u\n", ui);
printf("Double time: %u\n", tsDouble);
printf("Double value: %f\n", d);
puts("Press Enter to Exit");
getchar();
return 0;
}
コーディング言語 | コンパイル環境 | ビルドモード | 実行環境 | 結果(Integer time) | 結果(Double time) |
---|---|---|---|---|---|
C++ | VS 2010 on Win7 Ultimate x64 on Core i7 | Debug | Win7 Ultimate x64 on Core i7 | 3983ms | 11274ms |
C# | VS 2010 on Win7 Ultimate x64 on Core i7 | Debug(x86) | Win7 Ultimate x64 on Core i7 | 4469ms | 13734ms |
C# | VS 2010 on Win7 Ultimate x64 on Core i7 | Debug(AnyCPU) | Win7 Ultimate x64 on Core i7 | 4469ms | 13734ms |
C++ | VS 2010 on Win7 Ultimate x64 on Core i7 | Release | Win7 Ultimate x64 on Core i7 | 1019ms | 3995ms |
C# | VS 2010 on Win7 Ultimate x64 on Core i7 | Release(x86) | Win7 Ultimate x64 on Core i7 | 3709ms | 12983ms |
C# | VS 2010 on Win7 Ultimate x64 on Core i7 | Release(AnyCPU) | Win7 Ultimate x64 on Core i7 | 1014ms | 6583ms |
C++ | VS 2008 on Win7 HomePremium x64 on SU2300 | Debug | Win7 Ultimate x64 on Core i7 | 実行不能 | 実行不能 |
C# | VS 2008 on Win7 HomePremium x64 on SU2300 | Debug | Win7 Ultimate x64 on Core i7 | 2808ms | 9297ms |
C++ | VS 2008 on Win7 HomePremium x64 on SU2300 | Release | Win7 Ultimate x64 on Core i7 | 1153ms | 3995ms |
C# | VS 2008 on Win7 HomePremium x64 on SU2300 | Release | Win7 Ultimate x64 on Core i7 | 1014ms | 6583ms |
C++ | VS 2010 on Win7 Ultimate x64 on Core i7 | Debug | Win7 HomePremium x64 on SU2300 | 9375ms | 24148ms |
C# | VS 2010 on Win7 Ultimate x64 on Core i7 | Debug(x86) | Win7 HomePremium x64 on SU2300 | 9110ms | 43804ms |
C# | VS 2010 on Win7 Ultimate x64 on Core i7 | Debug(AnyCPU) | Win7 HomePremium x64 on SU2300 | 9103ms | 28298ms |
C++ | VS 2010 on Win7 Ultimate x64 on Core i7 | Release | Win7 HomePremium x64 on SU2300 | 2586ms | 9098ms |
C# | VS 2010 on Win7 Ultimate x64 on Core i7 | Release(x86) | Win7 HomePremium x64 on SU2300 | 8361ms | 42497ms |
C# | VS 2010 on Win7 Ultimate x64 on Core i7 | Release(AnyCPU) | Win7 HomePremium x64 on SU2300 | 2652ms | 16738ms |
C++ | VS 2008 on Win7 HomePremium x64 on SU2300 | Debug | Win7 HomePremium x64 on SU2300 | 8592ms | 23613ms |
C# | VS 2008 on Win7 HomePremium x64 on SU2300 | Debug | Win7 HomePremium x64 on SU2300 | 6567ms | 20217ms |
C++ | VS 2008 on Win7 HomePremium x64 on SU2300 | Release | Win7 HomePremium x64 on SU2300 | 3053ms | 9184ms |
C# | VS 2008 on Win7 HomePremium x64 on SU2300 | Release | Win7 HomePremium x64 on SU2300 | 2652ms | 16754ms |