Sobre o profiler do código MT5 - página 4

 
Renat Fatkhullin:

Pegue qualquer código da entrega padrão, trace o seu perfil e baseie suas perguntas nele, por favor. Isto permitirá que você avalie a situação de forma reprodutível e dê respostas precisas.

Caso contrário, não é bom em pequenas partes de seu código ser responsável por relatórios de perfiladores. Há uma enorme quantidade de trabalho de otimização acontecendo por lá, o que transforma todo o seu código em uma representação completamente diferente e embutida.

Entendo que sem reprodução não haverá respostas precisas.

É pouco provável que os códigos padrão sejam perfilados, mas tentarei dar pedaços reprodutíveis.

 
Andrey Khatimlianskii:

Obrigado por suas respostas!

1) Acho que não consigo reproduzi-lo em código simples, sim. E eu não estou pronto para entregar o projeto inteiro.

2) Neste caso em particular, concordo.

Mas há muitas outras classes que usam o mesmo controle ou um controle semelhante e não podem passar sem o TimeCurrent ou GetTickCount.
Como otimizar sua chamada para não solicitar o mesmo valor várias vezes?

E o TimeCurrent é realmente tão pesado que pode ser percebido no fundo de cálculos realmente pesados (mesmo se realizado uma vez a cada 1 ou 5 minutos)?
Ou eu me enganei novamente e 38,16% do Total de CPU / 26,07% do Auto CPU foi ocupado verificando se ele mesmo (sem considerar a chamada de funçãoTimeCurrent)? Mas então por que é assim?


1) Não ajuda a entender por que um parêntese de abertura tão voraz. Como interpretar isto?

2) Sobre o SelfCPU agora está claro, obrigado. É uma carga de código de função sem considerar as funções que estão sendo chamadas.

Isto também explica o baixo SelfCPU do fio com o iTime - foi muito raramente alcançado, só raramente foi chamado.

Mas por que um TotalCPU tão grande? Ou mostra a carga de todas as funções do iTime (e outras funções do CopyXXX?) em todo o programa?

  1. Parênteses separadores - pense nisto como um prólogo de uma função que normalmente leva várias instruções para colocar e, em particular, inicializar variáveis locais.
    Preste atenção ao tamanho das variáveis locais de uma função, você deve levar em conta que o tamanho pode aumentar devido ao inlining do chamado
    . Se a função consome mais de 4Kb para local, a função de serviço é chamada para fornecer memória de pilha - esta é uma dura verdade Nativa e não pode se livrar dela

  2. O SelfCPU não deve contar chamadas, caso contrário ele simplesmente duplicaria o TotalCPU e o tempo de suas próprias instruções seria borrado pelo tempo das funções chamadas
    TotalCPU para uma string é apenas o "tempo" dessa string
 
Alain Verleyen:

Não deveria ser sempre 100%? Ou ainda um pouco menos, considerando também @global_initializações e @global_deinicializações.

Aqui está mais de 102% ...(Construir 3003 sobre dados históricos).

Para o antigo profiler, o artigo dizia que poderia ser mais

O perfil nos dá estatísticas importantes: quantas vezes cada função foi chamada, quanto tempo levou para executá-la. Você pode ficar um pouco confuso com as estatísticas em porcentagem. Aqui deve ser entendido que as estatísticas não consideram o agrupamento de funções, portanto a soma de todas as porcentagens será muito maior do que 100%.

 
Vasiliy Pushkaryov :

Sobre o antigo profiler, o artigo apontava que pode haver mais

Obrigado. Mas, pelo que entendi, deveria ser diferente com o novo perfilador. Nenhuma desculpa é aceitável, um erro é um erro.
 
Ilyas:
  1. Um parêntese - pense nele como um prólogo de uma função, geralmente levando várias instruções para colocar e especialmente inicializar as variáveis locais.
    Preste atenção ao volume das variáveis locais da função, você deve levar em conta que o volume pode aumentar devido à inlining do chamado
    Se a função consome mais de 4Kb para variáveis locais, uma função de serviço é chamada para fornecer memória stack - esta é uma dura verdade da nativa e não há como se livrar dela

  2. O SelfCPU não deve contar chamadas, caso contrário ele simplesmente duplicará o TotalCPU e o tempo de suas próprias instruções será borrado pelo tempo das funções chamadas
    TotalCPU para uma string é apenas o "tempo" dessa string

1) Apenas uma variável dupla é declarada no corpo da função (sem contar o parâmetro de função simulada const bool).

2) Então o processador recebeu o iTime( m_symbol, PERIOD_CURRENT, 0 ) para uma das 11 ferramentas de trabalho (foi a que foi acionada a condição "m_CloseOnFirstTickOnly || m_OpenOnFirstTickOnly")?

Ou você quer dizer modo "Funções por Chamadas" (eu não o mostrei)?


Vou tentar fazer um trecho reproduzível do código com resultados que não entendo, para falar substantivamente.

 

Por favor, ajude-me a interpretar os dados do profiler com um exemplo simples.

#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 um monte de disparates.

  • O sono(2) está completamente ausente.
  • Por alguma razão a USAGE está comendo várias vezes mais do que Dormir(1).


Tentando realmente apanhar o jeito, sem sorte ainda.


Também tentou substituir o sono.

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

#define Sleep Sleep2

Ainda não estão claros os valores dos perfis.

 
fxsaber #:

Por favor, ajude-me a interpretar os dados do profiler com um exemplo simples.


Parece um monte de disparates.

  • O sono(2) está completamente ausente.
  • Por alguma razão a USAGE está comendo várias vezes mais do que Dormir(1).

Este mesmo código produz resultados absolutamente corretos no MT4.


O que estou fazendo de errado no MT5?

ZZY A última construção do MT5 com perfil MT4 é b2595 (b2593 - se produzir um erro interno do compilador).

 
E o que o faz pensar que o código que você escreve é igual ao que é realmente executável?

Quantas vezes tenho que lhes falar sobre a otimização excessiva e a mistura do código resultante? Os prefixos em linha indicam isso claramente.

Além disso, não faz sentido utilizar o profiler em um código tão minúsculo, onde o profiler de amostragem não tem tempo para reunir estatísticas.

Um profiler procura efetivamente por pontos de custo estatisticamente significativos em código brutalmente otimizado, em vez de ser uma busca linha por linha do código fonte.

Porque seu código tem pouco a ver com sua execução efetiva.




 
Renat Fatkhullin profiler em um código tão minúsculo, onde o profiler de amostragem não tem tempo para reunir estatísticas.

Um profiler procura efetivamente por pontos de custo estatisticamente significativos em código brutalmente otimizado, em vez de ser uma busca linha por linha do código fonte.

Porque seu código tem pouco a ver com sua execução efetiva.

Tive que escrever um exemplo tão simples, pois era impossível explicar os valores de perfil em EA militante com um tamanho significativo de código fonte.

Acima foram feitas as perguntas. Como pode ser que acerte o Sleep(1) mas não acerte o Sleep(2). Tenho certeza de que você não lançou nem olhou para nada e apenas escreveu sua resposta de uma só vez.

O mesmo absurdo é produzido quando a otimização é desativada. Além disso, o antigo profiler já se encontra no b2596, onde ainda não havia uma nova abordagem. Passou algum tempo estudando-o...

 

Presumi que o otimizador inteligente está combinando dois Sleeps seguidos em um só. Mas a verificação mostrou que este não é o caso.

#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);
}

O sono(2) não é visível.

Razão: