Ci sono CPU che eseguono questa possibile ottimizzazione della scrittura della cache L1?


9

Quando la CPU con una cache L1 esegue una scrittura, ciò che accade normalmente è che (supponendo che la riga della cache su cui sta scrivendo sia già nella cache L1) la cache (oltre all'aggiornamento dei dati) contrassegna tale riga come sporca e scriverà la riga con i dati aggiornati in un secondo momento.

Una possibile ottimizzazione sarebbe quella di far confrontare la cache tra il contenuto della scrittura e il contenuto precedente della cache e, se sono uguali, non contrassegnare la riga come sporca. Poiché ciò potrebbe consentire alla cache di evitare riscritture in alcune occasioni, posso vedere come il produttore della CPU potrebbe considerare questo valore degno delle porte necessarie per fare questa logica.

La mia domanda: ci sono CPU che eseguono questa ottimizzazione?

Background sul perché sto chiedendo: sto scrivendo del codice che deve avere accessi di memoria costanti; cioè, qualcuno che è in grado di ascoltare il comportamento della cache non dovrebbe essere in grado di dedurre ciò che sto facendo. Alcuni dei miei accessi sono scritture e, nel modo ovvio per implementare questo codice, molte scritture scriveranno gli stessi dati che sono già lì. Devo fare le scritture perché, a seconda dei dati, i dati che sto scrivendo possono essere o meno gli stessi, ed è importante eseguire la stessa azione a prescindere. Se la CPU si ottimizza non effettivamente scrivendo una "scrittura senza modifiche", ciò significherebbe che il comportamento della cache varierebbe a seconda di quello che sto facendo, il che sovvertirebbe il mio obiettivo.

Quindi, c'è una CPU che cerca di ottimizzare le scritture in questo modo?


11
Si dice che ci siano due problemi veramente difficili nell'informatica: invalidare la cache, nominare bene le cose ed errori off-by-one. Questo è un esempio del perché il primo di questi è difficile.
Mason Wheeler,

@poncho dici che "qualcuno che è in grado di ascoltare il comportamento della cache non dovrebbe essere in grado di dedurre ciò che sto facendo". Ora se alcune CPU implementassero questa funzionalità di "riscrittura intelligente" che non invalida la cache a meno che i dati non siano realmente aggiornati, andando un livello più lontano dalla CPU nella gerarchia di memoria, si sarebbe in grado di osservare il traffico / tempismo differenze tra scritture reali e scritture fittizie. È questo che ti preoccupa?
TheCodeArtist

@poncho Anche la tua vera domanda sembra riguardare l'implementazione di una modalità privilegiata / sicura che non perde informazioni sull'utilizzo. Forse dovresti chiederlo? ...
TheCodeArtist il

1
@TheCodeArtist: beh, sono stati pubblicati attacchi crittografici di sidechannel in cui una routine di crittografia potrebbe essere attaccata da un altro programma in esecuzione su un diverso core della stessa CPU, facendo in modo che il programma di attacco controlli la cache condivisa. Credo che un tale programma potrebbe potenzialmente rilevare se le linee della cache L1 sono state svuotate e quindi potrebbe dedurre informazioni sul programma che mi interessa, se la CPU esegue l'ottimizzazione in discussione. Non sto parlando di una "modalità sicura", poiché non presumo la possibilità di modificare la CPU o il sistema operativo.
poncho,

4
Anche se questo è vero oggi, non è garantito che sia vero domani.
pjc50,

Risposte:


4

Da ore di ricerca, non sono stato in grado di trovare una CPU che utilizza questa specifica ottimizzazione. La maggior parte delle ottimizzazioni menzionate di solito riguardavano hit / miss con operazioni di lettura / scrittura e accesso ai dati:

(pagine 7 e) https://cseweb.ucsd.edu/classes/fa14/cse240A-a/pdf/08/CSE240A-MBT-L15-Cache.ppt.pdf

Tuttavia, ciò non significa che questa ottimizzazione non possa essere eseguita. In generale, è possibile accedere a livello di codice alle dimensioni di una riga della cache della CPU. È anche possibile accedere ai valori correnti nei registri della cache, ma è alquanto pericoloso farlo. Se si accede a registri errati in un momento negativo, è possibile manomettere quelli relativi a un programma in esecuzione. Oppure potresti inavvertitamente modificare il contenuto delle righe che stai cercando di leggere.

Ottenere il valore corrente nella cache del registro

Inoltre, tutte le soluzioni teoriche richiedono una qualche forma di implementazione del software (assemblatore). Il più vicino che ho trovato riguarda l'architettura ARM, che sembra consentire la manipolazione della cache. Oltre a ciò, dovresti anche conoscere le dimensioni di una linea cache per la CPU desiderata. È possibile leggere attentamente il contenuto della cache in una posizione secondaria in memoria, con incrementi di dimensioni di linea, e confrontarlo con i dati che stanno per essere scritti nei registri (o le righe della cache L1, in questo caso).

Leggi il contenuto della cache della CPU

Da lì, è possibile escogitare un sistema basato su software che impedisce riscritture identiche. Anche se questo è un po 'semplificato, è perché la soluzione deve essere applicabile a qualsiasi CPU esistente.

Un'altra possibilità che ho trovato correlata alla coerenza della cache:

Passaggio pertinente di un articolo di Wikipedia sulla coerenza

Il punto principale che ha attirato la mia attenzione, in relazione a questo problema, è stata la descrizione Snarfing:

È un meccanismo in cui un controller di cache controlla sia l'indirizzo che i dati nel tentativo di aggiornare la propria copia di una posizione di memoria quando un secondo master modifica una posizione nella memoria principale. Quando si osserva un'operazione di scrittura in una posizione di cui una cache ha una copia, il controller della cache aggiorna la propria copia della posizione della memoria snarf con i nuovi dati.

In altre parole, ci sono forse meccanismi già in atto. È solo che potrebbero non essere utilizzati per l'ottimizzazione che hai suggerito. Dovresti implementare un software che ha eseguito il confronto in lettura / scrittura.


È anche possibile accedere ai valori correnti nei registri della cache, ma è alquanto pericoloso farlo. Eh, questo non ha senso. Intendi i registri della CPU? Il codice asm generato dal compilatore o scritto a mano utilizza i registri per contenere i valori su cui opera ...
Peter Cordes,

Se stai cercando di implementarlo nel software, il compilatore genererà semplicemente codice che lo fa if (mem != x) { mem = x; }invece di mem = x;. Questa a volte è solo un'ottimizzazione per le linee di cache condivise in un programma multi-thread, perché la scrittura interferisce con la lettura di altri thread.
Peter Cordes,

1
"ringhiare" non ha nulla a che fare con questo. È solo uno snooping passivo. Le cache della CPU utilizzano MESI in modo che possano avere cache di riscrittura coerenti.
Peter Cordes,

@PeterCordes Se trovi la mia risposta sgradevole, mi scuso. Tuttavia, sembra che tu abbia più informazioni di me sulla questione. Quindi, perché non rispondere alla domanda tu stesso? La mia risposta è stata ovviamente inadeguata dai tuoi standard ...


3

Scrivere nella cache L1 è un'operazione molto, molto critica.

La scrittura esatta degli stessi dati sembra essere piuttosto rara. Un'ottimizzazione che accelera le cose in questo caso particolare non otterrà molta accelerazione in totale.

D'altra parte, questa ottimizzazione richiede un confronto di vecchi dati e nuovi dati su ogni singola scrittura nella memoria cache. Ciò che peggiora le cose è che richiede che i dati da scrivere siano effettivamente disponibili al momento della scrittura!

Questo di solito non è il caso di una CPU moderna. I dati da scrivere possono ancora essere calcolati per esempio. La cache può ancora andare avanti, caricare la riga della cache, se necessario, contrassegnare la riga della cache come modificata e così via, anche prima che il calcolo sia terminato. Tutta la tenuta della contabilità può già essere eseguita ad eccezione della modifica effettiva della riga della cache. Se si desidera confrontare i risultati appena scritti con i dati della vecchia riga della cache, ciò non è possibile.

Ad esempio, se si dispone del codice C a [i] = x / y; la divisione x / y richiede molto tempo per essere eseguita sulla maggior parte delle CPU. Tuttavia, la maggior parte del lavoro necessario per gestire la memorizzazione del risultato in un [i] è avvenuta molto prima che la divisione finisse; l'unica cosa che manca è lo spostamento di otto byte risultato sulla riga della cache. Un'operazione di svuotamento della riga della cache attenderà automaticamente fino al termine della divisione. Un'operazione che legge un [i] verrà probabilmente reindirizzata per ottenere il risultato direttamente dal divisore.


Una cache che utilizza MESI per coerenza potrebbe comunque eseguire la RFO, ma se i dati comparassero gli stessi una volta che erano pronti, lasciare la linea in stato Esclusivo anziché Modificato. La vera ragione per cui non viene eseguita nell'hardware è che costa letture extra della cache quando i dati si impegnano a memorizzare nella cache e richiederebbe una sorta di cicli atomici di lettura / confronto / scrittura (con impostazione opzionale del bit sporco) che lo fanno succhiare per un implementazione pipeline
Peter Cordes,

1

Una possibile ottimizzazione sarebbe quella di far confrontare la cache tra il contenuto della scrittura e il contenuto precedente della cache e, se sono uguali, non contrassegnare la riga come sporca

Tale ottimizzazione non raddoppierà il tempo necessario alla CPU per scrivere qualcosa nella cache? Poiché ogni scrittura della riga della cache verrà ora accompagnata da un'operazione di confronto, che non è gratuita.

Quindi, attualmente l'ottimizzazione dipenderà dal fattore molto vago: quante volte un software medio riscrive la sua memoria memorizzabile nella cache con gli stessi dati.


Questo confronto verrebbe implementato nella logica della CPU. Non richiederebbe un'operazione CPU aggiuntiva, ma il tempo del segnale potrebbe aumentare, il che potrebbe essere un problema o meno.
ziggystar,

@ziggystar Beh, non sono un maestro dell'hardware, ma mi sono abituato al pensiero che tutto abbia un costo. Quindi confronta l'operazione con la riga della cache. Potrebbe essere veloce. Ma questo è ancora un costo. E penso che gli attuatori abbiano deciso di non pagarlo. Potrebbe essere anche dopo un po 'di pensiero e misurazione.
Vladislav Rastrusny,

1
Ma stai parlando di tempo, in cui il costo potrebbe essere solo un aumento del numero di porte.
ziggystar,

1
@ziggystar: Questo non è solo più cancelli. Quando i dati vengono inviati alla cache, normalmente il processo di invio dei dati può contrassegnare la riga della cache come modificata. Con questa "ottimizzazione", i vecchi dati e i nuovi dati devono entrambi passare attraverso queste porte, il che causerà un certo ritardo e solo allora la cache può essere invalidata. Devi comprimere tutto questo in un ciclo del processore, altrimenti la scrittura su una riga della cache richiede improvvisamente due cicli. E ora per rendere le cose più complicate, considera cosa succede quando scrivo otto parole consecutive su una riga della cache.
gnasher729,

1
E ognuna di queste scritture ritarda la decisione se la riga della cache viene modificata. Quindi, quando si verifica la seconda scrittura, la riga della cache non sa se è stata modificata o meno (ancora). Sarà divertente.
gnasher729,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.