ЗЫ: ну и тут много фанатов скорости, если начнут всё ровнять по уму, то должны полететь ещё быстрее, в теории по крайней мере.
В общем-то я такого даже не ожидал:
#define WRONG_ALIGNED
#define CACHE_LINE_SIZE 64struct Data {
#ifdef WRONG_ALIGNED
short bad_pad;
#endif
uint ar[CACHE_LINE_SIZE/sizeof(int)];
};
#import "msvcrt.dll"long memcpy(Data &, Data &, long);
#import
#define getaddr(x) memcpy(x, x, 0)
voidOnStart()
{
Data data[32768];
if (getaddr(data[0])%4 != 0) {
Alert("error");
return;
}
ZeroMemory(data);
int index = int(CACHE_LINE_SIZE - getaddr(data[0]) % CACHE_LINE_SIZE) / sizeof(int) - 1;
srand(GetTickCount());
ulong start_time = GetMicrosecondCount();
for(unsigned i = 0; i < 10000; ++ i) {
int rndnum = rand();
while (++rndnum < 32768)
for (int j = ArraySize(data[rndnum].ar)-1; j >= 0; -- j)
++ data[rndnum].ar[j];
}
Alert(GetMicrosecondCount() - start_time);
for (int j = ArraySize(data[100].ar)-1; j >= 0; -- j)
Print(data[100].ar[j]);
}
/*
WRONG_ALIGNED:
6117940
6104068
6047416
RIGHT_ALIGNED
3341823
2565150
2565150
*/
Код немного переусложнён - я пытался попасть на тот элемент, который не вмещается в кеш-линию и долбить прямо по нему, но не вышло (при большом желании получилось бы наверное, но надоело), а код сильно править не стал. Но так это даже больше впечатляет - всего лишь одно из 16ти сложений выполняется над элементом непопадающим в кеш-линию, тем не менее это даёт ощутимый результат.
ЗЫ: более объективно в данном случае делать RIGHT_ALIGNED через вставки двух short, а не удалением единственного (так добьёмся двух обновлений кеш-линии для обоих случаев). Так ускорение будет скромнее, но всё равно весомо около 1.5 раза.
Для демонстрации ошибки взял зигзаг из поставки метатрейдера. Добавил в код дополнительные буферы, взятые из моей программы. Никаких манипуляций с дополнительными буферами не предусмотрено в данном коде. Они просто для демонстрации ошибки.
Вывел данный зигзаг на график EURUSD таймфрейм H1. Закрыл терминал. Из истории удалил все сформированные таймсерии по EURUSD. То есть удалил все файлы *.hcc и *.hc по валютной паре EURUSD. Это сделано для того, чтобы при загрузке терминала началась загрузка файлов .hcc и формирование файлов .hc с чистого листа.
После запуска терминала на графике EURUSD наблюдается множество артефактов. И вот эти артефакты побороть не получается.
Код модифицированного зигзага в виде текста и в виде файла прикладываю.
Предупреждаю, что задание параметров зигзага оставил через #propert.
Все остальные буферы не задаю через #propert, так как у меня все, в том числе и буферы для зигзагов, изменяются программно динамически.
//+------------------------------------------------------------------+//| ZigZag.mq5 |//| Copyright 2009-2017, MetaQuotes Software Corp. |//| http://www.mql5.com |//+------------------------------------------------------------------+#property copyright"2009-2017, MetaQuotes Software Corp."#property link"http://www.mql5.com"#property version"1.00"#property indicator_chart_window#property indicator_buffers29#property indicator_plots17//---- plot Zigzag#property indicator_label17 "Zigzag"#property indicator_type17 DRAW_SECTION#property indicator_color17 Red
#property indicator_style17 STYLE_SOLID#property indicator_width17 1//--- input parametersinputint ExtDepth=12;
inputint ExtDeviation=5;
inputint ExtBackstep=3;
//--- indicator buffersdouble ZigzagBuffer[]; // main bufferdouble HighMapBuffer[]; // highsdouble LowMapBuffer[]; // lowsint level=3; // recounting depthdouble deviation; // deviation in pointsdouble Hmzz1[], Hmzz2[], Hmzz3[], Hmzz4[], Hmzz5[], Hmzz6[], Hmzz7[], Hmzz8[], Hmzz9[], Hmzz10[];
double Lmzz1[], Lmzz2[], Lmzz3[], Lmzz4[], Lmzz5[], Lmzz6[], Lmzz7[], Lmzz8[], Lmzz9[], Lmzz10[];
double nen_ZigZagL[], nen_ZigZagH[];
double ha[], la[], ham[], lam[];
//+------------------------------------------------------------------+//| Custom indicator initialization function |//+------------------------------------------------------------------+intOnInit()
{
//--- indicator buffers mappingSetIndexBuffer(0,Lmzz1,INDICATOR_DATA); // Plot = 0SetIndexBuffer(1,Hmzz1,INDICATOR_DATA);
SetIndexBuffer(2,Lmzz2,INDICATOR_DATA); // Plot = 1SetIndexBuffer(3,Hmzz2,INDICATOR_DATA);
SetIndexBuffer(4,Lmzz3,INDICATOR_DATA); // Plot = 2SetIndexBuffer(5,Hmzz3,INDICATOR_DATA);
SetIndexBuffer(6,Lmzz4,INDICATOR_DATA); // Plot = 3SetIndexBuffer(7,Hmzz4,INDICATOR_DATA);
SetIndexBuffer(8,Lmzz5,INDICATOR_DATA); // Plot = 4SetIndexBuffer(9,Hmzz5,INDICATOR_DATA);
SetIndexBuffer(10,Lmzz6,INDICATOR_DATA); // Plot = 5SetIndexBuffer(11,Hmzz6,INDICATOR_DATA);
SetIndexBuffer(12,Lmzz7,INDICATOR_DATA); // Plot = 6SetIndexBuffer(13,Hmzz7,INDICATOR_DATA);
SetIndexBuffer(14,Lmzz8,INDICATOR_DATA); // Plot = 7SetIndexBuffer(15,Hmzz8,INDICATOR_DATA);
SetIndexBuffer(16,Lmzz9,INDICATOR_DATA); // Plot = 8SetIndexBuffer(17,Hmzz9,INDICATOR_DATA);
SetIndexBuffer(18,Lmzz10,INDICATOR_DATA); // Plot = 9SetIndexBuffer(19,Hmzz10,INDICATOR_DATA);
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(3,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(4,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(5,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(6,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(7,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(8,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(9,PLOT_EMPTY_VALUE,0.0);
ArraySetAsSeries(Lmzz1,true);
ArraySetAsSeries(Hmzz1,true);
ArraySetAsSeries(Lmzz2,true);
ArraySetAsSeries(Hmzz2,true);
ArraySetAsSeries(Lmzz3,true);
ArraySetAsSeries(Hmzz3,true);
ArraySetAsSeries(Lmzz4,true);
ArraySetAsSeries(Hmzz4,true);
ArraySetAsSeries(Lmzz5,true);
ArraySetAsSeries(Hmzz5,true);
ArraySetAsSeries(Lmzz6,true);
ArraySetAsSeries(Hmzz6,true);
ArraySetAsSeries(Lmzz7,true);
ArraySetAsSeries(Hmzz7,true);
ArraySetAsSeries(Lmzz8,true);
ArraySetAsSeries(Hmzz8,true);
ArraySetAsSeries(Lmzz9,true);
ArraySetAsSeries(Hmzz9,true);
ArraySetAsSeries(Lmzz10,true);
ArraySetAsSeries(Hmzz10,true);
ArraySetAsSeries(nen_ZigZagH,true);
ArraySetAsSeries(nen_ZigZagL,true);
ArraySetAsSeries(ham,true);
ArraySetAsSeries(lam,true);
ArraySetAsSeries(ha,true);
ArraySetAsSeries(la,true);
PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_ZIGZAG);
PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_ZIGZAG);
PlotIndexSetInteger(2,PLOT_DRAW_TYPE,DRAW_ZIGZAG);
PlotIndexSetInteger(3,PLOT_DRAW_TYPE,DRAW_ZIGZAG);
PlotIndexSetInteger(4,PLOT_DRAW_TYPE,DRAW_ZIGZAG);
PlotIndexSetInteger(5,PLOT_DRAW_TYPE,DRAW_ZIGZAG);
PlotIndexSetInteger(6,PLOT_DRAW_TYPE,DRAW_ZIGZAG);
PlotIndexSetInteger(7,PLOT_DRAW_TYPE,DRAW_ZIGZAG);
PlotIndexSetInteger(8,PLOT_DRAW_TYPE,DRAW_ZIGZAG);
PlotIndexSetInteger(9,PLOT_DRAW_TYPE,DRAW_ZIGZAG);
PlotIndexSetInteger(0,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(1,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(2,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(3,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(4,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(5,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(6,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(7,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(8,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(9,PLOT_LINE_STYLE,STYLE_SOLID);
PlotIndexSetInteger(0,PLOT_LINE_COLOR, clrDarkOrange);
PlotIndexSetInteger(1,PLOT_LINE_COLOR, clrRoyalBlue);
PlotIndexSetInteger(2,PLOT_LINE_COLOR, clrForestGreen);
PlotIndexSetInteger(3,PLOT_LINE_COLOR, clrSienna);
PlotIndexSetInteger(4,PLOT_LINE_COLOR, clrDodgerBlue);
PlotIndexSetInteger(5,PLOT_LINE_COLOR, clrGreen);
PlotIndexSetInteger(6,PLOT_LINE_COLOR, clrBrown);
PlotIndexSetInteger(7,PLOT_LINE_COLOR, clrMediumBlue);
PlotIndexSetInteger(8,PLOT_LINE_COLOR, clrTeal);
PlotIndexSetInteger(9,PLOT_LINE_COLOR, clrMaroon);
PlotIndexSetInteger(0,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(1,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(2,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(3,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(4,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(5,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(6,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(7,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(8,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(9,PLOT_LINE_WIDTH, 0);
SetIndexBuffer(20,nen_ZigZagH,INDICATOR_DATA); // Plot = 10SetIndexBuffer(21,nen_ZigZagL,INDICATOR_DATA); // Plot = 11PlotIndexSetInteger(10,PLOT_DRAW_TYPE,DRAW_ARROW);
PlotIndexSetInteger(10, PLOT_ARROW, 159);
PlotIndexSetInteger(10,PLOT_LINE_STYLE, STYLE_SOLID);
PlotIndexSetInteger(10,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(10,PLOT_LINE_COLOR, clrMagenta);
PlotIndexSetInteger(11,PLOT_DRAW_TYPE,DRAW_ARROW);
PlotIndexSetInteger(11, PLOT_ARROW, 159);
PlotIndexSetInteger(11,PLOT_LINE_STYLE, STYLE_SOLID);
PlotIndexSetInteger(11,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(11,PLOT_LINE_COLOR, clrMagenta);
SetIndexBuffer(22,ham,INDICATOR_DATA); // Plot = 12SetIndexBuffer(23,lam,INDICATOR_DATA); // Plot = 13PlotIndexSetInteger(12,PLOT_DRAW_TYPE,DRAW_LINE);
PlotIndexSetInteger(12,PLOT_LINE_STYLE, STYLE_DOT);
PlotIndexSetInteger(12,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(12,PLOT_LINE_COLOR, clrGreen);
PlotIndexSetInteger(13,PLOT_DRAW_TYPE,DRAW_LINE);
PlotIndexSetInteger(13,PLOT_LINE_STYLE, STYLE_DOT);
PlotIndexSetInteger(13,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(13,PLOT_LINE_COLOR, clrOrange);
SetIndexBuffer(24,ha,INDICATOR_DATA); // Plot = 14SetIndexBuffer(25,la,INDICATOR_DATA); // Plot = 15PlotIndexSetInteger(14,PLOT_DRAW_TYPE,DRAW_LINE);
PlotIndexSetInteger(14,PLOT_LINE_STYLE, STYLE_DOT);
PlotIndexSetInteger(14,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(14,PLOT_LINE_COLOR, clrGreen);
PlotIndexSetInteger(15,PLOT_DRAW_TYPE,DRAW_LINE);
PlotIndexSetInteger(15,PLOT_LINE_STYLE, STYLE_DOT);
PlotIndexSetInteger(15,PLOT_LINE_WIDTH, 0);
PlotIndexSetInteger(15,PLOT_LINE_COLOR, clrRed);
SetIndexBuffer(26,ZigzagBuffer,INDICATOR_DATA);
SetIndexBuffer(27,HighMapBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(28,LowMapBuffer,INDICATOR_CALCULATIONS);
PlotIndexSetInteger(16,PLOT_DRAW_TYPE,DRAW_SECTION);
PlotIndexSetInteger(16,PLOT_LINE_STYLE, STYLE_SOLID);
PlotIndexSetInteger(16,PLOT_LINE_WIDTH, 1);
PlotIndexSetInteger(16,PLOT_LINE_COLOR, clrRed);
//--- set short name and digits PlotIndexSetString(16,PLOT_LABEL,"ZigZag("+(string)ExtDepth+","+(string)ExtDeviation+","+(string)ExtBackstep+")");
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//--- set empty valuePlotIndexSetDouble(16,PLOT_EMPTY_VALUE,0.0);
//--- to use in cycle
deviation=ExtDeviation*_Point;
//---return(0);
}
//+------------------------------------------------------------------+//| searching index of the highest bar |//+------------------------------------------------------------------+intiHighest(constdouble &array[],
int depth,
int startPos)
{
int index=startPos;
//--- start index validationif(startPos<0)
{
Print("Invalid parameter in the function iHighest, startPos =",startPos);
return0;
}
int size=ArraySize(array);
//--- depth correction if needif(startPos-depth<0) depth=startPos;
double max=array[startPos];
//--- start searchingfor(int i=startPos;i>startPos-depth;i--)
{
if(array[i]>max)
{
index=i;
max=array[i];
}
}
//--- return index of the highest barreturn(index);
}
//+------------------------------------------------------------------+//| searching index of the lowest bar |//+------------------------------------------------------------------+intiLowest(constdouble &array[],
int depth,
int startPos)
{
int index=startPos;
//--- start index validationif(startPos<0)
{
Print("Invalid parameter in the function iLowest, startPos =",startPos);
return0;
}
int size=ArraySize(array);
//--- depth correction if needif(startPos-depth<0) depth=startPos;
double min=array[startPos];
//--- start searchingfor(int i=startPos;i>startPos-depth;i--)
{
if(array[i]<min)
{
index=i;
min=array[i];
}
}
//--- return index of the lowest barreturn(index);
}
//+------------------------------------------------------------------+//| Custom indicator iteration function |//+------------------------------------------------------------------+intOnCalculate(constint rates_total,
constint prev_calculated,
constdatetime &time[],
constdouble &open[],
constdouble &high[],
constdouble &low[],
constdouble &close[],
constlong &tick_volume[],
constlong &volume[],
constint &spread[])
{
int i=0;
int limit=0,counterZ=0,whatlookfor=0;
int shift=0,back=0,lasthighpos=0,lastlowpos=0;
double val=0,res=0;
double curlow=0,curhigh=0,lasthigh=0,lastlow=0;
//--- auxiliary enumerationenum looling_for
{
Pike=1, // searching for next high
Sill=-1// searching for next low
};
//--- initializingif(prev_calculated==0)
{
ArrayInitialize(ZigzagBuffer,0.0);
ArrayInitialize(HighMapBuffer,0.0);
ArrayInitialize(LowMapBuffer,0.0);
}
//--- if(rates_total<100) return(0);
//--- set start position for calculationsif(prev_calculated==0) limit=ExtDepth;
//--- ZigZag was already counted beforeif(prev_calculated>0)
{
i=rates_total-1;
//--- searching third extremum from the last uncompleted barwhile(counterZ<level && i>rates_total-100)
{
res=ZigzagBuffer[i];
if(res!=0) counterZ++;
i--;
}
i++;
limit=i;
//--- what type of exremum we are going to findif(LowMapBuffer[i]!=0)
{
curlow=LowMapBuffer[i];
whatlookfor=Pike;
}
else
{
curhigh=HighMapBuffer[i];
whatlookfor=Sill;
}
//--- chippingfor(i=limit+1;i<rates_total && !IsStopped();i++)
{
ZigzagBuffer[i]=0.0;
LowMapBuffer[i]=0.0;
HighMapBuffer[i]=0.0;
}
}
//--- searching High and Lowfor(shift=limit;shift<rates_total && !IsStopped();shift++)
{
val=low[iLowest(low,ExtDepth,shift)];
if(val==lastlow) val=0.0;
else
{
lastlow=val;
if((low[shift]-val)>deviation) val=0.0;
else
{
for(back=1;back<=ExtBackstep;back++)
{
res=LowMapBuffer[shift-back];
if((res!=0) && (res>val)) LowMapBuffer[shift-back]=0.0;
}
}
}
if(low[shift]==val) LowMapBuffer[shift]=val; else LowMapBuffer[shift]=0.0;
//--- high
val=high[iHighest(high,ExtDepth,shift)];
if(val==lasthigh) val=0.0;
else
{
lasthigh=val;
if((val-high[shift])>deviation) val=0.0;
else
{
for(back=1;back<=ExtBackstep;back++)
{
res=HighMapBuffer[shift-back];
if((res!=0) && (res<val)) HighMapBuffer[shift-back]=0.0;
}
}
}
if(high[shift]==val) HighMapBuffer[shift]=val; else HighMapBuffer[shift]=0.0;
}
//--- last preparationif(whatlookfor==0)// uncertain quantity
{
lastlow=0;
lasthigh=0;
}
else
{
lastlow=curlow;
lasthigh=curhigh;
}
//--- final rejectionfor(shift=limit;shift<rates_total && !IsStopped();shift++)
{
res=0.0;
switch(whatlookfor)
{
case0: // search for peak or lawnif(lastlow==0 && lasthigh==0)
{
if(HighMapBuffer[shift]!=0)
{
lasthigh=high[shift];
lasthighpos=shift;
whatlookfor=Sill;
ZigzagBuffer[shift]=lasthigh;
res=1;
}
if(LowMapBuffer[shift]!=0)
{
lastlow=low[shift];
lastlowpos=shift;
whatlookfor=Pike;
ZigzagBuffer[shift]=lastlow;
res=1;
}
}
break;
case Pike: // search for peakif(LowMapBuffer[shift]!=0.0 && LowMapBuffer[shift]<lastlow && HighMapBuffer[shift]==0.0)
{
ZigzagBuffer[lastlowpos]=0.0;
lastlowpos=shift;
lastlow=LowMapBuffer[shift];
ZigzagBuffer[shift]=lastlow;
res=1;
}
if(HighMapBuffer[shift]!=0.0 && LowMapBuffer[shift]==0.0)
{
lasthigh=HighMapBuffer[shift];
lasthighpos=shift;
ZigzagBuffer[shift]=lasthigh;
whatlookfor=Sill;
res=1;
}
break;
case Sill: // search for lawnif(HighMapBuffer[shift]!=0.0 && HighMapBuffer[shift]>lasthigh && LowMapBuffer[shift]==0.0)
{
ZigzagBuffer[lasthighpos]=0.0;
lasthighpos=shift;
lasthigh=HighMapBuffer[shift];
ZigzagBuffer[shift]=lasthigh;
}
if(LowMapBuffer[shift]!=0.0 && HighMapBuffer[shift]==0.0)
{
lastlow=LowMapBuffer[shift];
lastlowpos=shift;
ZigzagBuffer[shift]=lastlow;
whatlookfor=Pike;
}
break;
default: return(rates_total);
}
}
//--- return value of prev_calculated for next callreturn(rates_total);
}
//+------------------------------------------------------------------+
Просьба разработчикам терминала помочь исправить данную ошибку.
По завершении установки в меню "Пуск" создается группа программ торговой платформы, а на рабочем столе дополнительно помещается ярлык программы. Используйте их для запуска. Нельзя запускать одновременно две копии платформы из одной директории. Чтобы одновременно запустить несколько копий, установите соответствующее количество программ в разные...
Для демонстрации ошибки взял зигзаг из поставки метатрейдера. Добавил в код дополнительные буферы, взятые из моей программы. Никаких манипуляций с дополнительными буферами не предусмотрено в данном коде. Они просто для демонстрации ошибки.
Вывел данный зигзаг на график EURUSD таймфрейм H1. Закрыл терминал. Из истории удалил все сформированные таймсерии по EURUSD. То есть удалил все файлы *.hcc и *.hc по валютной паре EURUSD. Это сделано для того, чтобы при загрузке терминала началась загрузка файлов .hcc и формирование файлов .hc с чистого листа.
После запуска терминала на графике EURUSD наблюдается множество артефактов. И вот эти артефакты побороть не получается.
Код модифицированного зигзага в виде текста и в виде файла прикладываю.
Предупреждаю, что задание параметров зигзага оставил через #propert.
Все остальные буферы не задаю через #propert, так как у меня все, в том числе и буферы для зигзагов, изменяются программно динамически.
Просьба разработчикам терминала помочь исправить данную ошибку.
Картинка с артефактами:
Инициализировать нужно все буферы.
Если нет значения в буфере на баре, то это нужно явно прописать в буфере. Т.е., если рассчитанное значение должно быть выведено в буфер - записываем его в буфер, иначе - записываем пустое значение.
Если нет значения в буфере на баре, то это нужно явно прописать в буфере. Т.е., если рассчитанное значение должно быть выведено в буфер - записываем его в буфер, иначе - записываем пустое значение.
Извините, пропустил инициализацию. У меня в программе она есть а в примере пропустил.
В аттаче файл с инициализацией. Эффект тот же.
Вопрос к разработчикам остается. Просьба устранить данную ошибку.
-------------
На мой взгляд, происходит следующее. При запуске программы вместе с терминалом размер таймсерий или равен нулю, или какое-то минимальное значение имеет.
Инициализация производится на имеющемся кусочке истории. А при увеличении размера таймсерий под массивы буферов задействуются участки памяти, которые не прошли через инициализацию. И в результате имеем такой эффект.
Пытался устранять этот эффект через события терминала. Все равно на доли секунды артефакты появляются. А это плохо. Такую программу нельзя выпускать в свет.
Исправить можно так. После выделения памяти под буферы сразу очищать эту память. Но как это сделать? Со стороны разработчика приложений для терминала я не нашел такой возможности.
Код немного переусложнён - я пытался попасть на тот элемент, который не вмещается в кеш-линию и долбить прямо по нему, но не вышло (при большом желании получилось бы наверное, но надоело), а код сильно править не стал. Но так это даже больше впечатляет - всего лишь одно из 16ти сложений выполняется над элементом непопадающим в кеш-линию, тем не менее это даёт ощутимый результат.
ЗЫ: более объективно в данном случае делать RIGHT_ALIGNED через вставки двух short, а не удалением единственного (так добьёмся двух обновлений кеш-линии для обоих случаев). Так ускорение будет скромнее, но всё равно весомо около 1.5 раза.
Простите, но где тут использование выравнивания? Пример вообще о другом.
П. С. Выкладывать код без комментариев и в сыром виде это неуважение к собеседникам.
Правильно было замечено, выравнивание было добавлено для использования объектов структур MQL в сторонних библиотеках, в частности dotnet.
Именно при добавлении поддержки dotnet библиотек и было добавлено выравнивание полей структур/классов pack.
Если говорить коротко и просто, то работает оно так:
Для каждого из типов (char, short, int, ...) есть свой allignment (1, 2, 4, байта соответственно) по умолчанию. Для поля структуры выбирается минимальное из двух выравниваний: по-умолчанию и заданное пользователем (через pack)
При этом, размер объекта с упаковкой устанавливается таким образом, чтобы адресация к полю объекта в массиве всегда была "правильным" ( заданным через pack, по умолчанию на 1 байт ) Именно из-за последнего создаётся ложное впечатление, что pack выравнивает размер структуры - это не так, выравниваются адреса полей, что и влечёт за собой выравнивание размера структуры.
По своей сути с/без WRONG_ALIGNED происходит одно и то же - на каждом while пишем в две соседние кеш-линии (запись в pad всегда в правильный адрес), разница лишь в том, что при WRONG_ALIGNED случаются случаи(не всегда), когда одна из записей в ar происходит в uint, который не попадет целиком в кеш-линию, у меня стабильная разница около 1.5 раз.
Vict:
ЗЫ: ну и тут много фанатов скорости, если начнут всё ровнять по уму, то должны полететь ещё быстрее, в теории по крайней мере.
В общем-то я такого даже не ожидал:
Код немного переусложнён - я пытался попасть на тот элемент, который не вмещается в кеш-линию и долбить прямо по нему, но не вышло (при большом желании получилось бы наверное, но надоело), а код сильно править не стал. Но так это даже больше впечатляет - всего лишь одно из 16ти сложений выполняется над элементом непопадающим в кеш-линию, тем не менее это даёт ощутимый результат.
ЗЫ: более объективно в данном случае делать RIGHT_ALIGNED через вставки двух short, а не удалением единственного (так добьёмся двух обновлений кеш-линии для обоих случаев). Так ускорение будет скромнее, но всё равно весомо около 1.5 раза.
Кстати в mql значение pack по умолчанию 1 вроде как.
Судя по предыдущему посту, возможно есть смысл всем структурам и классам явно прописывать 8.
Не получается побороть ошибку.
Для демонстрации ошибки взял зигзаг из поставки метатрейдера. Добавил в код дополнительные буферы, взятые из моей программы. Никаких манипуляций с дополнительными буферами не предусмотрено в данном коде. Они просто для демонстрации ошибки.
Вывел данный зигзаг на график EURUSD таймфрейм H1. Закрыл терминал. Из истории удалил все сформированные таймсерии по EURUSD. То есть удалил все файлы *.hcc и *.hc по валютной паре EURUSD. Это сделано для того, чтобы при загрузке терминала началась загрузка файлов .hcc и формирование файлов .hc с чистого листа.
После запуска терминала на графике EURUSD наблюдается множество артефактов. И вот эти артефакты побороть не получается.
Код модифицированного зигзага в виде текста и в виде файла прикладываю.
Предупреждаю, что задание параметров зигзага оставил через #propert.
Все остальные буферы не задаю через #propert, так как у меня все, в том числе и буферы для зигзагов, изменяются программно динамически.
Просьба разработчикам терминала помочь исправить данную ошибку.
Картинка с артефактами:
Не получается побороть ошибку.
Для демонстрации ошибки взял зигзаг из поставки метатрейдера. Добавил в код дополнительные буферы, взятые из моей программы. Никаких манипуляций с дополнительными буферами не предусмотрено в данном коде. Они просто для демонстрации ошибки.
Вывел данный зигзаг на график EURUSD таймфрейм H1. Закрыл терминал. Из истории удалил все сформированные таймсерии по EURUSD. То есть удалил все файлы *.hcc и *.hc по валютной паре EURUSD. Это сделано для того, чтобы при загрузке терминала началась загрузка файлов .hcc и формирование файлов .hc с чистого листа.
После запуска терминала на графике EURUSD наблюдается множество артефактов. И вот эти артефакты побороть не получается.
Код модифицированного зигзага в виде текста и в виде файла прикладываю.
Предупреждаю, что задание параметров зигзага оставил через #propert.
Все остальные буферы не задаю через #propert, так как у меня все, в том числе и буферы для зигзагов, изменяются программно динамически.
Просьба разработчикам терминала помочь исправить данную ошибку.
Картинка с артефактами:
Инициализировать нужно все буферы.
Если нет значения в буфере на баре, то это нужно явно прописать в буфере. Т.е., если рассчитанное значение должно быть выведено в буфер - записываем его в буфер, иначе - записываем пустое значение.
В общем-то я такого даже не ожидал:
Запуски у себя не показали заметной разницы.
Если вместо
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Ошибки, баги, вопросы
Vict, 2019.07.09 07:17
Data data[32768];сделать
то происходит замедление в 6 раз!
Инициализировать нужно все буферы.
Если нет значения в буфере на баре, то это нужно явно прописать в буфере. Т.е., если рассчитанное значение должно быть выведено в буфер - записываем его в буфер, иначе - записываем пустое значение.
Извините, пропустил инициализацию. У меня в программе она есть а в примере пропустил.
В аттаче файл с инициализацией. Эффект тот же.
Вопрос к разработчикам остается. Просьба устранить данную ошибку.
-------------
На мой взгляд, происходит следующее. При запуске программы вместе с терминалом размер таймсерий или равен нулю, или какое-то минимальное значение имеет.
Инициализация производится на имеющемся кусочке истории. А при увеличении размера таймсерий под массивы буферов задействуются участки памяти, которые не прошли через инициализацию. И в результате имеем такой эффект.
Пытался устранять этот эффект через события терминала. Все равно на доли секунды артефакты появляются. А это плохо. Такую программу нельзя выпускать в свет.
Исправить можно так. После выделения памяти под буферы сразу очищать эту память. Но как это сделать? Со стороны разработчика приложений для терминала я не нашел такой возможности.
давний баг в редакторе:
- сохраняем файл под новым именем (например: name_v1.2)
- ставим курсор на какую-нибудь переменную (или вызов функции)
- нажимаем alt+g
- открывается старый файл и редактирование перескакивает в него (
В общем-то я такого даже не ожидал:
Код немного переусложнён - я пытался попасть на тот элемент, который не вмещается в кеш-линию и долбить прямо по нему, но не вышло (при большом желании получилось бы наверное, но надоело), а код сильно править не стал. Но так это даже больше впечатляет - всего лишь одно из 16ти сложений выполняется над элементом непопадающим в кеш-линию, тем не менее это даёт ощутимый результат.
ЗЫ: более объективно в данном случае делать RIGHT_ALIGNED через вставки двух short, а не удалением единственного (так добьёмся двух обновлений кеш-линии для обоих случаев). Так ускорение будет скромнее, но всё равно весомо около 1.5 раза.
Простите, но где тут использование выравнивания? Пример вообще о другом.
П. С. Выкладывать код без комментариев и в сыром виде это неуважение к собеседникам.
Правильно было замечено, выравнивание было добавлено для использования объектов структур MQL в сторонних библиотеках, в частности dotnet.
Именно при добавлении поддержки dotnet библиотек и было добавлено выравнивание полей структур/классов pack.
Если говорить коротко и просто, то работает оно так:
Для каждого из типов (char, short, int, ...) есть свой allignment (1, 2, 4, байта соответственно) по умолчанию.
Для поля структуры выбирается минимальное из двух выравниваний: по-умолчанию и заданное пользователем (через pack)
При этом, размер объекта с упаковкой устанавливается таким образом, чтобы адресация к полю объекта в массиве всегда была "правильным" ( заданным через pack, по умолчанию на 1 байт )
Именно из-за последнего создаётся ложное впечатление, что pack выравнивает размер структуры - это не так, выравниваются адреса полей, что и влечёт за собой выравнивание размера структуры.
Например
Результат 16, чтобы адресация к первому полю d всегда была выравненной на 8 байт
Запуски у себя не показали заметной разницы.
Довёл до ума первоначальную идею (в первом коде неправильно считал адреса). Если не затруднит, то интересно будет посмотреть на результат у вас.
По своей сути с/без WRONG_ALIGNED происходит одно и то же - на каждом while пишем в две соседние кеш-линии (запись в pad всегда в правильный адрес), разница лишь в том, что при WRONG_ALIGNED случаются случаи(не всегда), когда одна из записей в ar происходит в uint, который не попадет целиком в кеш-линию, у меня стабильная разница около 1.5 раз.