エラー、バグ、質問 - ページ 2500

 
Vict:

アライメントが必要なのは、プロセッサがキャッシュライン2本分のIntを取得するためではなく、アライメントが必要なのです。

いいえ、プロセッサキャッシュはデータプリフェッチでまったくロードされず、異なるキャッシュレベルは遷移予測でまったくロードされない、pack()はそこに(キャッシュに)まったく到達できない、1または3(仮想)クロックサイクルで実行される代わりに任意の算術演算(2 intの加算)は、データアライメント分析につながる、などです。

物理的なレベルでは、次のように動作するはずです。コンパイラは実行コードを作成し、その中にpack() がありますが、RAM からデータを読み込むときは int データのみを読み込み、データセグメントのポインタはすぐにpack() バイト (int バイトではありません)に移動 されます。


間違っているかもしれませんが、今はすべてのプロセス(プロセッサ自体も含めて)が仮想化・最適化されている--これは、私が勉強したときにPentium-1の本を読んだので、私の推論ですが--。昔は高かったなぁ ))))

削除済み  
Igor Makanu:

いいえ、プロセッサキャッシュはデータプリフェッチでまったくロードされず、異なるキャッシュレベルは遷移予測でまったくロードされない、pack()はそこに(キャッシュに)まったく到達できない、1または3(仮想)クロックサイクルで実行されるのではなく、任意の算術演算(2 intの加算)はデータアライメント分析につながる、などです。

物理的なレベルでは、次のように動作するはずです。コンパイラが作成した実行コードにはpack() がありますが、RAMからデータを読み込むときは int 型のデータしか読み込まず、データセグメントのポインタはすぐにpack() バイトに 移動します(int 型のバイトには移動しません)。

つまり、プログラマではなくCPUの都合で、アライメントが狂っているのです。もちろん、コンパイラが構造体に空白を挿入することで実装している。

 
Alexey Viktorov:

つまり、MQL5ではアライメントが全くないのです。

ずっと前から存在していたんです。

削除済み  
Vict:

あなたは間違った場所を掘っている、アライメントはあなたのために全くない

マルチスレッド環境では、異なるコアが同じキャッシュラインに書き込まないようにデータを配置することが考えられますが、この場合、常にキャッシュの同期が必要となるため、パフォーマンスが低下します。まあ、そこもCPUの種類とか、いろいろとニュアンスがあるんですけどね。

 
fxsaber:

ずっと前から存在していたんです。

どこに書いてあったか覚えていますか?

 
fxsaber:

そうすると、アライメントの意味がなくなってしまうので

は、アライメントがどうなるのか、バイトで試してみました。

#property strict

const uint FFFF=0xFFFFFFFF;
//+------------------------------------------------------------------+
struct A pack(4)
  {
   ushort            j;
  };
//+------------------------------------------------------------------+
struct B pack(8)
  {
   ushort            j;
  };
//+------------------------------------------------------------------+
union UnionCheckByte
  {
   uint              byte_2x4[2];
   A                 a;
   B                 b;
  };
//+------------------------------------------------------------------+
void OnStart()
  {
   UnionCheckByte tst;
   tst.byte_2x4[0]=FFFF;   tst.byte_2x4[1]=FFFF;   // заполним память 0xFFFFFFFF FFFFFFFF
   Print("0xFFFFFFFF FFFFFFFF = ",tst.byte_2x4[0],",",tst.byte_2x4[1]);   // проверим
   
   
   
   tst.byte_2x4[0]=FFFF;   tst.byte_2x4[1]=FFFF;   // заполним память 0xFFFFFFFF FFFFFFFF
   tst.a.j=0;
   Print("A.  = ",tst.byte_2x4[0],",",tst.byte_2x4[1]);   // проверим



   tst.byte_2x4[0]=FFFF;   tst.byte_2x4[1]=FFFF;   // заполним память 0xFFFFFFFF FFFFFFFF
   tst.b.j=0;
   Print("B.  = ",tst.byte_2x4[0],",",tst.byte_2x4[1]);   // проверим
  }
//+------------------------------------------------------------------+

2019.07.07 17:51:30.601 tst (EURUSD,H1) 0xFFFFFFFFFF FFFFFFFFFF = 4294967295,4294967295

2019.07.07 17:51:30.601 tst (EURUSD,H1) A. = 4294901760,4294967295

2019.07.07 17:51:30.601 tst (EURUSD,H1) B. = 4294901760,4294967295




まだ起きていないのか、それとも pack(4) / pack(8) のアライメントがうまくいかないのか、私は構造体 A と B のサイズをコンパイラに明示的に指定しました。


されど

 ZeroMemory(tst.a);   //tst.a.j=0;
変わり映えしない
 
Alexey Viktorov:

どこに書いてあったか覚えていますか?

ドキュメントに書いてあったかは覚えていませんが。

 
Igor Makanu:

は、アライメントがバイト単位でどうなるかを試してみました。

私はまだ起きていないのか、それとも pack(4) / pack(8) のアライメントがうまくいかないのか、私は 構造体 A と B のサイズをコンパイラに明確に伝えました。

というのが、この議論の発 端です。そうでないことが判明した。

まあ、このサンプルは結局不正解なんだけどね。ushort-fieldをゼロにする場合、追加バイトは全く変更する必要がない。


ZeroMemoryはsizeofに誘導される可能性が高い一方、両者とも何らかの理由で2になっています。

 
fxsaber:

というのが、この議論の発端 です。 全くそんなことはないことがわかりました。

1.まあ、この例は結局のところ不正解なんだけどね。ushort-fieldをゼロにすることで、追加バイトを全く変更する必要がない。


2.ZeroMemoryはsizeofで誘導する必要があるが、なぜか両方ともdoubleになっている。


1.はい、そう思います。

2.ZeroMemoryは、私のためにメモリをゼロにする必要があります。


純粋なMQLでpack()を使う意味はないと思います。せいぜい.dllを使ってデータを操作するくらいで、確実に動作するはずです。

 
Igor Makanu:

2.ZeroMemoryは、まさにメモリをリセットするために必要なものです。

そうなんです。

struct A pack(4)
{
  short j;
  char i;
};

union U
{
  A a;
  uchar Bytes[sizeof(A)];
  
  U() { ArrayInitialize(this.Bytes, (char)0xFF); }
};

void OnStart()
{
  U u;
  
  ArrayPrint(u.Bytes); // 255 255 255 255
  
  ZeroMemory(u.a);
  ArrayPrint(u.Bytes); // 0 0 0 0
}