La serie dedicata alla nuova architettura NEx64T è arrivata al capolinea, dopo averla confrontata con quelle più note e importanti. Di seguito viene riportato l’elenco dei precedenti articoli, per rendere più facile recuperarli:
NEx64T – 1: Una Nuova Speranza
NEx64T – 2: struttura degli opcode per una decodifica semplice
NEx64T – 3: lunghezza delle istruzioni ed istruzioni eseguite
NEx64T – 4: uno sguardo alla nuova architettura
NEx64T – 5: modalità d’indirizzamento e valori immediati
NEx64T – 6: il legacy di x86/x64
NEx64T – 7: la nuova unità SIMD/vettoriale
NEx64T – 8: confronto con altre architetture
Dalla lista si può anche intuire come la nuova ISA affronti i punti più importanti in quest’ambito, a cui va posta particolare enfasi sull’eredità che si trascina da x86 e x64, ma che è stata opportunamente ridimensionata a seguito di particolari scelte che sono state fatte a livello di progettazione, in modo da ridurne al minimo l’impatto in tutte più importanti aree (silicio / numero di transistor, consumi, prestazioni).
E’ indubbio, infatti (nonché l’obiettivo principale per cui è chiaramente nata), che voglia rimpiazzare queste ultime, togliendo di mezzo un bel po’ di roba obsoleta che grava sui core dei processori, e portando al contempo una notevole quantità di innovazioni per essere molto più competitiva di quanto non lo siano adesso, considerato che la concorrenza si sta facendo sempre più agguerrita.
Da questo punto di vista va sottolineato come, oltre all’enorme libreria software a disposizione per essa, il punto di forza di queste due architetture è rappresentato dalle elevate prestazioni che le hanno caratterizzate, grazie agli investimenti principalmente di Intel e AMD per metterle al passo col le più blasonate architetture L/S
(ex-RISC
), in particolare a partire dall’80486 (uno dei due “anti-RISC”. L’altro era lo spettacolare 68040 di Motorola).
Il che non stupisce di certo, considerata la fame di prestazioni che il progresso tecnologico ha demandato per soddisfare i bisogni sempre più elevati dell’intera società, portandoci ai livelli di comodità e benessere di cui ormai godiamo (e a cui è difficile pensare di rinunciare, dopo averli “assaggiati”).
Il soddisfacimento di tali esigenze è passato sostanzialmente da due punti fondamentali: le frequenze di clock (sempre più elevate) e il numero di istruzioni eseguibili per ciclo di clock (IPC) che, molto (molto!) sommariamente, sono state utilizzate in qualità di “indice prestazionale” (con la famigerata metrica rappresentata dai MIPS).
Fattori a cui, negli ultimi tempi, si sono uniti i consumi dei chip, poiché non è più possibile scalare indefinitamente a livello prestazionale ignorando completamente quanta corrente sia necessaria erogare per alimentare questi dispositivi sempre più voraci.
Il Santo Graal delle prestazioni single-core…
Se le frequenze sempre più elevate sono state garantite dall’adozione di processi produttivi sempre più avanzati e i consumi non erano un problema per quei tempi (anche e soprattutto grazie a tali processi produttivi), lo stesso non si poteva assolutamente dire riguardo l’IPC.
A maggior ragione tenuto conto del fatto che, all’epoca del boom dell’informatica “domestica” (fine anni ’70 – primi anni ’80), i microprocessori non erano abituati a eseguire più istruzioni per ciclo di clock, ma, al contrario, le istruzioni richiedevano più cicli di clock per poter essere eseguite.
Il primordiale concetto di RISC ha sostanzialmente contribuito a introdurre quello di IPC, in quanto rappresenta uno dei quattro pilastri (eseguire le istruzioni in un ciclo di clock) sui quali questa macrofamiglia di architetture è basato (come già ampiamente discusso in una recente serie di articoli), ovviamente nel momento in cui si è passati a eseguire più istruzioni per ciclo di clock, per l’appunto.
Cosa che ha ulteriormente contribuito a rendere più difficile la valutazione delle prestazioni di un processore, con il già citato MIPS che ha progressivamente perso ogni significato in qualità di metrica da utilizzare per misurarle, che ha dato il la a diversi benchmark nati per prendere il suo posto, fra cui va rigorosamente citato l’arcinoto SPEC (diventato lo standard industriale di fatto).
In ogni caso e qualunque sia la metrica di riferimento, l’obiettivo dei costruttori di CPU (per lo meno di quelle mainstream / più “generali”) è stato quello di ricercare sempre migliori prestazioni, che fino all’avvento dei sistemi multithread & multicore hanno riguardato, infatti, un solo core e un solo thread hardware (parlando di SMT
), e per tale motivo ci si riferisce, in questo caso, a prestazioni in single-core/thread.
Ambito in cui, e come già detto, i processori di Intel e AMD si sono imposti sulla più rinomata concorrenza, quando gli ingegneri di queste aziende hanno trovato il modo di implementare in maniera efficace pipeline e superpipeline, col già citato 80486 prima e con Pentium e, soprattutto, Pentium-Pro poi.
D’altra parte è abbastanza ovvio che si arrivasse a questo punto, in quanto, e come già discusso parecchie volte in diversi articoli precedenti, i processori CISC sono, in genere, in grado di eseguire più “lavoro utile” rispetto alle architetture L/S
, richiedendo in media meno istruzioni per implementare e portare a termine un determinato compito.
Il che di conseguenza comporta meno istruzioni da essere caricate & decodificate nel frontend, riducendone la complessità (da questo punto di vista). Basti confrontare i diagrammi delle microarchitettura dei processori per rendersene immediatamente conto: è lampante!
NEx64T, in quanto riprogettazione & estensione di x86/x64, si inserisce prepotentemente nella tradizione di eseguire molto più “lavoro utile” nelle istruzioni, andandosi a posizionare ancora meglio rispetto alla concorrenza (incluse le due architetture che si prefigge di rimpiazzare).
A tal proposito, i precedenti articoli che hanno fornito una panoramica generale sulle istruzioni e sull’unità SIMD/vettoriale hanno mostrato l’enorme potenziale di questa nuova architettura da questo punto di vista, da cui è già possibile prendere atto della quantità di “lavoro utile” che è possibile eseguire dalle singole istruzioni.
Risulta, pertanto, evidente quanto meglio possa fare in ambito prestazionale, anche con frontend e backend più ridotti, col chiaro obiettivo di ottenerne la leadership.
…anche con architetture in-order!
Tutto ciò risulta ancor più vero se si prendono in considerazione le microarchitetture in-order, le quali non consentono di eseguire istruzioni utilizzando qualunque tecnica speculativa (proprie delle microarchitetture out-of-order, invece), ma la loro elaborazione avviene in maniera strettamente sequenziale e ordinata, anche nel caso in cui sia possibile farlo per più d’una per ciclo di clock.
La dimostrazione di ciò risulta abbastanza banale, prendendo un’istruzione come questa:
ADD.L [R0 + R1 * 4 + 0x1245678], 0x9ABCDEF0 ; .L = 32-bit integer
che è in grado di operare direttamente con la memoria, la quale potrebbe anche essere eseguita in un solo ciclo di clock (dipende dalla microarchitettura e, ovviamente, se il dato a cui sommare il valore immediato risulti già in memoria) in un’architettura CISC come x86/x64 o NEx64T.
L’equivalente per un’ISA L/S
è rappresentato da un mini sottoprogramma (l’esempio è puramente teorico / rappresentativo e non si riferisce a nessuna architettura in particolare), assumendo che i registri si possano riutilizzare liberamente (in particolare R0
, che viene sovrascritto):
LOAD R2, [GLOBALS_REG + OFFSET_0x1245678]
ADD R0, R0, R2
LOAD R2, [R0 + R1 * 4]
LOAD R3, [
GLOBALS_REG
+ IMMEDIATE_0x9ABCDEF0]
ADD R2, R2, R3
STORE R2, [R0 + R1 * 4]
Ovviamente queste considerazioni valgono anche per processori out-of-order, dove quelli L/S
possono mitigare l’impatto prestazionale (dover eseguire ben sei istruzioni anziché l’unica dei CISC) potendone eseguire alcune in parallelo, ma il punto è che i CISC non soltanto riescono a fare comunque meglio (e senza particolari sforzi: è nella loro intrinseca natura!), ma è proprio con le architetture in-order dove la situazione diventa a dir poco drammatica per i L/S
e i vantaggi dei CISC vengono assolutamente esaltati.
Questo lo si può toccare con mano nello studio che è stato riportato nel precedente articolo, dove l’Atom in-order a 2 vie di Intel stracciava gli equivalenti (dell’epoca) ARM a due vie (anche out-of-order!) e competeva con quello out-of-order a tre vie. Dunque quelli di cui si sta parlando non sono scenari ipotetici, ma ben concreti.
Sicurezza: attacchi side-channel
Potrà sembra anacronistico stressare la discussione sulle prestazioni di processori in-order quando i sistemi mainstream sono già da parecchie decadi basati su microarchitetture out-of-order, ma ci sono un paio di considerazioni non di poco conto da fare.
La prima è che una grossissima fetta dei dispositivi che integrano processori fanno uso di microarchitetture in-order, perché avere prestazioni più elevate in assoluto non è più importante del mantenimento di consumi ridotti e/o di avere piccoli core (che richiedono meno silicio e, quindi, la cui produzione è molto più economica).
La seconda è che la recente scoperta delle vulnerabilità di tipo side-channel ha scoperchiato il vaso di Pandora rappresentato dalle tante nonché variegate tecniche di esecuzione speculativa impiegate dai processori out-of-order per ottenere le prestazioni migliori possibili.
Sia chiaro che i processori che risultassero affetti da tali vulnerabilità non sarebbero affatto bacati, nella misura in cui implementino in maniera corretta l’ISA. I processori, infatti, funzionano a regola d’arte. Il problema sta nella particolare implementazione che consente di ottenere anche informazioni che altrimenti non dovrebbero essere accessibili: una vulnerabilità, quindi, ma non un bug del progetto.
Ciò precisato, le microarchitetture in-order sono molto importanti da questo punto di vista, perché a quanto pare non risentono di questi attacchi (per lo meno non ne sono state trovate, ma non esistono dimostrazioni che ne siano del tutto esenti. Ciò a memoria, al momento della scrittura di questo articolo).
Il che significa che si possono preferire tali processori al posto di altri out-of-order, se la sicurezza rivestisse un ruolo più importante delle prestazioni. Da cui risulta a dir poco ovvio che i processori CISC si trovino in una posizione assolutamente più vantaggiosa rispetto a quelli L/S
, come s’è visto.
Ancor meglio con NEx64T, la quale e come abbiamo già visto permette di poter referenziare ben due operandi direttamente in memoria, consentendo di ridurre ancora di più il numero di istruzioni necessarie e, quindi, eccellere con microarchitetture in-order.
Una fonte di problematiche di tipo side-channel è quella delle implementazioni SMT, a causa della condivisione di parte delle risorse presenti in un core. Di recente sono circolate delle voci, le quali sostengono che Intel sia in procinto di abbandonare questa tecnologia in futuri processori.
Il motivo non è da ricercarsi nel togliere di mezzo ogni possibile vulnerabilità che dovesse derivare da questa tecnologia, quanto nel concentrarsi nei nuovi core a basso consumi (chiamati E-Core
nella nomenclatura aziendale).
Quale che sia la ragione per la dismissione dell’Hyper-Threading, c’è da dire che NEx64T propone un modo nuovo e più “creativo” per utilizzare questa tecnologia al fine di migliorare le prestazioni in single-core. Non sono stati forniti dettagli (anche se si era già accennata alla presenza di una “salsa segreta” in uno dei precedenti articoli) per motivi intuibili, ma anche questa innovativa funzionalità andrebbe nel novero dei punti a favore di questa nuova architettura.
La fine della Legge di Moore
Altre motivazioni che ne promuovono l’adozione sono “collaterali” e legate a quanto discusso finora, in quanto diretta conseguenza se aggiungiamo un altro elemento estremamente importante quando parliamo di processori: i processi produttivi.
Sappiamo quanto siano stati assolutamente fondamentali nell’evoluzione dei processori e quali benefici abbiano portato allo sviluppo della nostra civiltà, ma la corsa a processi sempre migliori ha avuto un netto rallentamento negli ultimi anni, a causa di problematiche che emergono quando si fa uso di transistor di dimensione sempre più ridotta (e con gli effetti quantistici che cominciano a diventare più rilevanti).
D’altra parte e checché ne dica Intel, che su di essa ha fondato il suo successo, l’avvicinarsi ai limiti della materia porterà inevitabilmente alla fine della cosiddetta Legge di Moore, per lo meno per com’è stata formulata (ossia: legata alla progressiva riduzione della dimensione dei transistor).
Si stanno cercando altre strade (fotonica, uso di materiali alternativi al silicio) per andare oltre e continuare il progresso dei chip, ma anche in questo caso si tratterà comunque di rimandare la data di qualche altro anno, perché non si può piegare indefinitamente la materia alle esigenze dell’industria. “E’ ineluttabile…”
Quando ciò avverrà, il miglioramento delle prestazioni in single-core/thread diverrà più problematico, e architetture che sono naturalmente avvantaggiate da questo punto di vista saranno quelle su cui avrà senso puntare, per quanto finora discusso.
E’ importante sottolineare come la metrica single-core/thread rimanga assolutamente di primo piano quando si parla di prestazioni dei processori, nonostante da diversi anni ormai sia esploso il fenomeno dei processori multicore, con alcuni che arrivano a integrarne anche centinaia.
La motivazione è piuttosto semplice: non tutti gli algoritmi sono “parallelizzabili”. Tutt’altro! E’ certamente vero che si è già fatto molto (e si continua a lavorare in tal senso) per cercare di sfruttare quanti più core e nel migliore dei modi, ma ciò è possibile soltanto quando un algoritmo lo consenta, altrimenti anche la presenza di migliaia di core a disposizione diventa del tutto irrilevante.
Ecco perché avere processori in grado di eccellere in single-core/thread è e rimarrà importantissimo. D’altra parte, e se così non fosse, le GPU, che integrano ormai decine di migliaia core al loro interno, avrebbero già preso il posto delle classiche CPU da parecchio tempo.
Il ritorno della programmazione “a basso livello”
Per motivazioni legate alla precedente è prevedibile, di conseguenza, il ritorno alla programmazione in linguaggio assembly o agli equivalenti intrinsic. Certamente non per intere applicazioni, perché sarebbe senz’altro da folli (a meno che non lo si faccia per puro diletto. Ma questo è un altro paio di macchine), però mettere mano alle parti critiche per ottimizzarle meglio (magari anche con l’aiuto dei compilatori, guardando al codice che hanno generato) quando non è possibile fare altro perché il progresso tecnologico si è arrestato, è uno scenario tutt’altro che distopico.
Bisogna essere più realisti del re, insomma: cos’altro si potrebbe fare se i processori non possono migliorare più (in maniera consistente) le prestazioni in single-core/thread? E’ chiaro che bisognerà rivedere il codice già scritto, individuarne i punti critici, e cercare di ottimizzarli il più possibile (a livello algoritmico prima, e via via scendendo a più basso livello).
Da questo punto di vista le architetture più appetibili nonché gradevoli da programmare sono senza dubbio alcuno quelle CISC, in quanto richiedono la scrittura di meno righe di codice / istruzioni per implementare determinati algoritmi.
Compito che è reso più facile anche grazie alla presenza di modalità d’indirizzamento della memoria più complesse, oltre al fatto che la maggior parte delle istruzioni sono anche in grado di accedere direttamente alla memoria (altra semplificazione per gli sviluppatori).
Programmare in assembly coi processori CISC è stato da sempre più semplice e più “digeribile”, e ISA come quelle della famiglia Motorola 68000 ne hanno sublimato il concetto, facendo la gioia di migliaia di appassionati che ancora oggi si divertono “come ai vecchi tempi” scrivendo intere applicazioni o giochi con questo linguaggio.
NEx64T s’inserisce sul solco di questa tradizione, offrendo un’architettura molto più semplice e comoda da programmare anche in assembly, complice anche una forte ispirazione ai suddetti 68000 (di cui sono ancora oggi grandissimo estimatore).
I piani per introdurre NEx64T nel mercato
Appurato che questa nuova architettura abbia tutte le carte in regola per poter avere un ruolo di primo piano, non è pensabile che si possa introdurre di punto in bianco all’interno di ecosistemi solidi e per i quali, come discusso in altri altri articoli, è difficile poter effettuare un cambio di questa portata, soprattutto in tempi brevi.
Ci sono, però, settori in cui NEx64T si presta bene, grazie al fatto di essere stata progettata per essere compatibile al 100% a livello di codice assembly con x86 e x64. Una volta realizzati assemblatori, compilatori, librerie di sistema (libc in primis) e debugger, infatti, è relativamente semplice ottenere eseguibili per questa nuova ISA, poiché nella quasi totalità dei casi sarà sufficiente una banale ricompilazione.
Questo significa che potrebbe essere velocemente adottata per le console di prossima generazione di Sony e Microsoft, in quanto la compatibilità binaria con x64 (che è l’ISA al momento da loro utilizzata) non è indispensabile per le nuove console.
Inoltre realizzare emulatori per poter eseguire i giochi delle precedenti console è di gran lunga più semplice rispetto ad altre architetture, poiché i registri e le istruzioni di x64 si mappano direttamente con gli equivalenti di NEx64T e funzionano esattamente allo stesso modo. Grazie a ciò le prestazioni dovrebbero essere allineate a quelle delle architetture originali, tenendo anche a bada i consumi.
Similmente, potrebbe anche essere impiegata in server, dispositivi embedded o IoT, dove la compatibilità binaria con x86/x64 non è necessaria e, quindi, non servono nemmeno emulatori da dover realizzare.
Rimpiazzare gli attuali sistemi server e desktop che dipendono strettamente da x86/x64 è l’obiettivo di più lungo termine perché richiede più tempo, in quanto la libreria software è enorme e ci sono casi che fanno esplicito uso e riferimento agli opcode di queste architetture.
Un esempio classico è rappresentato da applicazioni o giochi che fanno uso di compilatori JIT che generano al volo binari x86 o x64. In questo caso è indispensabile cambiare il JITer in modo da fargli generare gli equivalenti per NEx64T.
Fortunatamente non si tratta di scenari molto comuni (considerata la totalità del parco software disponibile), ma sono comunque molto importanti e utilizzati, per cui servono investimenti per realizzarne il port per la nuova ISA.
IP/License e brevetti
A fare da contraltare agli investimenti necessari ci sono però, degli indubbi benefici derivanti dal fatto che NEx64T sia un’IP completamente nuova, per cui non è necessario pagare alcuna licenza a Intel e/o AMD per poterla implementare e utilizzare.
Il fatto di essere compatibile x86/x64 a livello assembly non vuol dire, infatti, che utilizzi esattamente gli stessi opcode o IP di queste architetture. Da questo punto di vista l’ISA è completamente diversa, con opcode che non hanno nulla a che vedere con quelli delle altre due architetture.
L’unico elemento comune è rappresentato dal contenuto dei registri (flag, controllo, debug, di sistema), il quale deve coincidere (altrimenti non funzionerebbe il codice ricompilato), ma non è dissimile da quanto succede con gli emulatori di x86/x64.
Avere una struttura degli opcode completamente diversa significa pure trovarsi nella situazione opposta, ossia avere a disposizione una nuova IP che ha un suo valore di mercato e che, quindi, può essere licenziata a chi fosse interessato.
Altro fattore non trascurabile è rappresentato dalla possibilità di richiedere brevetti per alcune soluzioni particolarmente creative e innovative dell’architettura (ad esempio per alcune istruzioni “compatte”), consentendo al contempo di “blindarne” l’utilizzo da parte di terzi. Anche questo è un notevole valore aggiunto per chi volesse investire nel progetto.
Conclusioni
Con quest’ultima riflessione si lancia il guanto di sfida principalmente a Intel e AMD, le quali sono le principali aziende che potrebbero e dovrebbero essere interessate a rimpiazzare le loro ISA con questa nuova, in quanto i loro prodotti hanno accumulato troppo legacy che pesa nell’implementazione, non consentendo più di essere competitive come in passato.
Complice, anche, l’agguerritissima concorrenza, la quale negli ultimi anni ha sfornato prodotti di degni di nota (basti pensare ad Apple ai suoi processori Mx, coi quali ha sostanzialmente fatto le scarpe a Intel, completando il processo di realizzazione “in casa” di tutti i componenti dei suoi dispositivi).
Va ricordato, però, che NEx64T nasce inizialmente come risposta alla domanda se fosse stato possibile realizzare un’estensione a 64 bit di x86 che fosse molto più efficiente di quella x64 che ha tirato fuori AMD. La risposta penso sia scontata.
L’altra sfida era quella di dimostrare agli sfegatati sostenitori dei processori RISC (che non sono più tali, ma esclusivamente L/S
, come ampiamente dimostrato in un’altra serie di articoli) che sì: ancora oggi si progettano processori CISC, i quali hanno molto più potenziale e sono ben più interessanti, e a maggior ragione in ottica futura.
C’è da precisare, però, che NEx64T è un’architettura che non nasce completamente libera, ma soggetta al vincolo di essere di totalmente compatibile, a livello di sorgenti assembly, con x86 e x64, includendo una parte del loro legacy (come spiegato nell’apposito articolo). Tante scelte architetturali e di struttura degli opcode derivano, infatti, da tali vincoli.
Giusto per essere chiari, con RISC-V i progettisti hanno avuto mano completamente libera di decidere ogni singolo aspetto di quest’architettura, sfruttando anche lo spazio degli opcode come meglio credevano.
Ciò non è stato possibile con NEx64T, altrimenti sarebbero state effettuate scelte diverse (anche di molto) per alcuni aspetti. Senza tali “catene” si poteva fare di meglio, insomma, realizzando un CISC più semplice ma anche più efficiente e prestazionale, però al costo di perdere il vantaggio della ricompilazione di qualunque sorgente x86/x64.
Questa, però, è un’altra storia, mentre quella di NEx64T si chiude qua.