Ошибки, баги, вопросы - страница 2505

 

давний баг в редакторе:

- сохраняем файл под новым именем (например: name_v1.2)
- ставим курсор на какую-нибудь переменную (или вызов функции)
- нажимаем alt+g

- открывается старый файл и редактирование перескакивает в него (

 
Vict:

В общем-то я такого даже не ожидал:

Код немного переусложнён - я пытался попасть на тот элемент, который не вмещается в кеш-линию и долбить прямо по нему, но не вышло (при большом желании получилось бы наверное, но надоело), а код сильно править не стал. Но так это даже больше впечатляет - всего лишь одно из 16ти сложений выполняется над элементом непопадающим в кеш-линию, тем не менее это даёт ощутимый результат.

ЗЫ: более объективно в данном случае делать RIGHT_ALIGNED через вставки двух short, а не удалением единственного (так добьёмся двух обновлений кеш-линии для обоих случаев). Так ускорение будет скромнее, но всё равно весомо около 1.5 раза.

Простите, но где тут использование выравнивания? Пример вообще о другом.

П. С. Выкладывать код без комментариев и в сыром виде это неуважение к собеседникам.

 

Правильно было замечено, выравнивание было добавлено для использования объектов структур MQL в сторонних библиотеках, в частности dotnet.

Именно при добавлении поддержки dotnet библиотек и было добавлено выравнивание полей структур/классов pack.

Если говорить коротко и просто, то работает оно так:

Для каждого из типов (char, short, int, ...) есть свой allignment (1, 2, 4, байта соответственно) по умолчанию.
Для поля структуры выбирается минимальное из двух выравниваний:  по-умолчанию и заданное пользователем (через pack)

При этом, размер объекта с упаковкой устанавливается таким образом, чтобы адресация к полю объекта в массиве всегда была "правильным" ( заданным через pack, по умолчанию на 1 байт )
Именно из-за последнего создаётся ложное впечатление, что pack выравнивает размер структуры - это не так, выравниваются адреса полей, что и влечёт за собой выравнивание размера структуры.



Например

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

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

Результат 16, чтобы адресация к первому полю d всегда была выравненной на 8 байт

 
fxsaber:

Запуски у себя не показали заметной разницы.

Довёл до ума первоначальную идею (в первом коде неправильно считал адреса). Если не затруднит, то интересно будет посмотреть на результат у вас.

#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
*/
По своей сути с/без WRONG_ALIGNED происходит одно и то же - на каждом while пишем в две соседние кеш-линии (запись в pad всегда в правильный адрес), разница лишь в том, что при WRONG_ALIGNED случаются случаи(не всегда), когда одна из записей в ar происходит в uint, который не попадет целиком в кеш-линию, у меня стабильная разница около 1.5 раз.
 
Vict:

Довёл до ума первоначальную идею (в первом коде неправильно считал адреса). Если не затруднит, то интересно будет посмотреть на результат у вас.

По своей сути с/без WRONG_ALIGNED происходит одно и то же - на каждом while пишем в две соседние кеш-линии (запись в pad всегда в правильный адрес), разница лишь в том, что при WRONG_ALIGNED случаются случаи(не всегда), когда одна из записей в ar происходит в uint, который не попадет целиком в кеш-линию, у меня стабильная разница около 1.5 раз.

Поясните пожалуйста, что вы пытаетесь получить данной строкой? В предыдущем примере это был мусорный код.

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

Поясните пожалуйста, что вы пытаетесь получить данной строкой? В предыдущем примере это был мусорный код.

Находим наше положение в текущей кеш-линии (в той, где находится pad) и берём такой индекс для ar[], что элемент с ним находится в следующей кеш-линии (возможно элемент находится в двух кеш-линиях при WRONG_ALIGNED)

 
Vict:

Находим наше положение в текущей кеш-линии (в той, где находится pad) и берём такой индекс для ar[], что элемент с ним находится в следующей кеш-линии (возможно элемент находится в двух кеш-линиях при WRONG_ALIGNED)

Вот теперь речь идёт о смещении. Но то что вы показываете это чисто синтетический пример, который в жизни никогда не встретится. А на реальных примерах выигрыш в скорости в лучшем случае будет около 1%. Ради такого мизерного ускорения и городить огород не следует.

П. С. Кроме того вы неверно посчитали размер регистра.
 
Francuz:

Вот теперь речь идёт о смещении. Но то что вы показываете это чисто синтетический пример, который в жизни никогда не встретится. А на реальных примерах выигрыш в скорости в лучшем случае будет около 1%. Ради такого мизерного ускорения и городить огород не следует.

Нет, это вполне реальный пример. В нём лишь 25% записей происходит в "проблемные" места на стыке кеш-линий. Много ли это? Например, у вас массив из long double, в одну кеш-линию поместятся лишь 4 значения, и если вы не заморачиваетесь с выравниванием (и за вас не делает это компилятор), то вы получаете 25% проблемных даблов - как раз как в моём примере. Тут ещё много нюансов, которые говорят за выравнивание, но я не буду о них - недостаточно всесторонне владею вопросом.

Ну хозяин барин.

П. С. Кроме того вы неверно посчитали размер регистра.
Да я его как бы вообще не считал ))
 
Vict:

Нет, это вполне реальный пример. В нём лишь 25% записей происходит в "проблемные" места на стыке кеш-линий. Много ли это? Например, у вас массив из long double, в одну кеш-линию поместятся лишь 4 значения, и если вы не заморачиваетесь с выравниванием (и за вас не делает это компилятор), то вы получаете 25% проблемных даблов - как раз как в моём примере. Тут ещё много нюансов, которые говорят за выравнивание, но я не буду о них - недостаточно всесторонне владею вопросом.

Ну хозяин барин.

Ещё раз говорю вы путаете размер регистра.

 
Francuz:

Ещё раз говорю вы путаете размер регистра.

Обоснуйте
Причина обращения: