2013-10-18 16 views
15

Sembra esserci un'opinione là fuori che l'utilizzo di un modello di runtime "split stack" non è necessario su architetture a 64 bit. Dico sembra essere, perché non ho visto nessuno effettivamente dire che, ballare solo intorno:Stack non necessari su amd64

L'utilizzo della memoria di un tipico programma multi-threaded può ridurre significativamente , in quanto ogni filo non necessita di pila pessima dimensione . Diventa possibile eseguire milioni di thread (completi NPTL thread o co-routines) in uno spazio di indirizzi a 32 bit. - Ian Lance Taylor

... il che implica che uno spazio di indirizzamento a 64 bit può già gestire.

E ...

... la costante sovraccarico di pile punte e il caso d'uso stretta (deposizione delle uova un numero enorme di attività di I/O-bound su architetture a 32-bit) non è accettabili ... - bstrie

Due domande: questo è quello che stanno dicendo? In secondo luogo, se è così, perché sono inutili su architetture a 64 bit?

risposta

19

Sì, questo è quello che stanno dicendo.

Gli stack divisi sono (attualmente) non necessari su architetture a 64 bit poiché lo spazio degli indirizzi virtuali a 64 bit è così grande da poter contenere milioni di intervalli di indirizzi dello stack, ciascuno grande quanto un intero spazio di indirizzamento a 32 bit, se necessario.

Nel Flat memory model in uso al giorno d'oggi, la traduzione da indirizzi virtuali a posizioni di memoria fisica viene eseguita con il supporto dello hardware MMU. Su amd64 si scopre che è meglio (nel complesso più veloce) riservare grandi blocchi dello spazio di indirizzi virtuali a 64 bit a ogni nuovo stack che si sta creando, mappando solo la prima pagina (4kB) alla RAM effettiva. In questo modo, lo stack sarà in grado di crescere e rimpicciolirsi, se necessario, su indirizzi virtuali contigui (ovvero meno codice in ogni function prologue, una grande ottimizzazione) mentre il sistema operativo riconfigura la MMU per mappare ogni pagina di indirizzi virtuali a un valore reale pagina di RAM, ogni volta che lo stack cresce o si restringe sopra/sotto alcune soglie configurabili.

Selezionando le soglie in modo intelligente (si veda ad esempio la teoria di dynamic arrays) è possibile ottenere O (1) complessità sull'operazione di stack medio, mantenendo i benefici di milioni di stack che possono crescere quanto è necessario e solo consumare la memoria che usano.

PS: l'attuale implementazione Go è molto indietro tutto questo :-)

+0

come viene definita la dimensione massima dello stack teorico? – thwd

+2

Non è definito, è solo una scelta della lingua o del compilatore. Avrei dovuto essere più chiaro, lo modificherò. – Tobia

9

Il team principale Go è attualmente discussing la possibilità di utilizzare stack contigui in una futura versione di Go.

L'approccio dello split stack è utile perché gli stack possono crescere in modo più flessibile, ma richiede anche che il runtime allochi una quantità relativamente grande di memoria per distribuire questi stack. C'è stato un gran numero di confusion sull'uso della memoria di Go, in parte a causa di questo.

Fare stack contigui ma coltivabili (rilocabili) è un'opzione che offre la stessa flessibilità e forse riduce la confusione sull'utilizzo della memoria di Go. Oltre a rimediare ad alcuni casi angosciosi su macchine a bassa memoria (vedi thread collegato).

Per quanto riguarda i vantaggi/svantaggi delle architetture a 32 bit rispetto a 64 bit, non penso che siano direttamente associati all'utilizzo di stack segmentati.

2

Update Vai 1.4 (Q4 2014)

Change to the runtime:

per andare 1.4, il tempo di esecuzione (Garbage Collector, supporto di concorrenza, gestione delle interfacce, mappe, slice, stringhe, ...) è stato scritto principalmente in C, con il supporto di alcuni assemblatori.
In 1.4, gran parte del codice è stato tradotto in Go in modo che il garbage collector possa eseguire la scansione delle pile di programmi nel runtime e ottenere informazioni accurate su quali variabili sono attive.

Questa riscrittura consente al garbage collector in 1.4 di essere completamente preciso, il che significa che è a conoscenza della posizione di tutti i puntatori attivi nel programma. Ciò significa che l'heap sarà più piccolo in quanto non ci saranno falsi positivi che manterranno vivi i non puntatori. Altre modifiche correlate riducono anche la dimensione dell'heap, che è inferiore del 10% -30% rispetto alla versione precedente.

Una conseguenza è che gli stack non sono più segmentati, eliminando il problema di "hot split". Quando viene raggiunto un limite di stack, viene allocato un nuovo stack più grande, vengono copiati tutti i frame attivi per la goroutine e tutti i puntatori nello stack vengono aggiornati.

risposta

iniziale (Marzo 2014)

L'articolo "Contiguous stacks in Go" di Agis Anastasopoulo affronta anche questo problema

Nei casi in cui il limite di stack capita di cadere in un loop stretto , l'overhead di creare e distruggere i segmenti diventa ripetutamente significativo.
Questo è chiamato il problema "hot split" all'interno della comunità Go.

Il "hot split" verrà indirizzato in Go 1.3 mediante l'implementazione di stack contigui.

Ora, quando una pila ha bisogno di crescere, invece di allocare un nuovo segmento avviene quanto segue:

  1. Creare un nuovo, pila po 'più grande
  2. Copiare il contenuto della vecchia pila al nuovo stack
  3. Re-regolare ogni puntatore copiato per puntare a nuovi indirizzi
  4. distruggere il vecchio pila

la seguente dicitura un problema visto principalmente in arhcitectures a 32 bit:

C'è una certa sfida però.
Il runtime 1.2 non sa se una parola di dimensioni puntatore nello stack è un puntatore effettivo o non. Potrebbero esserci float e, più raramente, interi che, se interpretati come puntatori, punterebbero effettivamente ai dati.

A causa della mancanza di tale conoscenza, il garbage collector deve considerare prudentemente tutte le posizioni nei frame dello stack come radici. Ciò lascia la possibilità di perdite di memoria, in particolare su architetture a 32 bit poiché il loro pool di indirizzi è molto più piccolo.

Quando si copiano le pile, tuttavia, è necessario evitare tali casi e quando si riaggiustano devono essere presi in considerazione solo i veri indicatori.

Work was done though e information about live stack pointers è ora incorporato nei file binari ed è disponibile per il runtime.
Questo significa non solo che il collettore in 1.3 può precisely dati dello stack, ma ora è possibile regolare nuovamente i puntatori dello stack.

Problemi correlati