À propos du profileur de code MT5 - page 4

 
Renat Fatkhullin:

Prenez n'importe quel code de la livraison standard, profilez-le et basez vos questions dessus, s'il vous plaît. Cela permettra d'évaluer la situation de manière reproductible et de fournir des réponses précises.

Sinon, il n'est pas bon que de petits morceaux de votre code soient responsables des rapports du profileur. Il y a derrière cela une énorme quantité de travail d'optimisation qui transforme tout votre code en une représentation complètement différente, mélangée et intégrée.

Je comprends que sans reproduction, il n'y aura pas de réponses précises.

Il est peu probable que les codes standards soient profilés, mais je vais essayer de donner des morceaux reproductibles.

 
Andrey Khatimlianskii:

Merci pour vos réponses !

1) Je ne pense pas pouvoir le reproduire sur un code simple, oui. Et je ne suis pas prêt à dévoiler tout le projet.

2) Dans ce cas particulier, je suis d'accord.

Mais il existe de nombreuses autres classes qui utilisent le même contrôle ou un contrôle similaire et qui ne peuvent se passer de TimeCurrent ou de GetTickCount.
Comment optimiser leur appel pour ne pas demander plusieurs fois la même valeur ?

Et TimeCurrent est-il vraiment si lourd qu'il puisse être perceptible dans le contexte de calculs très lourds (même s'il est exécuté une fois toutes les 1 ou 5 minutes) ?
Ou est-ce que je me suis encore trompé et que 38,16% de l'unité centrale totale / 26,07% de l'unité centrale personnelle ont été occupés par la vérification de if lui-même (sans tenir compte de l'appel de la fonctionTimeCurrent) ? Mais alors, pourquoi en est-il ainsi ?


1) Il n'est pas utile de comprendre pourquoi une parenthèse ouvrante aussi vorace. Comment interpréter cela ?

2) La question du SelfCPU est maintenant claire, merci. C'est une charge de code de fonction sans tenir compte des fonctions appelées.

Cela explique également le faible niveau de SelfCPU de la chaîne avec iTime - il était très rarement atteint, il était juste rarement appelé.

Mais pourquoi TotalCPU est-il si élevé ? Ou bien il montre la charge de toutes les fonctions iTime (et autres fonctions CopyXXX ?) dans l'ensemble du programme ?

  1. Crochet de rupture - pensez-y comme le prologue d'une fonction qui prend généralement plusieurs instructions pour se placer et notamment initialiser les variables locales.
    Faites attention à la taille des variables locales d'une fonction, vous devez prendre en compte que la taille peut augmenter en raison de l'inlining de
    appelé. Si la fonction consomme plus de 4Kb pour les locaux, la fonction de service est appelé à fournir la mémoire de la pile - c'est une dure vérité Nativa et ne peut pas se débarrasser d'elle

  2. Le SelfCPU ne doit pas compter les appels, sinon il ne ferait que dupliquer le TotalCPU et le temps de ses propres instructions serait dilué par le temps des fonctions appelées
    Le TotalCPU d'une chaîne de caractères est le "temps" de cette chaîne uniquement.
 
Alain Verleyen:

Ne devrait-il pas toujours être de 100% ? Ou même un peu moins, en considérant également les @global_initializations et @global_deinitializations.

Voici plus de 102% ...(Build 3003 sur les données historiques).

Pour l'ancien profileur, l'article disait que cela pouvait être plus

Le profilage nous donne des statistiques importantes : combien de fois chaque fonction a été appelée, combien de temps il a fallu pour l'exécuter. Vous êtes peut-être un peu dérouté par les statistiques en pourcentages. Il faut comprendre ici que les statistiques ne tiennent pas compte de l'imbrication des fonctions, de sorte que la somme de tous les pourcentages sera bien supérieure à 100 %.

 
Vasiliy Pushkaryov :

Sur l'ancien profileur, l'article souligne qu'il peut y avoir plus de

Merci. Mais d'après ce que j'ai compris, cela devrait être différent avec le nouveau profileur. Aucune excuse n'est acceptable, une erreur est une erreur.
 
Ilyas:
  1. Une parenthèse d'arrachage - considérez-la comme le prologue d'une fonction, prenant généralement plusieurs instructions pour la placer et surtout initialiser les variables locales.
    Faites attention au volume des variables locales de la fonction, vous devez tenir compte du fait que le volume peut augmenter en raison de l'inlining de la fonction appelée
    Si la fonction consomme plus de 4Kb pour les locales, une fonction de service est appelée pour fournir de la mémoire de pile - c'est une dure vérité de nativa et on ne peut pas s'en débarrasser

  2. Le SelfCPU ne doit pas compter les appels, sinon il ne fera que dupliquer le TotalCPU et le temps de ses propres instructions sera brouillé par le temps des fonctions appelées
    Le TotalCPU d'une chaîne de caractères est le "temps" de cette chaîne uniquement.

1) Une seule variable double est déclarée dans le corps de la fonction (sans compter le paramètre de fonction simulé const bool).

2) Le processeur a donc reçu iTime( m_symbol, PERIOD_CURRENT, 0 ) pour l'un des 11 outils de travail (c'est celui pour lequel la condition "m_CloseOnFirstTickOnly || m_OpenOnFirstTickOnly" a été déclenchée) ?

Ou voulez-vous dire le mode "Fonctions par appels" (je ne l'ai pas montré) ?


J'essaierai de faire des bouts de code reproductibles avec des résultats que je ne comprends pas, pour parler de manière substantielle.

 

Veuillez m'aider à interpréter les données du profileur à l'aide d'un exemple simple.

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


Ça ressemble à un tas de bêtises.

  • Sleep(2) est complètement absent.
  • Pour une raison quelconque, USAGE consomme plusieurs fois plus que Sleep(1).


J'essaie vraiment de m'y retrouver, mais je n'ai pas encore eu de chance.


J'ai aussi essayé le remplacement de Sleep.

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

#define Sleep Sleep2

Les valeurs du profileur ne sont toujours pas claires.

 
fxsaber #:

Veuillez m'aider à interpréter les données du profileur à l'aide d'un exemple simple.


Ça ressemble à un tas de bêtises.

  • Sleep(2) est complètement absent.
  • Pour une raison quelconque, USAGE mange plusieurs fois plus que Sleep(1).

Ce même code produit des résultats absolument corrects sur MT4.


Qu'est-ce que je fais de travers dans MT5 ?

HH La dernière version de MT5 avec le profileur de MT4 est b2595 (b2593 - si elle produit une erreur de compilation interne).

 
Et qu'est-ce qui vous fait penser que le code que vous écrivez est égal à ce qui est réellement exécutable ?

Combien de fois dois-je vous parler de la sur-optimisation et du mélange du code qui en résulte ? Les préfixes soulignés l'indiquent clairement.

De plus, il est inutile d'utiliser un profileur sur un code aussi minuscule, où le profileur d'échantillonnage n'a pas le temps de rassembler des statistiques.

Un profileur recherche effectivement les points de coût statistiquement significatifs dans un code brutalement optimisé, plutôt que de rechercher le code source ligne par ligne.

Parce que votre code a peu à voir avec son exécution réelle.




 
Renat Fatkhullin profileur sur un code aussi minuscule, où le profileur d'échantillonnage n'a pas le temps de rassembler des statistiques.

Un profileur recherche effectivement les endroits coûteux statistiquement significatifs dans un code brutalement optimisé, et non un guide ligne par ligne du code source.

Parce que votre code a peu à voir avec son exécution réelle.

J'ai dû écrire un exemple aussi simple, car il était impossible d'expliquer les valeurs du profileur sur une EA militante avec une taille importante de code source.

Les questions sont posées ci-dessus. Comment se peut-il qu'il touche le sommeil (1) mais pas le sommeil (2) ? Je suis sûr que vous n'avez rien lancé ou regardé et que vous avez juste écrit votre réponse d'un coup.

Le même non-sens est produit lorsque l'optimisation est désactivée. De plus, l'ancien profileur se trouve déjà dans la b2596 où il n'y avait pas encore de nouvelle approche. J'ai pris le temps d'étudier...

 

J'ai supposé que l'optimiseur intelligent combinait deux Sleeps consécutifs en un seul. Mais la vérification a montré que ce n'est pas le cas.

#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) n'est pas visible.

Raison: