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

 

У меня не строится график оптимизации по отрицательным значениям.

Данные в результатах оптимизации имеются.

Попробуйте в своих советниках задавать отрицательные значения. Значения можно * -1 для проверки.

 
Renat Fatkhullin:

Проверка показала, что:

  1. SQRT маппятся в прямые CPU инструкции

  2. SQRT + математические вычисления идут без ветвлений и за одну команду (128 бит данные) вычисляется сразу два корня

    Вот этот код превращается в следующий ассемблерный SSE код:
    Это произведение исскуства вообще-то. 8 корней вычислено за 4 вызова ассемблерной команды. Два double числа вычислялись за один вызов.

  3. При операциях через массив все идет штатно, с проверками, ветвлениями и потерями на конвертации double -> integer index

  4. При работе с массивами в этом примере идет постоянное смешение FPU/ALU, что очень плохо сказывается на производлительности

  5. Оптимизация доступа к динамическому массиву отличная, выше похвал. Но смешение FPU/ALU операций + перевод double -> integer + ветвления тратят время

Общий вывод: математика в MQL5 побеждает за счет идеальной оптимизации. Тут не массивы проигрывают, а математика выигрывает.

Спасибо большое за ценную информацию.

Новости, конечно же, больше радостные. Это реально круто!

Я всегда говорил, что MQ красавцы!

Но я также понимаю , что нужно быть крайне аккуратным со смешением типов данных. Но предупрежден - значит вооружен.
Было бы здорово от разработчиков получить какие-то рекомендации в этом свете.

Сейчас поэксперементирую с типами как обычных переменных так и массивов. Интересно что получиться. 

 
Renat Fatkhullin:

Поэкспериментировал.

Что-то у меня все равно пазлы не сходятся.

Сделал два варианта. Первый -по максимуму все перевел на тип int. Второй - на double.

Да, стало чуть быстрее. Но основные тормоза все равно присутствуют.

Вот с вариантом int главный тормозной блок:

 if(arr)
        {  // расчет квадратных корней через массив значений SQRT[]
         D1=SQRT[((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y))];
         D2=SQRT[((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y))];
         D3=SQRT[((X3-X)*(X3-X)+(Y3-Y)*(Y3-Y))];
         D4=SQRT[((X4-X)*(X4-X)+(Y4-Y)*(Y4-Y))];
         D5=SQRT[((X5-X)*(X5-X)+(Y5-Y)*(Y5-Y))];
         D6=SQRT[((X6-X)*(X6-X)+(Y6-Y)*(Y6-Y))];
         D7=SQRT[((X7-X)*(X7-X)+(Y7-Y)*(Y7-Y))];
         D8=SQRT[((X8-X)*(X8-X)+(Y8-Y)*(Y8-Y))];
        }

в нем только тип int и нет никакого смешения типов. При этом и сам массив SQRT стал int. 

Pаботает он только на процентов  10 быстрее.

C вариантом double похожая картина.

Ну все одинаковое, только в одном случае идет вычисление функции sqrt(), при этом там происходит смешение типов.

А во втором случае идет обращение к int массиву и нет никакого смешения типов  и по идее должен использоваться только ALU.

И при этом второй вариант в 3 раза медленнее. Ну как не крути причина - массив.

И еще один важный момент.

В примере int если канвас размером 100x100, т.е. с такими параметрами

то при обращении к массиву мы получаем выйгрыш в скорости. 

Т.е. когда используем  массив SQRT размером 20 000, мы в выигрыше 15-20%, а когда размером 3 000 000, то проигрыш 200% при абсолютно одинаковой математике.

Выходит размер массива причина тормозов?

Файлы:
LSD_double.mq5  10 kb
LSD_int.mq5  10 kb
 

Люди давно потеряли способность понимать результаты современных С++ компиляторов.

К тому же у вас винегрет/мусор из кода, что означает практически нулевую возможность выстроить наивные аксиомы «если такие условия, то результат получится такой». То есть, итоговая оптимизация настолько все перестроит, что ваши гипотезы будут давать на десятки процентов разные результаты даже при мизерных изменениях в коде.

Взгляните еще раз на утрамбовку 8 корней в 4 ассемблерные команды и поймите, что вы не имеете шанса что-либо утверждать, требовать или аппелировать к своей логике. Оптимизаторы давно уже работают на запредельных уровнях, недоступных программистам.

То, как компилятор разложил корни, является исскуством. А вы пытаетесь побить это массивами, даже не понимая простейшего ограничения - чтение из массива это уже провал. Идеальная регистровая работа и пакетное вычисление корней против ветвлений(штрафы) и лазанию в память с частыми промахами в кеш.

Вы задаете вопрос «почему на мелком буфере быстрее работает, а на большом оглушительно сливает» потому, что вообще не знаете о L1/L2/L3 кешах процессора. Попали в кеш - посчитали быстро. Не попали - ждите пару десятков циклов чтения данных из верхнего кеша или памяти.
 
Renat Fatkhullin:

Люди давно потеряли способность понимать результаты современных С++ компиляторов.

К тому же у вас винегрет/мусор из кода, что означает практически нулевую возможность выстроить наивные аксиомы «если такие условия, то результат получится такой». То есть, итоговая оптимизация настолько все перестроит, что ваши гипотезы будут давать на десятки процентов разные результаты даже при мизерных изменениях в коде.

Взгляните еще раз на утрамбовку 8 корней в 4 ассемблерные команды и поймите, что вы не имеете шанса что-либо утверждать, требовать или аппелировать к своей логике. Оптимизаторы давно уже работают на запредельных уровнях, недоступных программистам.

Я прекрасно вижу ваши результаты сравнения с VS и я в восторге от этого.
Но вопрос остается открытым. 

Я извиняюсь за хаосных рабочий код, но речь идет только о этом участке кода и  о сравнении двух вариантов выполнения:

 if(arr)
        {  // расчет квадратных корней через массив значений SQRT[]
         D1=SQRT[((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y))];
         D2=SQRT[((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y))];
         D3=SQRT[((X3-X)*(X3-X)+(Y3-Y)*(Y3-Y))];
         D4=SQRT[((X4-X)*(X4-X)+(Y4-Y)*(Y4-Y))];
         D5=SQRT[((X5-X)*(X5-X)+(Y5-Y)*(Y5-Y))];
         D6=SQRT[((X6-X)*(X6-X)+(Y6-Y)*(Y6-Y))];
         D7=SQRT[((X7-X)*(X7-X)+(Y7-Y)*(Y7-Y))];
         D8=SQRT[((X8-X)*(X8-X)+(Y8-Y)*(Y8-Y))];
        }
 else // расчет квадратных корней через функцию кв. корня sqrt()
        {
         D1=(int)sqrt((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y));
         D2=(int)sqrt((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y));
         D3=(int)sqrt((X3-X)*(X3-X)+(Y3-Y)*(Y3-Y));
         D4=(int)sqrt((X4-X)*(X4-X)+(Y4-Y)*(Y4-Y));
         D5=(int)sqrt((X5-X)*(X5-X)+(Y5-Y)*(Y5-Y));
         D6=(int)sqrt((X6-X)*(X6-X)+(Y6-Y)*(Y6-Y));
         D7=(int)sqrt((X7-X)*(X7-X)+(Y7-Y)*(Y7-Y));
         D8=(int)sqrt((X8-X)*(X8-X)+(Y8-Y)*(Y8-Y));
        }

Здесь нет мусора.

Вы сказали, что "Оптимизация доступа к динамическому массиву отличная, выше похвал."

Но ... см. мое предыдущее сообщение.

Как Вы объясните последний мой эксперимент?:

"Т.е. когда используем  массив SQRT размером 20 000, мы в выигрыше 15-20%, а когда размером 3 000 000, то проигрыш 200% при абсолютно одинаковой математике.

Выходит размер массива причина тормозов?"

 

Прочтите мой предыдущий ответ внимательно - он дописан с точным ответом.

Объясню ваши вопросы просто: вдумчиво прочтите пяток технических статей по устройству процессоров в плане производительности и факторов, влиящих на нее. Без этого нельзя вести обсуждение, так как вам нужно объяснять базовые вещи.

 
Renat Fatkhullin:

То, как компилятор разложил корни, является исскуством. А вы пытаетесь побить это массивами, даже не понимая простейшего ограничения - чтение из массива это уже провал. Идеальная регистровая работа и пакетное вычисление корней против ветвлений(штрафы) и лазанию в память с частыми промахами в кеш.

Вы задаете вопрос «почему на мелком буфере быстрее работает, а на большом оглушительно сливает» потому, что вообще не знаете о L1/L2/L3 кешах процессора. Попали в кеш - посчитали быстро. Не попали - ждите пару десятков циклов чтения данных из верхнего кеша или памяти.
Renat Fatkhullin:

Прочтите мой предыдущий ответ внимательно - он дописан с точным ответом.

Объясню ваши вопросы просто: вдумчиво прочтите пяток технических статей по устройству процессоров в плане производительности и факторов, влиящих на нее. Без этого нельзя вести обсуждение, так как вам нужно объяснять базовые вещи.

Ура!!!
Наконец-то!
Из Вас, Ренат, все клещами нужно вытягивать.

Теперь картина для меня проясняется. 

Был не прав, когда гнал на ваш компилятор. Каюсь, бес попутал. Можно было и додуматься, что причина в ограниченности кэшей процессора. Я, действительно, плохо соображаю в современных процессорах и, действительно, нужно почитать об этом.

Но все же не зря я написал этот код - лабораторную крысу и поднял эту волну.

Итак для читающих этот топик программистов подытожу, что лично мне в результате этой волны удалось выяснить:

  • Функция sqrt() и, скорей всего еще многие другие элементарные функции, очень быстры и выполняются не на уровне компилятора, а процессора.
  • Компилятор MQL5 настолько силен в оптимизации математической логики, что легко уделывает современный компилятор VS C++. Что очень вдохновляет.
  • Целесообразно стараться не смешивать типы в ресурсоёмких задачах. Смешение типов приводит к снижению скорости расчета.
  • РАЗМЕР ИМЕЕТ ЗНАЧЕНИЕ! (имеется ввиду размер массива :)) благодаря особенностям работы многоуровнего кэша процессора и его ограниченного размера. И программистам будет не лишним следить за суммарным размером массивов и понимать, что использование больших массивов может существенно влиять на скорость расчетов. Насколько я понял, речь идёт об  относительно комфортной работе массивов суммарным  объемом не превышающем приблизительно 512 кБ, а это ~65000 элементов типа double или ~130000 типа int., 

Пошел исправлять свой код исходя из этой информации. Я часто злоупотреблял размером массивов. 

Спасибо Всем!

 

как узнать нажата или отжата кнопка перекрестие?

можно отловить нажатие колесика мыши, но если мышь не используется как быть?

 
Alexandr Bryzgalov:

как узнать нажата или отжата кнопка перекрестие?

можно отловить нажатие колесика мыши, но если мышь не используется как быть?

Может при необходимости принудительно нажимать или отжимать её?

CHART_CROSSHAIR_TOOL

Включение/отключение доступа к инструменту "перекрестие" по нажатию средней клавиши мышки

bool  (значение по умолчанию true)

 
Alexey Viktorov:

Может при необходимости принудительно нажимать или отжимать её?

CHART_CROSSHAIR_TOOL

Включение/отключение доступа к инструменту "перекрестие" по нажатию средней клавиши мышки

bool  (значение по умолчанию true)

это насколько понял лишь доступ к инструменту, но не включение выключение.

Причина обращения: