Erros, bugs, perguntas - página 2505

 

um bug de longa data no editor:

- guardar o ficheiro com um novo nome (por exemplo: name_v1.2)
- colocar o cursor sobre alguma variável (ou chamada de função)
- pressione alt+g

- um ficheiro antigo é aberto e a edição salta para ele (

 
Vict:

Em geral, eu nem sequer esperava isso:

O código é um pouco complicado demais - tentei chegar ao elemento que não cabe na linha de cache e martelo directamente sobre ele, mas falhou (provavelmente poderia tê-lo feito se realmente quisesse, mas aborreci-me), e não mudei muito o código. Mas desta forma é ainda mais impressionante - apenas um dos 16 colapsos é realizado sobre um elemento que não cabe na linha de cache, no entanto tem um resultado notável.

SZY: Mais objectivamente neste caso para fazer RIGHT_ALIGNED através da inserção de dois curtos, e não através da remoção de um único (por isso vamos conseguir duas actualizações da linha de cache para ambos os casos). A velocidade será mais modesta, mas ainda assim cerca de 1,5 vezes mais.

Desculpe-me, mas onde está a utilização do alinhamento? Não é disso que se trata neste exemplo.

П. С. Publicar o seu código sem comentários e de uma forma grosseira é desrespeitoso para com os seus amigos.

 

Correctamente notado, foi adicionado alinhamento para utilizar objectos com estrutura MQL em bibliotecas de terceiros, em particular dotnet.

Foi quando foram adicionadas bibliotecas dotnet para apoiar o dotnet que o alinhamento foi adicionado aos campos de estruturas/classes de pacotes.

Para o tornar curto e simples, funciona assim:

Para cada tipo (char, short, int, ...) existe um alinhamento por defeito (1, 2, 4 bytes respectivamente).
Para o campo da estrutura é escolhido o mínimo de dois alinhamentos: o por defeito e o definido pelo utilizador (através do pacote)

Ao mesmo tempo, o tamanho do objecto embalado é definido de tal forma que o endereçamento do campo do objecto na matriz é sempre "correcto" (o byte predefinido é definido com o pacote).
É por causa desta última que se cria a falsa impressão que o pacote alinha o tamanho da estrutura; não é verdade, os endereços dos campos são alinhados, o que implica alinhar o tamanho da estrutura.



Por exemplo

struct A pack(8)
  {
   double d;
   char   c;
  };

void OnStart()
  {
   Print(sizeof(A));
   
  }

Resultado 16, para que o endereçamento para o primeiro campo d seja sempre alinhado por 8 bytes

 
fxsaber:

As corridas por minha conta não mostraram qualquer diferença perceptível.

Melhorei a ideia original (no primeiro código, os endereços foram contados incorrectamente). Se não se importar, será interessante ver o resultado para si.

#define  WRONG_ALIGNED
#define  CACHE_LINE_SIZE 64

struct Data {
#ifdef  WRONG_ALIGNED
   ushort pad;
#else
   uint pad;
#endif
   uint ar[CACHE_LINE_SIZE/sizeof(int)+1];
};

#import "msvcrt.dll"
  long memcpy(uint &, uint &, long);
#import
#define  getaddr(x) memcpy(x, x, 0)

void OnStart()
{
   Data data[32768];
   ZeroMemory(data);
   
   srand(GetTickCount());
   
   ulong start_time = GetMicrosecondCount();
   
   for(unsigned i = 0; i < 10000; ++ i) {
      int rndnum = rand();
      while (++rndnum < 32768) {
         int index = int(CACHE_LINE_SIZE - getaddr(data[rndnum].ar[0]) % CACHE_LINE_SIZE) / sizeof(int);
         ++ data[rndnum].ar[index];
         ++ data[rndnum].pad;
      }
   }
      
   Alert(GetMicrosecondCount() - start_time);
   
   Print(data[100].ar[0]);
   Print(data[100].pad);
}
/*
WRONG_ALIGNED:
6206397
6185472

RIGHT_ALIGNED
4089827
4003213
*/
Na essência a mesma coisa acontece com/sem WRONG_ALIGNED - em cada uma delas enquanto escrevemos em duas linhas de cache adjacentes (escrever para almofada sempre para corrigir endereço), a única diferença é que com WRONG_ALIGNED há casos (nem sempre) quando uma das entradas em ar ocorre em uint, que não vai entrar completamente na linha de cache, eu tenho uma diferença estável de cerca de 1,5 vezes.
 
Vict:

Tive a ideia original (o primeiro código não contava correctamente os endereços). Se não se importar, será interessante ver o resultado no seu caso.

Basicamente a mesma coisa acontece com/sem WRONG_ALIGNED - em cada uma delas enquanto escrevemos em duas linhas de cache adjacentes (entrada de bloco sempre para corrigir endereço), a única diferença é que com WRONG_ALIGNED há casos (nem sempre) quando uma das entradas em ar ocorre em uint, que não atingirá toda a linha de cache, eu tenho uma diferença estável cerca de 1,5 vezes.

Por favor explique, o que está a tentar obter com esta linha? No exemplo anterior era um código de lixo.

int index = int(CACHE_LINE_SIZE - getaddr(data[rndnum].ar[0]) % CACHE_LINE_SIZE) / sizeof(int);
 
Francuz:

Por favor, explique o que está a tentar obter com esta linha? No exemplo anterior era um código de lixo.

Encontre a nossa posição na linha de cache actual (aquela onde está o bloco) e tome esse índice para ar[], esse elemento com ele está na linha de cache seguinte (talvez o elemento esteja em duas linhas de cache com WRONG_ALIGNED)

 
Vict:

Encontrar a nossa posição na linha de cache actual (aquela onde está o bloco) e tomar tal índice para ar[] que o elemento com ele está na linha de cache seguinte (talvez o elemento esteja em duas linhas de cache em WRONG_ALIGNED)

Agora estamos a falar de uma compensação. Mas o que mostra é puramente um exemplo sintético, que nunca irá ocorrer na vida real. E em exemplos reais, o ganho de velocidade será de cerca de 1% na melhor das hipóteses. Não se deve fazer um grande alarido por uma aceleração tão insignificante.

П. С. Além disso, calculou o tamanho do registo de forma incorrecta.
 
Francuz:

Agora estamos a falar de deslocação. Mas o que se mostra é um exemplo puramente sintético que nunca será visto na vida real. Em exemplos do mundo real, o ganho de velocidade é de cerca de 1% na melhor das hipóteses. Não se deve fazer um grande alarido com uma aceleração tão insignificante.

Não, este é um exemplo bem real. Apenas 25% das escritas lá ocorrem em lugares "problemáticos" na interface das linhas de cache. Quanto é que isso custa? Por exemplo, se tiver uma longa matriz dupla, uma linha de cache contém apenas 4 valores e se não se preocupar com o alinhamento (e o compilador não o faz por si) então terá 25% de lugares duplos problemáticos - como é no meu exemplo. Há muito mais nuances que falam de alinhamento, mas não vou entrar nelas - não sou bem versado no assunto.

Bem, mestre da casa.

P.S. Também, calculou mal o tamanho do registo.
Eu não o contei de todo ))
 
Vict:

Não, este é um exemplo perfeitamente realista. Nele, apenas 25% das entradas ocorrem em lugares "problemáticos" na junção da linha da cache. É muito? Por exemplo, se tiver uma longa matriz dupla, uma linha de cache contém apenas 4 valores, e se não se importar com o alinhamento (e o compilador não o faz por si), então obtém 25% do dobro problemático - como no meu exemplo. Há muitas mais nuances, que falam por alinhamento, mas não vou falar sobre elas - não sou suficientemente versado na questão.

Bem, o senhor é que manda.

Mais uma vez, direi que está confuso por tamanho de registo.

 
Francuz:

Mais uma vez, está a confundir o tamanho do registo.

Justifique