2

x86 Intelマシン、Windows 7、およびVisual C ++(バージョン2005/2012 Express)を使用しています

私はアラインメントで遊んでいます(これは学習演習として行っています)。確かに、パディングの観点からクラス/構造体のサイズへの影響を理解しています。CPU命令が機能し、データを期待する方法のおかげで、それもより適切に調整されていることを理解していると思います。

私は一般的に多くの異なるリソースを見てきました。たとえば、(興味深い) c ++データアライメント/メンバーの順序と継承 (およびウィキペディアのような他のリンク)http://en.wikipedia.org/wiki/Data_structure_alignment

影響を受ける可能性のある領域の1つ(私が読んだ)はパフォーマンスのようです。データをレジスターの特定のサイズにする必要があるため、データの位置がずれていると問題が発生する可能性があります(ウィキペディアを参照)。

3つの構造体を作成したコードを作成しました。すべて同じメンバーで、パッキングが1に設定され、通常の配置で、メンバーが再配置されています。これにより、サイズが8、10、および12のオブジェクトが得られました。それぞれに対して次のようなコードを実行しました。

struct MixedData1
{
    char Data1;
    short Data2;
    int Data3;
    char Data4;

    void operator() (MixedData1& md)
    {
        md.Data1 = 'a';
        md.Data2 = 1024;
        md.Data3 = 1000000;
        md.Data4 = 'b';
    }
};

typedef std::vector<MixedData1> MDVector;


int main(int argc, char* argv[])
{
    MixedData1 md;
    for(int count = 0; count < 10 ; count++)
    {    
        {
        std::cout << sizeof(md) << std::endl;
        boost::timer::auto_cpu_timer t;
        MDVector mdv(10000000); 
        std::fill(mdv.begin(),mdv.end(),md );
        std::for_each(mdv.begin(),mdv.end(),md);
        }
    }
}

私は値にあまり興味がないので、ベクトルの各要素は同じように初期化されます。とにかく、構造体のサイズに応じて実行時間が増加することを示す結果が得られました-IE with pack(1)(8バイト)私は最も速い0.08を取得し、通常の配置(12バイト)では最も遅い0.105を取得しました。

私の質問は、間違って配置された場合の影響についてです。C ++プログラマーとしてのX年間、アライメントに問題があったことはないと思いますが、もちろん、それは私を通り過ぎたかもしれません。

(1)アライメントは私のテスト(編集)で効果がありました(私は信じています)が、ニールが投稿したように、それは構造体のサイズの違いによるものでした。彼の返事に従ってメンバーにアクセスしようとしましたが、実際の効果は見られませんでした....より明確な例はありますか?ミスアライメントの劇的な影響を見る方法はありますか?(2)可能であれば、ミスアライメントによるクラッシュを誘発する方法はありますか。

4

2 に答える 2

4

コードで行うことは、プロセッサがメモリをコピーできる速さをテストすることだけです。メモリが多いほど、コピーは遅くなります。構造内の個々のメンバーの位置合わせは、コピーの速度には関係なく、構造のサイズのみが重要です。

アライメントの効果を確認したい場合は、アライメントされていない個々の構造体メンバーに実際にアクセスするコードを記述する必要があります。たとえば、各構造体の data3 メンバーをインクリメントするループを作成できます。アーキテクチャによっては、演算を実行するために異なる命令を使用する必要があることをコンパイラが認識している場合があります。x86 では、通常はそうではなく、プロセッサーがアライメントされていないアクセスを処理できるため、コンパイラーは自然に見えるコードを生成します。一部のプロセッサは、整列されていないデータを、整列されたデータと同じ速度で実際に読み書きできます。これの簡単な例は 8088 です。これには 8 ビット データ バスしかないため、16 ビット命令はすべて 2 つのロードを使用してエミュレートされます。

ミスアラインメントによってクラッシュを引き起こしたい場合は、通常、異なる型の間でポインターをキャストする必要があります。その場合、コンパイラは、ポインターが正しく整列されていない可能性があることを常に認識するとは限らず、整列されていないアクセスに対して正しい命令を生成しません。たとえば、キャスト char* ポインターで SSE 命令を呼び出そうとする可能性があります。

于 2012-11-04T22:07:32.740 に答える
1

簡単な答え: 実際には問題ありません。

理由は次のとおりです。1 つまたは 2 つのキャッシュ ミスは 1 ミリ秒未満で済む可能性が高いため、アライメントされていないデータへのアクセスが問題になるのは、次の場合のみです。

  1. データが 2 つのキャッシュ ラインにまたがっている
  2. メモリ内で連続していない、アラインされていない多くのデータにアクセスします。

2. とにかく大量のキャッシュミスが発生するため、データが整列されていても、そのような状況になるべきではありません。アラインメントを改善しても、キャッシュ ミスの数は 2 倍以上改善されませんが、データを連続して保存すると、パフォーマンスが何倍も改善される可能性があります。

データのアライメントが必要な命令がいくつかあります。これらの指示が必要な場合は、それについて知っているか、コンパイラがアライメントを保証する必要があります。これがパフォーマンスに影響するかどうかは、プロセッサのマイクロアーキテクチャとコンパイラによって異なります。いずれにせよ、ボトルネックを見つけるためにプログラムのプロファイリングを開始する必要があります。アラインメントがプログラムのパフォーマンスに大きな影響を与える場合は、それを修正してください。それ以外の場合は、心配しないでください。

于 2012-11-05T18:33:02.717 に答える