Acerca del perfilador de código de MT5 - página 4

 
Renat Fatkhullin:

Tome cualquier código de la entrega estándar, perfílelo y base sus preguntas en él, por favor. Esto le permitirá evaluar la situación de forma reproducible y dar respuestas precisas.

De lo contrario, no es bueno en pequeñas piezas de su código para ser responsable de los informes del perfilador. Hay una enorme cantidad de trabajo de optimización detrás que convierte todo tu código en una representación completamente diferente y desordenada.

Entiendo que sin reproducción no habrá respuestas precisas.

Es poco probable que los códigos estándar estén perfilados, pero intentaré dar trozos reproducibles.

 
Andrey Khatimlianskii:

Gracias por sus respuestas.

1) No creo que pueda reproducirlo en código simple, sí. Y no estoy dispuesta a dar todo el proyecto.

2) En este caso concreto, estoy de acuerdo.

Pero hay muchas otras clases que utilizan la misma comprobación o una similar y no pueden prescindir de TimeCurrent o GetTickCount.
¿Cómo optimizar su llamada para que no solicite el mismo valor varias veces?

¿Y es TimeCurrent realmente tan pesado, que puede notarse en el fondo de cálculos realmente pesados (incluso si se realiza cada 1 o 5 minutos)?
¿O me equivoqué de nuevo y el 38,16% de la CPU total / el 26,07% de la CPU propia fue ocupado por la comprobación del propio if (sin considerar la llamada a la funciónTimeCurrent)? Pero entonces, ¿por qué es así?


1) No ayuda a entender el porqué de un paréntesis inicial tan voraz. ¿Cómo interpretar esto?

2) Lo de SelfCPU ya está claro, gracias. Es una carga de código de funciones sin tener en cuenta las funciones que se llaman.

Esto también explica el bajo AutoCPU de la cadena con iTime - se alcanzó muy raramente, sólo se llamó raramente.

Pero, ¿por qué un TotalCPU tan grande? ¿O muestra la carga de todas las funciones iTime (y otras funciones CopyXXX?) en todo el programa?

  1. Corchete de ruptura - piense en él como un prólogo de una función que generalmente toma varias instrucciones para colocar y en particular inicializar las variables locales.
    Preste atención al tamaño de las variables locales de una función, hay que tener en cuenta que el tamaño puede aumentar debido a la inlining de la llamada
    . Si la función consume más de 4Kb para el local, la función de servicio se llama para proporcionar la memoria de la pila - esto es una dura verdad Nativa y no puede deshacerse de él

  2. SelfCPU no debería contar las llamadas, de lo contrario simplemente duplicaría TotalCPU y el tiempo de sus propias instrucciones se diluiría por el tiempo de las funciones llamadas
    TotalCPU para una cadena es el "tiempo" de esa cadena solamente
 
Alain Verleyen:

¿No debería ser siempre el 100%? O incluso algo menos, teniendo en cuenta también @global_initializations y @global_deinitializations.

Aquí es más del 102% ...(Construir 3003 en los datos históricos).

Para el antiguo perfilador el artículo decía que podía ser más

La creación de perfiles nos proporciona estadísticas importantes: cuántas veces se ha llamado a cada función y cuánto tiempo se ha tardado en ejecutarla. Es posible que las estadísticas de los porcentajes le confundan un poco. Aquí hay que entender que la estadística no considera el anidamiento de funciones, por lo que la suma de todos los porcentajes será mucho mayor que el 100%.

 
Vasiliy Pushkaryov :

Sobre el antiguo perfilador, el artículo señalaba que puede haber más

Gracias. Pero por lo que tengo entendido debería ser diferente con el nuevo perfilador. No se aceptan excusas, un error es un error.
 
Ilyas:
  1. Un corchete de arranque - piense en él como un prólogo de una función, que normalmente toma varias instrucciones para colocar y especialmente inicializar las variables locales.
    Preste atención al volumen de las variables locales de la función, debe tener en cuenta que el volumen puede aumentar debido al inlining de la llamada
    Si la función consume más de 4Kb para las variables locales, se llama a una función de servicio para proporcionar memoria de pila - esta es una dura verdad de nativa y no hay que librarse de ella

  2. SelfCPU no debe contar las llamadas, de lo contrario simplemente duplicará TotalCPU y el tiempo de sus propias instrucciones se verá difuminado por el tiempo de las funciones llamadas
    TotalCPU para una cadena es el "tiempo" de esa cadena solamente

1) Sólo se declara una variable doble en el cuerpo de la función (sin contar el parámetro de la función simulada const bool).

2) ¿Así que el procesador recibió iTime( m_symbol, PERIOD_CURRENT, 0 ) para una de las 11 herramientas de trabajo (fue aquella para la que se disparó la condición "m_CloseOnFirstTickOnly || m_OpenOnFirstTickOnly")?

¿O te refieres al modo "Funciones por llamadas" (no lo he mostrado)?


Intentaré hacer un fragmento de código reproducible con resultados que no entiendo, para hablar con fundamento.

 

Por favor, ayúdame a interpretar los datos del perfilador con un ejemplo sencillo.

#include <fxsaber\Usage\Usage.mqh> // https://www.mql5.com/ru/code/33875

const bool Init = EventSetMillisecondTimer(1);

void f()
{
  Sleep(1);
}

void OnTimer()
{
  _USAGE
  
  f();
  Sleep(2);
}


Parece una tontería.

  • Sleep(2) ha desaparecido por completo.
  • Por alguna razón USAGE está consumiendo varias veces más que Sleep(1).


Intentando de verdad cogerle el tranquillo, sin suerte todavía.


También probé el reemplazo del sueño.

void Sleep2( uint Interval )
{
  const ulong StartTime = GetMicrosecondCount();
  
  Interval *= 1000;
  
  while (GetMicrosecondCount() - StartTime < Interval)
    ;
}

#define Sleep Sleep2

Todavía no están claros los valores del perfilador.

 
fxsaber #:

Por favor, ayúdame a interpretar los datos del perfilador con un ejemplo sencillo.


Parece una tontería.

  • Sleep(2) ha desaparecido por completo.
  • Por alguna razón USAGE está comiendo varias veces más que Sleep(1).

Este mismo código produce resultados absolutamente correctos en MT4.


¿Qué estoy haciendo mal en MT5?

ZZY La última compilación de MT5 con el perfilador MT4 es b2595 (b2593 - si produce un error interno del compilador).

 
¿Y qué te hace pensar que el código que escribes es igual al que realmente se ejecuta?

¿Cuántas veces tengo que hablarte de la sobreoptimización y la mezcla del código resultante? Los prefijos subrayados lo indican claramente.

Además, no tiene sentido utilizar el perfilador en un código tan minúsculo, en el que el perfilador de muestreo no tiene tiempo de recopilar estadísticas.

Un perfilador busca efectivamente lugares costosos estadísticamente significativos en un código brutalmente optimizado, no una guía línea por línea del código fuente.

Porque su código tiene poco que ver con la ejecución real.




 
Renat Fatkhullin el perfilador en un código tan minúsculo, en el que el perfilador de muestreo no tiene tiempo de recopilar estadísticas.

Un perfilador busca efectivamente puntos de coste estadísticamente significativos en el código brutalmente optimizado, en lugar de ser una búsqueda de código fuente línea por línea.

Porque su código tiene poco que ver con la ejecución real.

Tuve que escribir un ejemplo tan simple, ya que era imposible explicar los valores del perfilador en un EA militante con un tamaño significativo de código fuente.

Por encima de las preguntas. Cómo puede ser que se dé el sueño(1) pero no se dé el sueño(2). Seguro que no has lanzado ni mirado nada y has escrito tu respuesta de golpe.

El mismo sinsentido se produce cuando se desactiva la optimización. Además, el antiguo perfilador ya se encuentra en b2596, donde aún no había un nuevo enfoque. Pasé algún tiempo estudiándolo...

 

Supuse que el optimizador inteligente está combinando dos Sueños seguidos en uno. Pero la comprobación ha demostrado que no es así.

#include <fxsaber\Usage\Usage.mqh> // https://www.mql5.com/ru/code/33875

const bool Init = EventSetMillisecondTimer(1);

void f()
{
  Sleep(1);
}

ulong Temp;

void OnTimer()
{
  _USAGE
  
  f();
  
  Temp += GetMicrosecondCount() - Temp;
  
  Sleep(2);
}

void OnDeinit( const int )
{
  Print(Temp);
}

Sleep(2) no es visible.