3

3 つの主要な言語間で生の CPU パフォーマンス速度を比較してきました (コードと結果は以下にあります)。主な言語が生の計算能力をどのように比較するかについて、私は非常に興味があります。Java と C# は、メモリのオーバーヘッドがなければ C++ に匹敵する可能性があるという理論がありました。

私の質問:

1) 編集済み (C++ のタイミングがより現実的になりました)

2) JVM は最初の反復で時間がかかりましたが、2 番目の反復では分析が終了して最適化されたと考えるのは正しいですか? Hotspot は、外側のループの最初の繰り返しの後、途中ではなく最適化を終了することをどのように認識したのでしょうか?

3) C# が Java のように機能せず、最初から大幅に最適化されないのはなぜですか? Java に関して C# の違いは何ですか? C# が遅いのはなぜですか? 単純に最適化が少ないためですか?

4) C# テストのタイミングで 2246 ミリ秒と 2262 ミリ秒の間で変動する特定の理由はありますか? CPU には 2 つのコアがあるため、これは 2 つの異なる時間である可能性がありますか?

編集: C# コードでストップウォッチの使用法を表示するようにコードを更新しています。

編集: C++ タイミング コードと結果を修正

セットアップ:

  • C++: VS2010 および Intel Compiler (組み込みリリース モード、最適化: O2、組み込み関数を有効にする: はい、サイズまたは速度を優先する: どちらでもない、フレーム ポインターを省略する: いいえ、ファイバーセーフ最適化を有効にする: いいえ、プログラム全体の最適化: はい)

  • Java: Eclipse、Hotspot 64 ビット コンパイラ バージョン 17、Java 1.6

  • C#: VS2010 および .net 4.0 (ビルトイン リリース モード)

  • CPU: Intel E6600 (2.4GHz) 2.7GHz で動作、バス速度 300MHz、メモリ 8GB、DRAM 周波数: 375MHz

  • 勝つ 7 (64 ビット)

C++ コード:

#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#include <stdio.h>
#include <fstream> 

using namespace std;


double PCFreq = 0.0;
__int64 CounterStart = 0;

void StartCounter()
{
    LARGE_INTEGER li;
    if(!QueryPerformanceFrequency(&li))
        cout << "QueryPerformanceFrequency failed!\n";

    PCFreq = li.QuadPart;

    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
}
double GetCounter()
{
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart-CounterStart)/PCFreq;
}

static long counter = 0;

int _tmain(int argc, _TCHAR* argv[])
{

    for (int m = 0; m < 10; m++)
    {
        StartCounter();
        counter = 0;

        for (int j = 0; j < 3; j++)
        {
            //Just to test timing is working correctly
            //int* p = new int;

            for (long i = 0; i < 200000000; i++)
            {
                counter++;
            }
        }

        cout << GetCounter()*1000000 << " microseconds" << endl;
    }


    int p = 0;
    cin >> p;
    return 0;
}

C++ の結果:

7.19 マイクロ秒

1.89

2.27

1.51

4.92

10.22

10.22

9.84

9.84

10.6

Java コード:

public class main {

    static long counter = 0;

    public static void main(String[] args) {

        for(int m=0; m<10; m++){
            long start = System.nanoTime();
            counter = 0;

            for(int j=0;j<3; j++){
                for(long i=0; i<200000000; i++){
                    counter++;
                }
            }

            System.out.println(((System.nanoTime()-start)/1000000) + " ms");
        }
    }
}

Java の結果:

5703 milliseconds
471 ms
468 ms
467 ms
469 ms
467 ms
467 ms
467 ms
469 ms
464 ms

C# コード:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics

namespace t1
{
    class Program
    {
        static long counter = 0;

        static void Main(string[] args)
        {
            for (int m = 0; m < 10; m++)
            {
                Stopwatch s = new Stopwatch();
                s.Start();
                counter = 0;

                for (int j = 0; j < 3; j++)
                {

                    for (long i = 0; i < 200000000; i++)
                    {
                        counter++;
                    }

                }
                s.Stop();
                Console.WriteLine(s.Elapsed.TotalMilliseconds + " ms");
            }

            Console.ReadLine();
        }
    }
}

C# の結果:

2277 ミリ秒

2246ミリ秒

2262ミリ秒

2246ミリ秒

2262ミリ秒

2246ミリ秒

2262ミリ秒

2246ミリ秒

2262ミリ秒

2262ミリ秒

4

4 に答える 4

2

1 - Sixlettervariables は、これに関するあなたの間違いを指摘したようです

2 - ホットスポットはコードを最適化します。これは、ループで10倍のスピードアップも見られる同様の質問です。したがって、表示されるのは期待される出力です。 初めて Java ループが SLOW で実行されるのはなぜですか? [Sun HotSpot 1.5、sparc]

3 - C# について十分な知識がありません。内部ループを最適化しない可能性があります (3 つの異なるループがあります)。テストしている2つのループを完全に別の方法に抽出して、それが役立つかどうかを確認してください。

4 - DateTime は、高精度のタイミングではなく、日付と時刻を表します。したがって、それほど正確ではありません。私が知る限り、DateTime.Now の解像度は 10ms です

(参考までに、この投稿には、JIT、C#、および C++ の最適化に関するいくつかの適切な説明があり、役立つ可能性があります: C++ のパフォーマンスと Java/C# の比較)

于 2012-04-21T15:32:29.500 に答える
2

を使用する C++ コードに論理的な問題がありますQueryPerformanceFrequency

PCFreq = double(li.QuadPart)/1000000000.0; // <- this is not correct
PCFreq = li.QuadPart;                      // <- this is correct

印刷コードでミリ秒またはナノ秒に割り当てて変換するだけli.QuadPartです。PCFreq

// convert from seconds to milliseconds
cout << GetCounter() * 1000.0 << endl;

この変更により、C++ コードの実際のタイミングが得られます。これらのタイミングが「有効」であるかどうか、または比較に役立つかどうかについては、コメントしません.

于 2012-04-21T15:20:40.513 に答える
1

コンパイラがコンパイル時にカウンターの値を計算し、ループを反復しない可能性があると思います。

単純なカウンターは本当に悪いベンチマークだと思います。

ところで、メソッド内で Java コードを実行してみてください。JIT最適化により、より高速になる場合があります。(しかし、よくわかりません)

于 2012-04-21T14:58:59.603 に答える
1

さまざまなコンパイラのベンチマークはすでに行われており、非常にうまくまとめられています。

コンピュータ言語ベンチマーク ゲーム

Java 7 サーバーと GNU C++ の比較

C# Mono と GNU C++ の比較

C# Mono vs Java 7 サーバー

Java 7 Server は C# Mono 2.10.8 よりも高速ですが、Java 7 が使用するメモリの量を見てください。

于 2012-04-21T15:45:09.487 に答える