Features of the mql5 language, subtleties and tricks - page 248

 
trader6_1 #:

How about this?

Insert your variant here and compare.

 

Astatic variable declared inside a method of a class is a static variable of the class itself.

class A {
   void foo() {
      static int i;
      i++;
      Print(i);
   }
 public:
   A(){foo();};
} o1, o2, o3;

void OnStart() {
}

result
1

2

3

Not that special. I checked, it's the same in C++. And it seems to make sense. But I didn't know it personally. That's why by habit I often used static variables in class methods, making hard-to-see mistakes (when there are several class objects).

 
Nikolai Semko static variable declared inside a class method is a static variable of the class itself.
I use it for speed, so that I don't need to allocate memory on each call.
  virtual void MultiTick( void )
  {
    static MqlTick Tick = {};

    if (::SymbolInfoTick(this.SymbolOrders, Tick))
      this.NewTick(Tick);

    return;
  }
I haven't measured it, though. Probably self-deception.
 
fxsaber #:
I use it for speed, so that I don't have to allocate memory on each call. I haven't measured it, though. Probably self-delusion.

I think it's justified. But, yes, it would be interesting to measure it. Maybe accessing a global variable takes longer than allocating new memory.

 
Nikolai Semko #:

I think it's justified. But, yes, it would be interesting to measure it. Maybe access to a global variable takes longer than new memory allocation.

It will depend on many factors.

  1. The stack is more likely to be in the processor's cache than .data and .bss segments, simply based on the fact that operations are constantly happening to the stack.
  2. If the structure allocated on the stack is not large or only separate fields are used, then during optimisations the compiler does not allocate memory on the stack at all, but bypasses registers.

Hence the conclusion: don't use static instead of local storage in the above context, it won't be better, but it will almost certainly be worse.

PS. If you remove static in that example, you should also remove the initialisation of the structure, so as not to waste CPU time, it will be initialised in SymbolInfoTick.

 
Vladimir Simakov #:

It's going to depend on a lot of factors.

  1. The probability of finding the stack in the processor's cache is higher than that of .data and .bss segments, simply on the basis of the fact that operations are constantly performed on the stack.
  2. If the structure allocated on the stack is not large or only separate fields are used, then during optimisations the compiler does not allocate memory on the stack at all, but makes do with registers.

Hence the conclusion: don't use static instead of local storage in the above context, it won't be better, but it will almost certainly be worse.

PS. If you remove static in that example, you should also remove the initialisation of the structure, so as not to waste CPU time, it will be initialised in SymbolInfoTick.

I quite admit it.
Still, we should measure it
But it will be difficult to make an objective measurement
 
Nikolai Semko #:
I quite admit it.
Still, we should measure it
But it will be difficult to make an objective measurement
I would say it is self evident, because the stack needs to be allocated anyways, and therefore it will be done in one call.

Additionally this will ensure cache locality, and it will reduce mem paging as well.

So the benefits are obvious, imho.
 
Vladimir Simakov #:

It will depend on many factors.

  1. The stack is more likely to be in the processor's cache than .data and .bss segments, simply based on the fact that operations are constantly happening to the stack.
  2. If the structure allocated on the stack is not large or only separate fields are used, then during optimisations the compiler does not allocate memory on the stack at all, but bypasses registers.

Hence the conclusion: don't use static instead of local storage in the above context, it won't be better, but it will almost certainly be worse.

PS. If you remove static in that example, you should also remove the initialisation of the structure, so as not to waste CPU time, it will be initialised in SymbolInfoTick.

How do you know it will be initialized? Won't it just be filled with values? Or do you mean this with "initialized".
 
Nikolai Semko #:
You still have to measure it
But it would be difficult to make an objective measurement

I tried it.

#define  BENCH(A)                                                             \
  {                                                                          \
    const ulong StartTime = GetMicrosecondCount();                           \
    A;                                                                       \
    Print(#A + ":" + (string)(GetMicrosecondCount() - StartTime) + " mcs."); \
  } 

datetime f1( datetime &Tmp )
{
  static MqlTick Tick = {};

  if (!Tmp)
    Tick.time = 1;
    
  return(Tick.time);
}

datetime f2( datetime &Tmp )
{
  MqlTick Tick;

  if (!Tmp)
    Tick.time = 1;
    
  return(Tick.time);
}

void Bench1( datetime &Tmp )
{
  for (int i = 0; i < 1 e7; i++)
    Tmp += f1(Tmp);
}

void Bench2( datetime &Tmp )
{
  for (int i = 0; i < 1 e7; i++)
    Tmp += f2(Tmp);
}

void OnStart()
{  
  datetime Tmp = 1;

  BENCH(Bench1(Tmp))
  BENCH(Bench2(Tmp))
  
  Print(Tmp);  
}


Result.

Bench1(Tmp):5675 mcs.
Bench2(Tmp):0 mcs.

Frankly speaking, I don't understand why the second line gets zero when there is no initialisation.

 
fxsaber #:

I tried it.


Result.

Frankly speaking, I don't understand why the second line gets zero when there is no initialisation.

Probably because the compiler does an unrole, and reduces it to one assignment line...

Try a random number instead of incrementing by 1.