Informazioni sul profilatore di codice MT5 - pagina 4

 
Renat Fatkhullin:

Prendete qualsiasi codice dalla consegna standard, profilatelo e basate le vostre domande su di esso, per favore. Questo ti permetterà di valutare la situazione in modo riproducibile e di dare risposte accurate.

Altrimenti non va bene che piccoli pezzi del vostro codice siano responsabili dei rapporti del profilatore. C'è un'enorme quantità di lavoro di ottimizzazione lì dietro che trasforma tutto il vostro codice in una rappresentazione completamente diversa, confusa e incorporata.

Capisco che senza riproduzione non ci saranno risposte precise.

È improbabile che i codici standard siano profilati, ma cercherò di dare dei pezzi riproducibili.

 
Andrey Khatimlianskii:

Grazie per le vostre risposte!

1) Non credo di poterlo riprodurre su un codice semplice, sì. E non sono pronto a dare via l'intero progetto.

2) In questo caso particolare, sono d'accordo.

Ma ci sono molte altre classi che usano lo stesso o simile controllo e non possono fare a meno di TimeCurrent o GetTickCount.
Come ottimizzare la loro chiamata per non richiedere lo stesso valore più volte?

E TimeCurrent è davvero così pesante che può essere notato sullo sfondo di calcoli davvero pesanti (anche se eseguito una volta ogni 1 o 5 minuti)?
O mi sono sbagliato di nuovo e il 38,16% della CPU totale / 26,07% della CPU Self è stato occupato dal controllo del se stesso (senza considerare la chiamata alla funzioneTimeCurrent)? Ma allora perché è così?


1) Non aiuta a capire il perché di una parentesi di apertura così vorace. Come interpretare questo?

2) Su SelfCPU è ora chiaro, grazie. È un carico di codice di funzioni senza tener conto delle funzioni che vengono chiamate.

Questo spiega anche il basso SelfCPU della stringa con iTime - è stato raggiunto molto raramente, è stato chiamato solo raramente.

Ma perché TotalCPU è così alto? O mostra il carico di tutte le funzioni iTime (e altre funzioni CopyXXX?) nell'intero programma?

  1. Parentesi graffa - pensatela come un prologo di una funzione che di solito richiede diverse istruzioni per posizionare e in particolare inizializzare le variabili locali.
    Prestare attenzione alla dimensione delle variabili locali di una funzione, è necessario tenere conto che la dimensione può aumentare a causa dell'inlining di
    chiamato. Se la funzione consuma più di 4Kb per locale, la funzione di servizio è chiamato a fornire memoria dello stack - questa è una dura verità Nativa e non può sbarazzarsi di esso

  2. SelfCPU non dovrebbe contare le chiamate, altrimenti duplicherebbe semplicemente TotalCPU e il tempo delle proprie istruzioni sarebbe offuscato dal tempo delle funzioni chiamate
    TotalCPU per una stringa è solo il "tempo" di quella stringa
 
Alain Verleyen:

Non dovrebbe essere sempre il 100%? O anche un po' meno, considerando anche @global_initializations e @global_deinitializations.

Qui è più del 102% ...(Build 3003 su dati storici).

Per il vecchio profiler l'articolo diceva che potrebbe essere più

Il profiling ci dà importanti statistiche: quante volte ogni funzione è stata chiamata, quanto tempo ci è voluto per eseguirla. Potreste essere un po' confusi dalle statistiche in percentuale. Qui bisogna capire che la statistica non considera l'annidamento delle funzioni, quindi la somma di tutte le percentuali sarà molto maggiore del 100%.

 
Vasiliy Pushkaryov :

Sul vecchio profiler, l'articolo sottolineava che ci possono essere più

Grazie. Ma per quanto ho capito dovrebbe essere diverso con il nuovo profiler. Nessuna scusa è accettabile, un errore è un errore.
 
Ilyas:
  1. Una parentesi a strappo - pensatela come un prologo di una funzione, di solito richiede diverse istruzioni per posizionare e soprattutto inizializzare le variabili locali.
    Fate attenzione al volume delle variabili locali della funzione, dovete tener conto che il volume può aumentare a causa dell'inlining di
    chiamato Se la funzione consuma più di 4Kb per le variabili locali, viene chiamata una funzione di servizio per fornire la memoria dello stack - questa è una dura verità di nativa e non c'è modo di liberarsene

  2. SelfCPU non dovrebbe contare le chiamate, altrimenti duplicherà semplicemente TotalCPU e il tempo delle proprie istruzioni sarà offuscato dal tempo delle funzioni chiamate
    TotalCPU per una stringa è solo il "tempo" di quella stringa

1) Solo una variabile doppia è dichiarata nel corpo della funzione (senza contare il parametro di funzione const bool simulato).

2) Quindi il processore ha ricevuto iTime( m_symbol, PERIOD_CURRENT, 0 ) per uno degli 11 strumenti di lavoro (era quello per il quale era scattata la condizione "m_CloseOnFirstTickOnly || m_OpenOnFirstTickOnly")?

O intendete la modalità "Funzioni per chiamate" (non l'ho mostrata)?


Cercherò di fare snippet di codice riproducibile con risultati che non capisco, per parlare in modo sostanziale.

 

Per favore, aiutatemi a interpretare i dati del profiler con un semplice esempio.

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


Sembra un sacco di sciocchezze.

  • Sleep(2) manca completamente.
  • Per qualche ragione USAGE sta consumando diverse volte più di Sleep(1).


Sto davvero cercando di capire come funziona, ma non ho ancora avuto fortuna.


Ho anche provato la sostituzione del sonno.

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

#define Sleep Sleep2

Ancora non sono chiari i valori del profiler.

 
fxsaber #:

Per favore, aiutatemi a interpretare i dati del profiler con un semplice esempio.


Sembra un sacco di sciocchezze.

  • Sleep(2) manca completamente.
  • Per qualche ragione USAGE sta mangiando diverse volte più di Sleep(1).

Questo stesso codice produce risultati assolutamente corretti su MT4.


Cosa sto sbagliando in MT5?

ZZY L'ultima build di MT5 con MT4 profiler è b2595 (b2593 - se produce un errore interno del compilatore).

 
E cosa vi fa pensare che il codice che scrivete sia uguale a quello che è effettivamente eseguibile?

Quante volte devo dirvi della sovraottimizzazione e della fusione del codice risultante? I prefissi sottolineati lo indicano chiaramente.

Inoltre, non ha senso usare il profiler su un codice così minuscolo, dove il profiler di campionamento non ha il tempo di raccogliere statistiche.

Un profiler cerca effettivamente punti di costo statisticamente significativi nel codice brutalmente ottimizzato, piuttosto che essere una ricerca riga per riga del codice sorgente.

Perché il tuo codice ha poco a che fare con la sua effettiva esecuzione.




 
Renat Fatkhullin profiler su un codice così minuscolo, dove il profiler di campionamento non ha il tempo di raccogliere statistiche.

Un profiler cerca effettivamente punti di costo statisticamente significativi nel codice brutalmente ottimizzato, piuttosto che essere una ricerca riga per riga del codice sorgente.

Perché il tuo codice ha poco a che fare con la sua effettiva esecuzione.

Ho dovuto scrivere un esempio così semplice, poiché era impossibile spiegare i valori del profiler su EA militante con dimensioni significative di codice sorgente.

Sopra ha fatto le domande. Come può essere che colpisca Sleep(1) ma non Sleep(2). Sono sicuro che non hai lanciato o guardato nulla e hai scritto la tua risposta in una volta sola.

La stessa assurdità viene prodotta quando l'ottimizzazione è disabilitata. Inoltre, il vecchio profiler si trova già in b2596 dove non c'era ancora un nuovo approccio. Ha passato il tempo a studiare...

 

Ho pensato che l'ottimizzatore intelligente combina due Sleeps in fila in uno solo. Ma il controllo ha dimostrato che non è così.

#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) non è visibile.