Errori, bug, domande - pagina 2505

 

un bug di vecchia data nell'editor:

- salvare il file con un nuovo nome (per esempio: nome_v1.2)
- posizionare il cursore su qualche variabile (o chiamata di funzione)
- premere alt+g

- viene aperto un vecchio file e l'editing salta ad esso (

 
Vict:

In generale, non me lo aspettavo nemmeno:

Il codice è un po' troppo complicato - ho provato a raggiungere l'elemento che non entra nella linea di cache e martellare direttamente su di esso, ma non è riuscito (probabilmente avrei potuto farlo se avessi voluto davvero, ma mi sono annoiato), e non ho cambiato troppo il codice. Ma in questo modo è ancora più impressionante - solo uno dei 16 collassi viene eseguito su un elemento che non entra nella linea di cache, tuttavia ha un risultato notevole.

SZY: Più oggettivamente in questo caso fare RIGHT_ALIGNED attraverso l'inserimento di due short, e non rimuovendo un singolo (così otterremo due aggiornamenti della linea di cache per entrambi i casi). L'accelerazione sarà più modesta, ma ancora circa 1,5 volte tanto.

Mi scusi, ma dov'è l'uso dell'allineamento? Non si tratta di questo esempio.

П. С. Postare il vostro codice senza commenti e in forma grezza è irrispettoso per i vostri amici.

 

Correttamente notato, l'allineamento è stato aggiunto per utilizzare gli oggetti struttura MQL in librerie di terze parti, in particolare dotnet.

È stato quando le librerie dotnet sono state aggiunte per supportare dotnet che l'allineamento è stato aggiunto ai campi delle strutture/classi del pacchetto.

Per farla breve e semplice, funziona così:

Per ogni tipo (char, short, int, ...) c'è un allineamento predefinito (1, 2, 4 byte rispettivamente).
Per il campo della struttura si sceglie il minimo di due allineamenti: quello di default e quello definito dall'utente (tramite pack)

Allo stesso tempo, la dimensione dell'oggetto impacchettato è impostata in modo tale che l'indirizzamento del campo dell'oggetto nell'array sia sempre "corretto" (il default di un byte è impostato con il pack).
È quest'ultimo che dà la falsa impressione che il pack allinea la dimensione della struttura - non è vero, gli indirizzi dei campi sono allineati, il che comporta l'allineamento della dimensione della struttura.



Per esempio

struct A pack(8)
  {
   double d;
   char   c;
  };

void OnStart()
  {
   Print(sizeof(A));
   
  }

Risultato 16, in modo che l'indirizzamento al primo campo d sia sempre allineato di 8 byte

 
fxsaber:

Le corse per conto mio non hanno mostrato alcuna differenza evidente.

Ho migliorato l'idea originale (nel primo codice, gli indirizzi erano contati in modo errato). Se non ti dispiace, sarà interessante vedere il risultato per te.

#define  WRONG_ALIGNED
#define  CACHE_LINE_SIZE 64

struct Data {
#ifdef  WRONG_ALIGNED
   ushort pad;
#else
   uint pad;
#endif
   uint ar[CACHE_LINE_SIZE/sizeof(int)+1];
};

#import "msvcrt.dll"
  long memcpy(uint &, uint &, long);
#import
#define  getaddr(x) memcpy(x, x, 0)

void OnStart()
{
   Data data[32768];
   ZeroMemory(data);
   
   srand(GetTickCount());
   
   ulong start_time = GetMicrosecondCount();
   
   for(unsigned i = 0; i < 10000; ++ i) {
      int rndnum = rand();
      while (++rndnum < 32768) {
         int index = int(CACHE_LINE_SIZE - getaddr(data[rndnum].ar[0]) % CACHE_LINE_SIZE) / sizeof(int);
         ++ data[rndnum].ar[index];
         ++ data[rndnum].pad;
      }
   }
      
   Alert(GetMicrosecondCount() - start_time);
   
   Print(data[100].ar[0]);
   Print(data[100].pad);
}
/*
WRONG_ALIGNED:
6206397
6185472

RIGHT_ALIGNED
4089827
4003213
*/
In sostanza la stessa cosa accade con/senza WRONG_ALIGNED - su ogni mentre scriviamo su due linee di cache adiacenti (scrivendo su pad sempre all'indirizzo corretto), l'unica differenza è che con WRONG_ALIGNED ci sono casi (non sempre) in cui una delle voci in ar avviene in uint, che non entrerà completamente nella linea di cache, ho una differenza stabile di circa 1,5 volte.
 
Vict:

Ho elaborato l'idea originale (nel primo codice, non ho contato correttamente gli indirizzi). Se non ti dispiace, sarà interessante vedere il risultato nel tuo caso.

Fondamentalmente la stessa cosa accade con/senza WRONG_ALIGNED - ad ogni mentre scriviamo su due linee di cache adiacenti (voce pad sempre all'indirizzo corretto), l'unica differenza è che con WRONG_ALIGNED ci sono casi (non sempre) in cui una delle voci in ar si verifica in uint, che non colpirà l'intera linea di cache, ho una differenza stabile circa 1,5 volte.

Per favore, spiega, cosa stai cercando di ottenere con questa linea? Nell'esempio precedente era un codice spazzatura.

int index = int(CACHE_LINE_SIZE - getaddr(data[rndnum].ar[0]) % CACHE_LINE_SIZE) / sizeof(int);
 
Francuz:

Per favore, spiega cosa stai cercando di ottenere con questa linea? Nell'esempio precedente era un codice spazzatura.

Trova la nostra posizione nella linea di cache corrente (quella in cui si trova il pad) e prende tale indice per ar[], che l'elemento con esso è nella prossima linea di cache (forse l'elemento è in due linee di cache con WRONG_ALIGNED)

 
Vict:

Trovare la nostra posizione nella linea di cache corrente (quella dove si trova pad) e prendere un indice tale per ar[] che l'elemento con esso sia nella prossima linea di cache (forse l'elemento è in due linee di cache a WRONG_ALIGNED)

Ora stiamo parlando di un offset. Ma quello che lei mostra è un esempio puramente sintetico, che non si verificherà mai nella vita reale. E su esempi reali il guadagno di velocità sarà di circa l'1% nel migliore dei casi. Non dovresti farne un dramma per un'accelerazione così misera.

П. С. Inoltre, avete calcolato la dimensione del registro in modo errato.
 
Francuz:

Ora si parla di spostamento. Ma quello che lei mostra è un esempio puramente sintetico che non si incontrerà mai nella vita reale. Negli esempi del mondo reale, il guadagno di velocità è di circa l'1% nel migliore dei casi. Non si dovrebbe fare un grande affare per un'accelerazione così misera.

No, questo è un esempio abbastanza reale. Solo il 25% delle scritture avviene in luoghi "problematici" all'interfaccia delle linee di cache. Quanto costa? Per esempio, se avete una lunga matrice doppia, una linea di cache contiene solo 4 valori e se non vi preoccupate dell'allineamento (e il compilatore non lo fa per voi) allora avrete il 25% di posti doppi problematici - come è nel mio esempio. Ci sono molte altre sfumature che parlano di allineamento, ma non mi addentrerò in esse - non sono molto ferrato in materia.

Bene, padrone di casa.

P.S. Inoltre, hai calcolato male la dimensione del registro.
Non l'ho contato per niente ))
 
Vict:

No, questo è un esempio perfettamente realistico. In esso, solo il 25% delle voci si verifica in posizioni "problematiche" alla giunzione della linea della cache. È molto? Per esempio, se avete una lunga matrice doppia, una linea di cache contiene solo 4 valori, e se non vi preoccupate dell'allineamento (e il compilatore non lo fa per voi), allora avrete il 25% di doppio problematico - come nel mio esempio. Ci sono molte altre sfumature, che parlano per l'allineamento, ma non ne parlerò - non sono abbastanza ferrato in materia.

Beh, tu sei il capo.

Ancora una volta dico che siete confusi dalla dimensione del registro.

 
Francuz:

Ancora una volta, stai confondendo la dimensione del registro.

Giustificare