Über den MT5-Code-Profiler - Seite 4

 
Renat Fatkhullin:

Nehmen Sie bitte einen beliebigen Code aus der Standardauslieferung, erstellen Sie ein Profil davon und stützen Sie Ihre Fragen darauf. So können Sie die Situation reproduzierbar einschätzen und genaue Antworten geben.

Andernfalls ist es nicht gut, wenn kleine Teile Ihres Codes für Profiler-Berichte verantwortlich sind. Dahinter verbirgt sich eine enorme Menge an Optimierungsarbeit, die Ihren gesamten Code in eine völlig andere, durcheinandergewürfelte und eingebettete Darstellung verwandelt.

Mir ist klar, dass es ohne Reproduktion keine genauen Antworten geben wird.

Es ist unwahrscheinlich, dass Standardcodes profiliert werden, aber ich werde versuchen, reproduzierbare Teile zu geben.

 
Andrey Khatimlianskii:

Vielen Dank für Ihre Antworten!

1) Ich glaube nicht, dass ich es mit einfachem Code reproduzieren kann, ja. Und ich bin nicht bereit, das ganze Projekt zu verraten.

2) In diesem speziellen Fall stimme ich zu.

Aber es gibt viele andere Klassen, die die gleiche oder eine ähnliche Prüfung verwenden und auf TimeCurrent oder GetTickCount nicht verzichten können.
Wie kann man ihren Aufruf so optimieren, dass sie nicht mehrmals denselben Wert anfordern?

Und ist TimeCurrent wirklich so schwer, dass es sich im Hintergrund von wirklich schweren Berechnungen bemerkbar machen kann (selbst wenn sie alle 1 oder 5 Minuten durchgeführt werden)?
Oder habe ich mich wieder geirrt und 38,16% der Gesamt-CPU / 26,07% der Selbst-CPU wurden durch die Überprüfung von if selbst belegt (ohne Berücksichtigung desTimeCurrent Funktionsaufrufs)? Aber warum ist es dann so?


1) Es hilft nicht zu verstehen, warum eine so gefräßige Eröffnungsparenthese. Wie ist dies zu interpretieren?

2) Über SelfCPU ist jetzt klar, danke. Es ist ein Haufen Funktionscode ohne Rücksicht auf die aufgerufenen Funktionen.

Dies erklärt auch die niedrige SelfCPU des Strings mit iTime - sie wurde nur sehr selten erreicht, sie wurde nur selten aufgerufen.

Aber warum ist TotalCPU so hoch? Oder zeigt es die Auslastung aller iTime- (und anderer CopyXXX-?) Funktionen im gesamten Programm?

  1. Abtrennbare Klammer - stellen Sie sich diese als Prolog einer Funktion vor, die in der Regel mehrere Anweisungen zur Platzierung und insbesondere zur Initialisierung lokaler Variablen benötigt.
    Achten Sie auf die Größe der lokalen Variablen einer Funktion, müssen Sie berücksichtigen, dass die Größe aufgrund von Inlining von aufgerufenen
    erhöhen kann. Wenn Funktion verbraucht mehr als 4Kb für lokale, Service-Funktion aufgerufen wird, um Stack-Speicher zur Verfügung stellen - das ist eine harte Wahrheit Nativa und kann es nicht loswerden

  2. SelfCPU sollte keine Aufrufe zählen, da es sonst einfach TotalCPU duplizieren würde und die Zeit seiner eigenen Anweisungen durch die Zeit der aufgerufenen Funktionen verwässert würde
    TotalCPU für einen String ist nur die "Zeit" dieses Strings
 
Alain Verleyen:

Sollten es nicht immer 100 % sein? Oder sogar etwas weniger, wenn man auch @global_initializations und @global_deinitializations berücksichtigt.

Hier ist mehr als 102% ...(Build 3003 auf historischen Daten).

Für den alten Profiler hieß es in dem Artikel , dass es mehr sein könnte

Das Profiling liefert uns wichtige Statistiken: wie oft wurde jede Funktion aufgerufen, wie viel Zeit wurde für ihre Ausführung benötigt. Vielleicht verwirrt Sie die prozentuale Statistik ein wenig. Dabei ist zu beachten, dass die Statistik die Verschachtelung von Funktionen nicht berücksichtigt, so dass die Summe aller Prozentsätze viel größer als 100 % sein wird.

 
Vasiliy Pushkaryov :

In dem Artikel über den alten Profiler wird darauf hingewiesen, dass es möglicherweise mehr

Ich danke Ihnen. Aber soweit ich weiß, sollte es mit dem neuen Profiler anders sein. Es gibt keine Ausreden, ein Fehler ist ein Fehler.
 
Ilyas:
  1. Eine abreißbare Klammer - stellen Sie sich diese als Prolog einer Funktion vor, die normalerweise mehrere Anweisungen benötigt, um lokale Variablen zu platzieren und insbesondere zu initialisieren.
    Achten Sie auf das Volumen der lokalen Variablen der Funktion, Sie sollten berücksichtigen, dass das Volumen durch das Inlining der aufgerufenen
    Wenn die Funktion mehr als 4Kb für lokale Variablen verbraucht, wird eine Servicefunktion aufgerufen, um Stapelspeicher zur Verfügung zu stellen - dies ist eine harte Wahrheit von nativa und man wird sie nicht los

  2. SelfCPU sollte keine Aufrufe zählen, da es sonst einfach TotalCPU dupliziert und die Zeit seiner eigenen Anweisungen durch die Zeit der aufgerufenen Funktionen verwischt wird
    TotalCPU für eine Zeichenkette ist nur die "Zeit" dieser Zeichenkette

1) Im Funktionsrumpf wird nur eine Double-Variable deklariert (der simulierte Funktionsparameter const bool wird nicht mitgezählt).

2) Der Prozessor hat also iTime( m_symbol, PERIOD_CURRENT, 0 ) für eines der 11 Arbeitsinstrumente empfangen (es war dasjenige, für das die Bedingung "m_CloseOnFirstTickOnly || m_OpenOnFirstTickOnly" ausgelöst wurde)?

Oder meinen Sie den Modus "Funktionen nach Aufrufen" (ich habe ihn nicht gezeigt)?


Ich werde versuchen, reproduzierbare Codeschnipsel mit Ergebnissen zu machen, die ich nicht verstehe, um inhaltlich zu reden.

 

Bitte helfen Sie mir bei der Interpretation der Profiler-Daten anhand eines einfachen Beispiels.

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


Das sieht nach einem Haufen Unsinn aus.

  • Sleep(2) fehlt völlig.
  • Aus irgendeinem Grund verbraucht USAGE mehrere Male mehr als Sleep(1).


Ich versuche wirklich, den Dreh rauszukriegen, habe aber noch kein Glück.


Habe auch Sleep Replacement ausprobiert.

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

#define Sleep Sleep2

Immer noch keine klaren Profiler-Werte.

 
fxsaber #:

Bitte helfen Sie mir bei der Interpretation der Profiler-Daten anhand eines einfachen Beispiels.


Das sieht nach einem Haufen Unsinn aus.

  • Sleep(2) fehlt völlig.
  • Aus irgendeinem Grund frisst USAGE mehrere Male mehr als Sleep(1).

Derselbe Code liefert absolut korrekte Ergebnisse auf MT4.


Was mache ich im MT5 falsch?

HH Der letzte Build von MT5 mit dem Profiler von MT4 ist b2595 (b2593 - wenn er einen internen Compilerfehler erzeugt).

 
Und wie kommen Sie darauf, dass der von Ihnen geschriebene Code mit dem tatsächlich ausführbaren Code übereinstimmt?

Wie oft muss ich Ihnen noch von der Überoptimierung und der Vermischung des resultierenden Codes erzählen? Die eingefügten Präfixe zeigen dies deutlich.

Außerdem macht es keinen Sinn, einen Profiler für solch winzigen Code zu verwenden, bei dem der Sampling-Profiler keine Zeit hat, Statistiken zu sammeln.

Ein Profiler sucht effektiv nach statistisch signifikanten Kostenstellen in brutal optimiertem Code, anstatt den Quellcode Zeile für Zeile zu durchsuchen.

Denn Ihr Code hat wenig mit der tatsächlichen Ausführung zu tun.




 
Renat Fatkhullin Profiler für solch winzigen Code zu verwenden, bei dem der Sampling-Profiler keine Zeit hat, Statistiken zu sammeln.

Ein Profiler sucht effektiv nach statistisch signifikanten, kostspieligen Stellen in brutal optimiertem Code, nicht nach einem zeilenweisen Leitfaden für den Quellcode.

Denn Ihr Code hat wenig mit der tatsächlichen Ausführung zu tun.

Ich musste ein so einfaches Beispiel schreiben, da es unmöglich war, die Profiler-Werte bei einem militanten EA mit einer beträchtlichen Größe des Quellcodes zu erklären.

Oben wurden die Fragen gestellt. Wie kann es sein, dass es auf Sleep(1) trifft, aber nicht auf Sleep(2). Ich bin mir sicher, dass Sie nichts gestartet oder angeschaut haben und Ihre Antwort einfach sofort geschrieben haben.

Derselbe Unsinn wird produziert, wenn die Optimierung deaktiviert ist. Außerdem liegt der alte Profiler bereits in b2596, wo es noch keinen neuen Ansatz gab. Ich habe die Zeit genutzt, um zu studieren...

 

Ich nahm an, dass der intelligente Optimierer zwei aufeinanderfolgende Schläuche zu einem kombiniert. Eine Überprüfung hat jedoch ergeben, dass dies nicht der Fall ist.

#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) ist nicht sichtbar.