Errori, bug, domande - pagina 2165

 

Non sto ottenendo un grafico di ottimizzazione per i valori negativi.

I dati sono disponibili nei risultati dell'ottimizzazione.

Prova a impostare valori negativi nei tuoi EA. I valori possono essere * -1 per controllare.

 
Renat Fatkhullin:

Un controllo ha rivelato che:

  1. SQRT mappato in istruzioni dirette della CPU

  2. SQRT + i calcoli matematici vengono eseguiti senza rami e per un'istruzione (dati a 128 bit) vengono calcolate due radici in una volta sola

    Questo codice si trasforma nel seguente codice assembler SSE:
    Questa è un'opera d'arte in realtà. 8 radici sono state calcolate in 4 chiamate di un'istruzione dell'assemblatore. Due numeri doppi sono valutati in una chiamata.

  3. Quando si opera attraverso un array, tutto va come al solito con controlli, ramificazioni e perdite durante la conversione del doppio -> indice intero.

  4. Quando si lavora con gli array in questo esempio c'è una costante mescolanza FPU/ALU che è molto negativa per la produttività

  5. L'ottimizzazione dell'accesso dinamico all'array è grande - oltre ogni lode. Ma mischiare operazioni FPU/ALU + doppio -> intero + ramificazione fa perdere tempo

La conclusione generale: la matematica ha vinto in MQL5 grazie alla perfetta ottimizzazione. Qui non sono gli array a perdere, ma vince la matematica.

Grazie mille per le preziose informazioni.

La notizia è, naturalmente, più gioiosa. È davvero forte!

Ho sempre detto che le MQ sono belle!

Ma mi rendo anche conto che bisogna stare molto attenti a mescolare i tipi di dati. Ma chi è avvisato è avvisato.
Sarebbe bello ricevere qualche consiglio dagli sviluppatori in questa luce.

Ora sperimenterò con i tipi sia delle variabili ordinarie che degli array. Mi chiedo cosa verrà fuori.

 
Renat Fatkhullin:

Ho fatto degli esperimenti.

Non riesco ancora a mettere insieme il puzzle.

Ho fatto due varianti. Il primo - ha convertito tutto al tipo int. Il secondo - per raddoppiare.

Sì, è diventato un po' più veloce. Ma l'inconveniente principale è ancora lì.

Ecco il blocco frenante principale con la variante int:

 if(arr)
        {  // расчет квадратных корней через массив значений SQRT[]
         D1=SQRT[((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y))];
         D2=SQRT[((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y))];
         D3=SQRT[((X3-X)*(X3-X)+(Y3-Y)*(Y3-Y))];
         D4=SQRT[((X4-X)*(X4-X)+(Y4-Y)*(Y4-Y))];
         D5=SQRT[((X5-X)*(X5-X)+(Y5-Y)*(Y5-Y))];
         D6=SQRT[((X6-X)*(X6-X)+(Y6-Y)*(Y6-Y))];
         D7=SQRT[((X7-X)*(X7-X)+(Y7-Y)*(Y7-Y))];
         D8=SQRT[((X8-X)*(X8-X)+(Y8-Y)*(Y8-Y))];
        }

Ha solo il tipo int e nessuna mescolanza di tipi. L'array SQRT stesso è diventato int.

Funziona solo il 10% più velocemente.

La situazione con la doppia variante è simile.

Bene, tutto è identico - solo che nel primo caso è la funzione sqrt() ad essere calcolata e c'è un mix di tipi.

Mentre il secondo caso si riferisce a una matrice int e non c'è mescolanza di tipi, e in teoria si dovrebbe usare solo ALU.

Ma il secondo modo è 3 volte più lento. Beh, qualunque sia la ragione, è la matrice.

C'è un'altra cosa importante.

Nell'esempio int, se la tela ha dimensioni 100x100, cioè con i seguenti parametri

otteniamo un vantaggio di velocità nell'accesso all'array.

Cioè, quando si usa una matrice SQRT di 20 000, si guadagna il 15-20%, e quando si usa una matrice di 3 000 000, si perde il 200%, nonostante una matematica assolutamente identica.

Quindi la dimensione dell'array è la causa dei freni?

File:
LSD_double.mq5  10 kb
LSD_int.mq5  10 kb
 

La gente ha perso da tempo la capacità di capire i risultati dei moderni compilatori C++.

Inoltre, avete un casino di codice, che significa quasi zero possibilità di costruire assiomi ingenui "se queste condizioni, allora il risultato sarà questo". Cioè, l'ottimizzazione risultante riorganizzerà tutto così tanto che le vostre ipotesi produrranno decine di per cento di risultati diversi anche con minuscoli cambiamenti nel codice.

Date un'altra occhiata a stipare 8 radici in 4 comandi di assemblaggio e rendetevi conto che non avete la possibilità di affermare, esigere o fare appello alla vostra logica. Gli ottimizzatori hanno operato a lungo a livelli proibitivi, fuori dalla portata dei programmatori.

Il modo in cui il compilatore scompone le radici è un'arte. E state cercando di batterlo con gli array senza nemmeno capire il vincolo più semplice - leggere da un array è già un fallimento. Perfetto lavoro di registro e calcolo in batch delle radici contro la ramificazione (penalità) e la scalata in memoria con frequenti missioni di cache.

Vi state chiedendo "perché è più veloce su un buffer piccolo e fallisce miseramente su uno grande" perché non sapete assolutamente nulla delle cache L1/L2/L3 del processore. Se si entrava nella cache, si contava in fretta. Non preso - aspetta un paio di dozzine di cicli di lettura dei dati dalla cache superiore o dalla memoria.
 
Renat Fatkhullin:

La gente ha perso da tempo la capacità di capire i risultati dei moderni compilatori C++.

Inoltre, avete un casino di codice, il che significa quasi zero possibilità di costruire assiomi ingenui "se queste condizioni, allora il risultato sarà questo". Cioè, l'ottimizzazione finale riorganizzerà tutto così tanto che le vostre ipotesi produrranno decine di per cento di risultati diversi anche con minuscoli cambiamenti nel codice.

Date un'altra occhiata a stipare 8 radici in 4 comandi di assemblaggio e rendetevi conto che non avete la possibilità di affermare, esigere o fare appello alla vostra logica. Gli ottimizzatori hanno operato a lungo a livelli proibitivi, fuori dalla portata dei programmatori.

Posso vedere perfettamente i vostri risultati rispetto a VS e ne sono felice.
Ma la domanda rimane.

Mi scuso per il codice di lavoro caotico, ma stiamo parlando solo di questa sezione di codice e confrontando le due opzioni di esecuzione:

 if(arr)
        {  // расчет квадратных корней через массив значений SQRT[]
         D1=SQRT[((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y))];
         D2=SQRT[((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y))];
         D3=SQRT[((X3-X)*(X3-X)+(Y3-Y)*(Y3-Y))];
         D4=SQRT[((X4-X)*(X4-X)+(Y4-Y)*(Y4-Y))];
         D5=SQRT[((X5-X)*(X5-X)+(Y5-Y)*(Y5-Y))];
         D6=SQRT[((X6-X)*(X6-X)+(Y6-Y)*(Y6-Y))];
         D7=SQRT[((X7-X)*(X7-X)+(Y7-Y)*(Y7-Y))];
         D8=SQRT[((X8-X)*(X8-X)+(Y8-Y)*(Y8-Y))];
        }
 else // расчет квадратных корней через функцию кв. корня sqrt()
        {
         D1=(int)sqrt((X1-X)*(X1-X)+(Y1-Y)*(Y1-Y));
         D2=(int)sqrt((X2-X)*(X2-X)+(Y2-Y)*(Y2-Y));
         D3=(int)sqrt((X3-X)*(X3-X)+(Y3-Y)*(Y3-Y));
         D4=(int)sqrt((X4-X)*(X4-X)+(Y4-Y)*(Y4-Y));
         D5=(int)sqrt((X5-X)*(X5-X)+(Y5-Y)*(Y5-Y));
         D6=(int)sqrt((X6-X)*(X6-X)+(Y6-Y)*(Y6-Y));
         D7=(int)sqrt((X7-X)*(X7-X)+(Y7-Y)*(Y7-Y));
         D8=(int)sqrt((X8-X)*(X8-X)+(Y8-Y)*(Y8-Y));
        }

Non c'è spazzatura qui.

Avete detto che"l'ottimizzazione dell'accesso all' array dinamico è eccellente, oltre ogni lode".

Ma... vedere il mio messaggio precedente.

Come spiega il mio ultimo esperimento?

"Cioè, quando usiamo un array SQRT di dimensione 20.000, siamo ad un guadagno del 15-20%, e quando usiamo un array di dimensione 3.000.000, perdiamo il 200% con esattamente la stessa matematica.

Quindi la dimensione dell'array è la causa dei freni?".

 

Legga attentamente la mia risposta precedente - è completa di una risposta esatta.

Spiegherò le vostre domande in modo semplice: leggete cinque articoli tecnici riflessivi sul design del processore in termini di prestazioni e fattori che lo influenzano. Non si può avere una discussione senza questo, perché bisogna spiegare le basi.

 
Renat Fatkhullin:

Il modo in cui il compilatore scompone le radici è un'arte. E state cercando di batterlo con gli array senza nemmeno capire il vincolo più semplice: leggere da un array è già un fallimento. Perfetto lavoro di registro e calcolo in batch delle radici contro la ramificazione (penalità) e la scalata in memoria con frequenti missioni di cache.

Vi state chiedendo "perché è più veloce su un piccolo buffer e fallisce assordantemente su uno grande" perché non conoscete affatto le cache L1/L2/L3 del processore. Se si entrava nella cache, si contava in fretta. Se non ce l'avete, dovrete aspettare un paio di decine di cicli per leggere i dati dalla cache superiore o dalla memoria.
Renat Fatkhullin:

Legga attentamente la mia risposta precedente - è finita con una risposta esatta.

Lasciatemi spiegare le vostre domande in modo semplice: leggete cinque articoli tecnici riflessivi sul design del processore in termini di prestazioni e fattori che lo influenzano. Non si può avere una discussione senza questo, perché bisogna spiegare le cose fondamentali.

Evviva!!!
Finalmente!
Tu, Renat, dovresti essere pizzicato per tutto.

Il quadro è ora più chiaro per me.

Mi sbagliavo quando davo la colpa al vostro compilatore. Mi dispiace, ho sbagliato. Avrei potuto indovinare che la ragione era nelle cache limitate del processore. Sono davvero pessimo con i processori moderni e ho davvero bisogno di leggerlo.

Eppure, non è per niente che ho scritto questo codice - topo di laboratorio - e ho fatto quest'onda.

Quindi, per i programmatori che leggono questo thread, riassumerò ciò che ho scoperto personalmente come risultato di questa ondata:

  • La funzione sqrt() e molto probabilmente molte altre funzioni elementari sono molto veloci e vengono eseguite non a livello del compilatore, ma a livello della CPU.
  • Il compilatore MQL5 è così forte nell'ottimizzare la logica matematica che batte facilmente il moderno compilatore VS C++. Il che è molto stimolante.
  • È ragionevole cercare di non mischiare i tipi nei compiti ad alta intensità di risorse. Mescolare i tipi porta a una minore velocità di calcolo.
  • LA DIMENSIONE CONTA! (intendo la dimensione dell'array :)) a causa delle peculiarità del lavoro della cache multilivello del processore e della sua dimensione limitata. E i programmatori farebbero bene a guardare la dimensione totale degli array e a capire che l'uso di grandi array può influenzare significativamente la velocità dei calcoli. Per quanto ho capito, stiamo parlando di un lavoro relativamente comodo di array con dimensioni totali che non superano circa 512kB, e si tratta di ~65000 elementi di tipo doppio o ~130000 di int..,

Sono andato a sistemare il mio codice basandomi su questa informazione. Ho spesso abusato della dimensione degli array.

Grazie a tutti!

 

come faccio a sapere se il pulsante del mirino è premuto o rilasciato?

si può catturare quando la rotella del mouse è premuta, ma se il mouse non è in uso come si può fare?

 
Alexandr Bryzgalov:

come faccio a sapere se il pulsante del mirino è premuto o rilasciato?

Si può catturare il clic della rotella del mouse, ma se il mouse non è in uso, che fare?

Che ne dici di forzarlo o spingerlo indietro quando è necessario?

STRUMENTO GRAFICO_CROSSHAIR

Abilita/disabilita l'accesso allo strumento "mirino" premendo il tasto centrale del mouse

bool (valore predefinito true)

 
Alexey Viktorov:

Può essere forzato o spinto indietro se necessario?

STRUMENTO GRAFICO_CROSSHAIR

Abilita/disabilita l'accesso allo strumento "mirino" premendo il tasto centrale del mouse

bool (true di default)

per quanto ho capito accede solo allo strumento, ma non lo spegne.