Ci sono ottimizzazioni che fanno guadagnare qualche punto percentuale perché un algoritmo viene rifinito. E poi ci sono quelle che fanno emergere una domanda più interessante: perché stavamo rifacendo ogni volta un lavoro che il sistema poteva già conoscere?
È il caso di una serie di patch guidata da Yuan Liu di Intel per il memory hotplug di Linux. Il problema è molto specifico: quando una zona di memoria cambia estensione, il kernel deve sapere se quella zona è contigua. Il meccanismo esistente ricostruisce questa informazione scandendo la zona pageblock per pageblock. Su zone molto grandi, quella verifica smette di essere un dettaglio e diventa parte misurabile del costo dell’operazione.
La patch v10 pubblicata sulla mailing list del kernel mostra numeri difficili da ignorare: nel test su macchina virtuale, l’hotplug di 256 GB passa da 10 a 3 secondi; con 512 GB da 36 a 7 secondi. L’hot-unplug passa rispettivamente da 11 a 4 secondi e da 36 a 9 secondi. Sono riduzioni del 70%, 81%, 64% e 75% nel test descritto dagli autori.
La tentazione è fermarsi qui e scrivere “Linux accelera il memory hotplug dell’81%”. Sarebbe il modo meno interessante — e meno corretto — di leggere il lavoro.
Il problema non era spostare la memoria
Il punto centrale è set_zone_contiguous(). Quando funzioni come move_pfn_range_to_zone() o remove_pfn_range_from_zone() modificano una zona, Linux deve aggiornare l’informazione che indica se, all’interno dello span della zona, è possibile convertire un PFN in una pagina senza ulteriori verifiche.
La vecchia logica ricontrollava l’intera zona a granularità di pageblock. È una scelta comprensibile: se vuoi sapere se qualcosa è ancora vero dopo una modifica, lo ricontrolli. Ma quando la dimensione della struttura cresce, il costo di quella certezza cresce con lei. E in un sistema che vuole aggiungere o rimuovere centinaia di gigabyte a runtime, “ricontrolliamo tutto” comincia ad avere un prezzo.
La patch introduce invece pages_with_online_memmap dentro struct zone: un contatore che tiene traccia delle pagine nello span della zona dotate di una memory map online. Se spanned_pages == pages_with_online_memmap, il kernel può determinare la contiguità senza ripercorrere l’intera zona pageblock per pageblock.
Quando una proprietà costa troppo da riscoprire a ogni operazione, spesso il problema non è rendere più veloce la scansione: è smettere di averne bisogno.
È un cambio piccolo come idea e molto più importante come modello: invece di ricostruire lo stato dal mondo ogni volta, mantieni lo stato necessario mentre il mondo cambia.
L’81% non è una promessa universale
I benchmark della patch v10 sono stati eseguiti in una VM su server Intel Ice Lake, guest kernel 7.3-rc3 e QEMU 9.0.0, aggiungendo e rimuovendo 256 o 512 GB tramite virtio-mem. Il tempo misurato va dal comando QEMU al momento in cui /proc/meminfo riflette tutta la memoria aggiunta.
Quindi no: non significa che qualsiasi macchina Linux vedrà automaticamente l’81% di miglioramento. Significa che, in quello scenario, una quota enorme del tempo era assorbita da un lavoro la cui complessità cresceva con la zona da controllare. Più la zona diventava grande, più eliminare quella scansione diventava rilevante.
Questo dettaglio è ancora più evidente nei test CXL. Nel riscontro pubblicato da Samsung su una piattaforma Intel Xeon 6960P con dispositivi Samsung CXL 2.0 da 128 GB, i risultati cambiano in funzione della dimensione e della policy di onlining. In alcuni casi il miglioramento sui 512 GB è netto; in altri, soprattutto sui 256 GB, il risultato è quasi neutro o leggermente peggiore. È esattamente il motivo per cui un benchmark va letto come misura di un contesto, non come percentuale da incollare su una brochure.
Perché CXL rende questo problema meno accademico
Per anni abbiamo pensato alla memoria soprattutto come a una quantità decisa prima dell’avvio: installi i DIMM, accendi la macchina, il sistema parte con quella capacità. Virtualizzazione, memory hotplug e soprattutto CXL spostano progressivamente il problema verso il runtime.
Se la memoria può essere aggiunta, rimossa o riconfigurata mentre il sistema è operativo, il costo del lifecycle della memoria entra nell’architettura. Non basta poter collegare capacità aggiuntiva: il sistema operativo deve riuscire ad assorbirla senza trasformare la gestione della memoria in una procedura lenta proprio quando le dimensioni diventano interessanti.
Qui sta il valore della patch oltre il numero da benchmark. CXL promette infrastrutture in cui la memoria è più componibile e meno rigidamente legata alla configurazione iniziale della macchina. Ma la componibilità hardware ha senso soltanto se anche il software che la governa scala. Una scansione lineare che sembrava innocua su quantità tradizionali può diventare un attrito architetturale quando la capacità cresce di centinaia di gigabyte per operazione.
Il pattern si vede molto oltre il kernel
È lo stesso tipo di problema che incontro spesso nei sistemi software, anche molto lontani dal kernel: si conserva il dato principale, ma non l’informazione necessaria a decidere rapidamente. Così, quando serve una risposta, il sistema ripercorre tabelle, oggetti, file o servizi per ricostruire qualcosa che avrebbe potuto mantenere incrementalmente.
Non sempre aggiungere stato è una buona idea. Un contatore derivato introduce invarianti da rispettare, casi limite e il rischio di divergenza. La patch Linux lo mostra bene: pages_with_online_memmap deve essere aggiornato durante online e offline della memoria, gestire i buchi nella memory map e comportarsi in modo conservativo quando il conteggio può essere temporaneamente inferiore al reale. La nuova verifica è anche più severa della precedente: richiede che ogni PFN nello span soddisfi la condizione prevista.
Il vantaggio, però, è che il costo viene spostato dal momento della domanda al momento in cui lo stato cambia. È una scelta architetturale classica: pagare un po’ di complessità nel mantenimento per evitare di pagare una scansione completa su ogni operazione critica.
È la stessa ragione per cui, quando si parla di ottimizzare risorse e processi, guardare soltanto alla velocità della singola istruzione porta spesso fuori strada. Le ottimizzazioni più interessanti cambiano la quantità di lavoro necessaria, non soltanto la velocità con cui eseguiamo lo stesso lavoro.
Il vero segnale: la scala cambia ciò che consideriamo trascurabile
Una scansione pageblock per pageblock può essere perfettamente ragionevole finché la dimensione della zona e la frequenza delle operazioni la rendono irrilevante. Poi cambiano le condizioni: VM più grandi, hotplug da centinaia di gigabyte, memoria CXL. E improvvisamente una parte del codice che prima era solo corretta deve diventare anche scalabile.
Questo è un promemoria utile per chi progetta sistemi: la complessità algoritmica non è una questione accademica da colloquio tecnico. È una proprietà che può restare invisibile per anni e presentare il conto quando cambia la scala operativa.
La serie v10, al momento del lavoro editoriale, è nel percorso di integrazione del sottosistema memory-management: una risposta del maintainer indica l’intenzione di metterla in coda. Non va quindi raccontata come una funzione già distribuita universalmente nelle release stabili. Ma il risultato tecnico è già abbastanza chiaro da essere interessante: il kernel non ha reso magicamente più veloce l’hardware. Ha eliminato una domanda costosa che continuava a farsi da solo.
E, molto spesso, è lì che si trovano le ottimizzazioni che cambiano davvero la scala di un sistema.
Domande frequenti
Che cos’è il memory hotplug in Linux?
È il meccanismo che consente di aggiungere o rimuovere memoria mentre il sistema è in esecuzione. È rilevante soprattutto in virtualizzazione e negli scenari con memoria espandibile o componibile, come CXL.
Cosa ottimizzano le patch Intel?
Evitano di ricostruire la contiguità di una zona scandendola pageblock per pageblock. Il kernel mantiene invece un contatore, pages_with_online_memmap, che consente di determinare la condizione senza ripetere l’intera scansione.
Il memory hotplug diventa davvero più veloce dell’81%?
L’81% è il miglior risultato riportato nei test VM della patch v10: 512 GB passano da 36 a 7 secondi. Non è una percentuale universale: hardware, dimensione, policy di onlining e scenario influenzano il risultato.
Perché questa ottimizzazione è importante per CXL?
CXL rende più realistico aggiungere memoria come risorsa gestita a runtime. Se il software deve compiere scansioni costose ogni volta che la memoria cambia, il costo di gestione cresce proprio negli scenari di maggiore scala.
