PDA

View Full Version : Un chip RISC-V promette di demolire Apple M1. Ecco chi c'è dietro e di cosa si tratta


Redazione di Hardware Upg
01-12-2020, 11:21
Link alla notizia: https://www.hwupgrade.it/news/cpu/un-chip-risc-v-promette-di-demolire-apple-m1-ecco-chi-c-e-dietro-e-di-cosa-si-tratta_93873.html

La californiana Micro Magic afferma di aver messo a punto un core basato su ISA RISC-V che non teme confronti, nemmeno l'interessantissimo Apple M1 su base ARM, grazie a frequenze intorno ai 5 GHz e consumi estremamente ridotti.

Click sul link per visualizzare la notizia.

phmk
01-12-2020, 11:50
..."Perciò, per aziende che necessitano di ridurre l'uso della batteria, ad esempio Tesla, possiamo raggiungere le prestazioni necessarie"...
Perciò fammi capire, guardano al consumo di qualche chip e "tralasciano" i motori ... su un'auto ??? :D :D :D

pipperon
01-12-2020, 11:56
sono sempre esistiti processori molto performanti, poi, vuoi per il vecchiume microsoft, vuoi per i costi, vuoi perche' il resto del computer non gli stava dietro sono tutti affondati.

Apple non voleva pagare di piu' i chip power,
arm e' rimasta nel congelatore piu' di 10 anni rinascendo in strambi dispositivi (proma del boom del celli),
sparc era eccellente,
come del resto non ricordare alpha che e' morto per questioni politiche piu' che prestazionali,
ed infine il simpatico Z8000 che non si e' filato nessuno.

Ovviamente rifacendo da zero la isa pensandola per il mondo attuale e senza l'idea di essere un 6502 pompato come ARM o un vecchio rottame come l'8080 tirato alla spasmo permette rendimenti piu' alti.

Sara' da vedere se questo e' sufficiente per far ricompilare tutto per un nuovo processore, certo per android e' piu' semplice, alla fine linux e' stato compilato persino per oggetti incredibili, ma non e' detto.

Il mondo windows e' sempre stato arroccato sull'x86, spesso neppure compilato per i processori attuali, ma quelli di almeno 5 anni prima.

Il mondo apple sta ragionando su ARM e l'embedded ha tanta roba con 68000, Z80, arm, soprattutto arm.

e' difficile a dirsi se avra' successo, del resto quando AMD sverniciava i vari pentium e Cyrix era una valida alternativa manco in un piccolo stagno si riusci a salire di quote.

L'unica caratteristica che smuove le acque e' l'isa open... ma la domanda su compatibilita' fra diversi fornitori, e fra versioni, e' una bella domanda.
Ricordiamo Linux agli inizi che molti programmi per una distro per farli funziare su di un'altra era dura?
Non e' che ti fai tutto un progetto miliardario e poi il chip nuovo non e' compatibile.

Solo chi ha la palla di cristallo ha certezze

pipperon
01-12-2020, 11:58
..."Perciò, per aziende che necessitano di ridurre l'uso della batteria, ad esempio Tesla, possiamo raggiungere le prestazioni necessarie"...
Perciò fammi capire, guardano al consumo di qualche chip e "tralasciano" i motori ... su un'auto ??? :D :D :D

Bisogna parlare di auto elettriche: sarà un bagno di sangue e chi e' dentro, anche solo per sentito dire, e' ricco.

Cfranco
01-12-2020, 12:10
s
Ovviamente rifacendo da zero la isa pensandola per il mondo attuale e senza l'idea di essere un 6502 pompato come ARM o un vecchio rottame come l'8080 tirato alla spasmo permette rendimenti piu' alti.


Guarda che ormai da 20 anni in qua i processori e l'ISA sono praticamente separati ;)
Non dico che puoi prendere qualsiasi processore, sostituirgli il decoder istruzioni con un' altra ISA e farlo andare uguale, ma non manca tanto ( oddio, nel caso di Transmeta l' ISA in teoria si poteva programmare al volo )
E oltretutto le prestazioni migliori le ottieni con le estensioni dedicate, che son tutta roba nuova.

WarDuck
01-12-2020, 12:45
sono sempre esistiti processori molto performanti, poi, vuoi per il vecchiume microsoft, vuoi per i costi, vuoi perche' il resto del computer non gli stava dietro sono tutti affondati.

Apple non voleva pagare di piu' i chip power,
arm e' rimasta nel congelatore piu' di 10 anni rinascendo in strambi dispositivi (proma del boom del celli),
sparc era eccellente,
come del resto non ricordare alpha che e' morto per questioni politiche piu' che prestazionali,
ed infine il simpatico Z8000 che non si e' filato nessuno.

Ovviamente rifacendo da zero la isa pensandola per il mondo attuale e senza l'idea di essere un 6502 pompato come ARM o un vecchio rottame come l'8080 tirato alla spasmo permette rendimenti piu' alti.

Sara' da vedere se questo e' sufficiente per far ricompilare tutto per un nuovo processore, certo per android e' piu' semplice, alla fine linux e' stato compilato persino per oggetti incredibili, ma non e' detto.

Il mondo windows e' sempre stato arroccato sull'x86, spesso neppure compilato per i processori attuali, ma quelli di almeno 5 anni prima.

Il mondo apple sta ragionando su ARM e l'embedded ha tanta roba con 68000, Z80, arm, soprattutto arm.

e' difficile a dirsi se avra' successo, del resto quando AMD sverniciava i vari pentium e Cyrix era una valida alternativa manco in un piccolo stagno si riusci a salire di quote.

L'unica caratteristica che smuove le acque e' l'isa open... ma la domanda su compatibilita' fra diversi fornitori, e fra versioni, e' una bella domanda.
Ricordiamo Linux agli inizi che molti programmi per una distro per farli funziare su di un'altra era dura?
Non e' che ti fai tutto un progetto miliardario e poi il chip nuovo non e' compatibile.

Solo chi ha la palla di cristallo ha certezze

Windows NT e il kernel attuale di Windows possono tranquillamente supportare processori diversi da quello Intel.

Riguardo le ottimizzazioni non è come dici te. La maggior parte delle distribuzioni Linux oggi in circolazione è compilata per x86_64 con ottimizzazioni generiche. E anche per Windows è sostanzialmente la stessa solfa.

Anzi in alcuni casi Windows richiede istruzioni che non sono incluse nel set "generic" x86_64.

Gli Intel x86 32 bit non fanno molto testo ormai, ma anche in quel caso mi sembra di ricordare che Windows richieda almeno il supporto SSE2 (cosa già inclusa di default in x86_64).

Quindi, a meno di compilarsi a manina tutto (a la Gentoo per capirci), la maggior parte del codice (binario) esistente ha come target x86_64 generic.

Edit: aggiungo ancora, per quanto concerne i kernel dei SO importa relativamente come è compilato di base l'eseguibile, dato che viene distribuito con funzioni aventi diversi livelli di ottimizzazione, sulla base del tipo di architettura. In sostanza a run-time vengono fatti dei controlli e viene usato il codice più opportuno per l'architettura rilevata. Questo è vero anche per quei programmi che richiedono performance elevate (mi vengono in mente i programmi per il calcolo scientifico).

White_Tree
01-12-2020, 14:02
Qualcuno ha maggiori info sulla 2da generazione di tale processore?

https://arstechnica.com/science/2019/08/16-bit-risc-v-processor-made-with-carbon-nanutubes/

Sp3cialFx
01-12-2020, 14:50
Facciamo finta che siamo nel 2020 e non nel 1990.
Parlare di "ISA x86" come se fosse un vincolo non ha senso perché ormai è 25 anni che le cpu x86 usano il microcode; in altre parole l'ISA x86 non ha corrispondenza nel silicio. Gli x86 sono core RISC con una piccolissima fetta di silicio dedicata alla traduzione tra ISA x86 al microcode.

Ora, se l'M1 di turno EMULANDO VIA SW un x86 gira al 80/85% del nativo, darei per scontato che il traduttore hardware ISA x86 -> microcode che è integrato nelle CPU x86 possa andare anche oltre.

C'è un'ultima considerazione da fare. Il fatto di avere un traduttore HW consente di avere quindi un livello di astrazione in più rispetto alle altre CPU. Il microcode che hai scelto ti è stretto? Cambi microcode, basta adattare di conseguenza il traduttore.

Fatta tutta questa lunga premessa la mia domanda è:
con le risorse / esperienza di Intel e AMD, e con la possibilità che hanno gli x86 di avere sotto il cofano qualsiasi tipo di core piaccia loro, com'è che Apple tira fuori M1, questi tirano fuori un RISC-V, domani arriva Qualcomm con gli 865 e rimangono al palo?

Disclaimer: gradirei risposte TECNICHE per capire qual è il tassello che mi manca, di chiacchiera da bar ne ho già letta a sufficienza quindi i pipponi su innovazione / ISA x86 / memoria unificata e bla bla anche no grazie

Cfranco
01-12-2020, 15:24
Ora, se l'M1 di turno EMULANDO VIA SW un x86 gira al 80/85% del nativo, darei per scontato che il traduttore hardware ISA x86 -> microcode che è integrato nelle CPU x86 possa andare anche oltre.
96-97% ;)


Fatta tutta questa lunga premessa la mia domanda è:
con le risorse / esperienza di Intel e AMD, e con la possibilità che hanno gli x86 di avere sotto il cofano qualsiasi tipo di core piaccia loro, com'è che Apple tira fuori M1, questi tirano fuori un RISC-V, domani arriva Qualcomm con gli 865 e rimangono al palo?
Intanto parliamo di CoreMark, un test sintetico che ha poco a che vedere con la realtà
Oltretutto se si parla di punteggio per W ovviamente le cpu a bassissimo consumo hanno un enorme vantaggio rispetto alle cpu ad alta potenza, per cui il discorso che fa questo tizio è ovviamente del tutto irrilevante, la sua cpu ha un punteggio altissimo perché non consuma una mazza, mica perché va forte.
Quando cerchi le prestazioni i Watt aumentano esponenzialmente, e quindi il punteggio cala inevitabilmente.
Sul fatto che Apple M1 batta le cpu low power di Intel la spiegazione è brutalmente semplice: 5nm TMSC contro 14nm Intel è una lotta impari.

umanoz
01-12-2020, 15:28
Una risposta tecnica non te la so dare, ma credo sia una questione economica, che senso ha al momento per AMD e Intel competere in quei mercati, profitti e volumi probabilmente non sono ancora al livello per cui valga la pena investire.
Amd non mi pare sia stata proprio ferma al palo, non vedo l'ora che escano i nuovi Epyc

pabloski
01-12-2020, 16:06
Ora, se l'M1 di turno EMULANDO VIA SW un x86 gira al 80/85% del nativo, darei per scontato che il traduttore hardware ISA x86 -> microcode che è integrato nelle CPU x86 possa andare anche oltre.


Non è scontato. Rosetta non è un emulatore, ma un traduttore di codice binario. Funziona come le vm jit di .NET e Java. Il codice viene tradotto quando necessario, cercando un buon tradeoff tra latenze e throughput, e poi viene messo in cache il codice nativo. Non sia mai fosse stata seguita la via dell'emulazione o dell'intepretazione...sarebbero nei guai.

Il microcodice invece è un ammasso di routine programmate manualmente ( non vale per tutte le istruzioni dell'ISA "emulata" ) nel linguaggio macchina dell'ISA sottostante. In questo senso è più prestante, in quanto non traduce nulla. E' come chiamare una funzione in C, tranne che il chiamante e il chiamato non sono codificati nello stesso linguaggio macchina. Per le istruzioni più usate, le microoperazioni vengono direttamente generate da un instruction decoder hardware. Cioè non c'è manco una subroutine in rom che viene letta.

Talune istruzioni necessitano però di utilizzare una complessa sequenziazione delle microoperazioni ( gli automi a stati finiti sono la soluzione comune ) ed è qui che s'insinua il dubbio che esprimevo all'inizio. Perchè ovviamente il microsequenziatore non ha a disposizione la ram. Non può scialacquare in 16-32 GB di memoria e cachare tutto il cachabile.

E c'è la questione di quanta incide il legacy. Cioè tu hai transistor che sono presenti solo perchè ci sono funzionalità legacy da mantenere. Questi transistor sono attivi, consumano corrente. Ciò può limitare la quantità di corrente che puoi dare ad altre subunità ( i processori sono oggetti fisici, attraversati da quantità di elettricità notevoli, che vanno dissipate...e la gestione dell'energia implementata nei moderni processori fa i salti mortali, aumentando/diminuendo tensioni e frequenze dinamicamente nelle varie zone del chip ) e quindi le relative prestazioni.

Ma diventa rapidamente un discorso statistico, tant'è che Intel cosa dice del TDP? Che è la media del calore prodotto durante l'esecuzione di certi workload campione, che nei casi reali hanno certe probabilità di essere eseguiti.

Magari un'altra architettura, in quei workload campione, riesce a mantenere i consumi e quindi il calore a livelli più bassi, in modo da poter dare un maggior boost alle unità funzionali, ottenendo un throughput maggiore.

E' quello che è hanno fatto pure gli ingegneri Apple col M1.

In soldoni, meglio bagaglio legacy ti dà (1) più libertà nella progettazione delle unità funzionali ( e se sei bravo le rendi più efficienti ), (2) meno zavorra elettronica da portarsi dietro solo per mantenere cose come la segmentazione ( che non è usata manco per sbaglio in modalità long, cioè quella x86_64 ).

Sia chiaro però che questo ragionamento vale sempre per quei workload tipici. Cioè se impili i lego in un certo ordine, avrai una macchina molto veloce a svolgere il task A, ma magari lentissima nello svolgere il task B. Se li impili in un altro ordine, la situazione cambierà. Ma se B è un task che compare nello 0.001% dei casi reali ( che poi può anche significare che nel corso di una sessione di lavoro il task B occupa lo 0.001% del tempo di computing del macrotask di cui fa parte ), allora la prima soluzione può essere migliore della seconda.

LMCH
01-12-2020, 17:59
Guarda che ormai da 20 anni in qua i processori e l'ISA sono praticamente separati ;)
Non dico che puoi prendere qualsiasi processore, sostituirgli il decoder istruzioni con un' altra ISA e farlo andare uguale, ma non manca tanto ( oddio, nel caso di Transmeta l' ISA in teoria si poteva programmare al volo )
E oltretutto le prestazioni migliori le ottieni con le estensioni dedicate, che son tutta roba nuova.

Il set d'istruzioni e l'architettura che lo esegue sono separati ... ma si influenzano reciprocamente in un sacco di modi che uno non si aspetta.

Ad esempio il decoder da istruzioni visibili al programmatore a microOp/macroOp eseguite internamente diventa un problema se crea dei colli di bottiglia riguardo il numero di istruzioni riordinabili e/o eseguibili in parallelo.

E non è che l'M1 abbia un decoder da 8 istruzioni per ciclo contro le 4..5 degli x86-64 più recenti perchè è implementato a 5nm TSMC contro i 7nm TSMC dei Ryzen di AMD ed i 10nm Intel.

I core Arm usati da Apple avevano già un decoder da 6 istruzioni per ciclo nel 2013 (core Cyclone, 28nm), salito a 7 nel 2017 (core Monsoon, 10nm) e poi ad 8 nel 2019 (core Lightning, 7nm).

Il motivo per cui i core Apple sono così è che il rapporto costo/benefici è a favore di decoder più ampi perchè si riesce ad estrarre un maggior numero di istruzioni senza troppe interdipendenze rispetto allo stesso codice compilato per x86-64 (i 16 registri interi in più e le istruzioni più semplici da decodificare velocemente aiutano parecchio) e questo poi ha conseguenze anche sul numero di buffer di riordino ed altre cose a valle del decoder.

Sp3cialFx
01-12-2020, 18:20
...

O tiri fuori numeri / fonti a suffragio delle tue tesi, o non vieni a dire né che il traduttore implementato in HW è meno performante di un traduttore implementato in SW come Rosetta. Fa la stessa cosa in tempo reale. Se fosse meno performante ovviamente lo implementeresti lato SW. Le CPU x86 hanno visto un sacco di modalità in cui potevano esser messe, potresti fare la modalità "native microcode". Il microcode lo generi a livello di OS con l'equivalente di Rosetta fatto direttamente da Intel / AMD.

Cmq Cfranco dice che l'efficienza è 96/97%. Uno dei due ha torto.


Cfranco: in realtà oltre al nodo produttivo (che poi Intel è al palo ma AMD è comunque ai 7nm) c'è un altro aspetto che nessuno rileva: il numero di transistor. Paradossalmente il gigante tra i "grossi" x86 e il "leggero e agile" M1 è quest'ultimo. Poi si, non sono tutti dedicati alla CPU ma comunque da quello che sembra tra un quarto e un terzo del totale si... comunque un numero molto elevato.

LMCH: scusa ma perché non riordinano le microop al posto del codice x86? Su un M1 con Rosetta il riordino avviene ovviamente dopo aver tradotto il linguaggio macchina x86 in linguaggio macchina ARM. Immagino sarebbe anche più facile... probabilmente non dà gli stessi risultati, anche perché 5 istruzioni x86 non sono 5 istruzioni ARM.

TheAlchemyst
01-12-2020, 20:07
Scusate la domanda da non programmatore, ma se si ha una architettura diversa (x86, arm, questa nuova), il problema per avere dei programmi che vi girano non sta soprattutto nel supporto da parte del compilatore? Cioè, se io ho il sorgente di un programma, il porting su un architettura diversa non dipende solamente dal fatto che uso un compilatore che sa tradurre in linguaggio macchina specifico per quell'architettura? Ovviamente se il programma necessità di set di istruzioni che non sono presenti in quella specifica CPU il discorso cambia, bisogno modificare il sorgente. O sbaglio?

Cfranco
01-12-2020, 20:26
Cmq Cfranco dice che l'efficienza è 96/97%. Uno dei due ha torto.


Questa era la situazione nel 1998 ( Pentium II )
The microcode engines on current CPUs are about 95% as fast as direct execution
https://archive.arstechnica.com/cpu/4q99/risc-cisc/rvc-3.html#Microcode

Presumo che in 20 anni siano riusciti a migliorare ancora qualcosina :O

LMCH
02-12-2020, 01:05
Qualcuno ha maggiori info sulla 2da generazione di tale processore?

https://arstechnica.com/science/2019/08/16-bit-risc-v-processor-made-with-carbon-nanutubes/

L' RV16X-NANO non era un "vero" Risc-V (nel senso che rispettava le specifiche delle cpu Risc-V). Era una cpu con ISA "derivata" da RV32I in cui registri ed indirizzi venivano ridotti a 16bit.
Serviva solo per dimostrare che era possibile implementare con i nanotubi anche delle cpu "moderne".

pabloski
02-12-2020, 09:47
O tiri fuori numeri / fonti a suffragio delle tue tesi, o non vieni a dire né che il traduttore implementato in HW è meno performante di un traduttore implementato in SW come Rosetta.


E dalle...no, non ho numeri da mostrare. Ma già stai sbagliando, perchè nelle CPU non c'è nessun traduttore hardware che traduce al volo dall'ISA esterna a quella interna della CPU. Ripeto che si tratta di (1) un decoder che implementa tanti circuiti, ognuno attivato da un certa istruzione/un certo set d'istruzioni dell'ISA esterna, (2) una rom con dentro delle subroutine scritte nel linguaggio macchina della CPU sottostante per alcune istruzioni dell'ISA esterna. E' totalmente diversa da come funziona un traduttore binario software.

E ribadisco che non c'è una cache, in cui mettere il codice nativo tradotto per poter riutilizzare.


Fa la stessa cosa in tempo reale.


Definisci tempo reale in questo contesto.


Se fosse meno performante ovviamente lo implementeresti lato SW.


Implementi il microcodice via software? Dando via i segreti industriali nascosti nel tuo design hardware? Geniale!


Le CPU x86 hanno visto un sacco di modalità in cui potevano esser messe, potresti fare la modalità "native microcode".


Come se il bloating non mancasse nel mondo x86. Please...


Il microcode lo generi a livello di OS con l'equivalente di Rosetta fatto direttamente da Intel / AMD.

Tutto disaccoppiato dalla CPU e portato su ogni singolo OS da supportare....e gli altri OS fanno la birra? Semplicemente non possono usare la CPU? :doh:


Cmq Cfranco dice che l'efficienza è 96/97%. Uno dei due ha torto.


Pure l'efficienza di un traduttore binario software si attesta su quei livelli. Parliamo comunque di un 80% e più nel caso medio. Poi ci sono i benchmark sintetici, dove puoi sfruttare il caching a manetta e arrivi vicinissmo al 100%.

E poi c'è tutto il discorso sulla parte hardware, che ho fatto sopra, che ti fa capire perchè ha senso usare qualcos'altro ( magari realizzato ex novo ) rispetto a x86 o anche ARM, che pure ha il suo legacy.

Si parlava di RISC-V e di come potrebbe fare le scarpe pure ad ARM. Ed è possibilissimo. E non è semplicemente una questione di microdice, ma di quanti transistor puoi liberare, non dovendo supportare funzionalità legacy.

Esempio banale: se ritornassimo indietro, levassimo il microcodice, e progammassimo direttamente nel linguaggio macchina della CPU, avremmo un miglioramento? Si, perchè avremmo meno transistor/li potrebbe usare per implementare ulteriori unità funzionali, utili a scopi pratici.

Sp3cialFx
02-12-2020, 10:51
paboloski, te l'ho detto nell'ultimo post in modo un po' aggressivo con la speranza di farti capire che non mi interessano le opinioni o la visione personale secondo quanto si ha capito;
se hai riferimenti da leggere benissimo, altrimenti delle chiacchiere faccio poco.

Il punto di fondo è: Intel e AMD sono nel settore da 40 anni. ARM da poco meno. Arriva Apple che ha un botto di know how ma non nelle CPU (ha fatto due acquisizioni di aziende che definirei piccole) e fa l'M1 (*). Ora arriva pinco pallino e dice che la sua CPU va n volte di più dell'M1.

C'è qualcosa che non torna, e di chiacchiere a riguardo ne ho lette già abbastanza, vorrei qualche argomento consistente ma soprattutto verificabile / comprovabile.

(*) ricordo che M1 è un ARM ma va il doppio degli altri ARM. E l'ultima volta che ho controllato gli altri ARM non usano una ISA x86 ma usano un'ISA ARM :P

Il fatto che l'M1 sia avanti di un nodo nel processo produttivo sicuramente aiuta ma non è sufficiente a chiudere la questione.

pabloski
02-12-2020, 11:54
C'è qualcosa che non torna, e di chiacchiere a riguardo ne ho lette già abbastanza, vorrei qualche argomento consistente ma soprattutto verificabile / comprovabile.


L'unica possibilità allora è andarti a studiare l'architettura proposta da quest'azienda. Solo così potrai vedere se e dove hanno eliminato colli di bottiglia e come. E capire in quali casi ( perchè ripeto che un design può essere più performante su certi task e meno su altri rispetto ad un concorrente, per cui non esiste il migliore in assoluto ) riesce a rendere.


(*) ricordo che M1 è un ARM ma va il doppio degli altri ARM.


Ecco. Questo è uno dei punti da chiarire. M1 e tutti i SoC Apple NON SONO ARM!! Implementano l'ISA ARM, ma i design hardware sono totalmente diversi e molto probabilmente ( e ripeto, si può solo supporre, perchè è roba protetta da segreto industriale ) si tratta di chip Power o Power-like, dato che gli ingegneri della PA Semi lavorano su chip Power.



Il fatto che l'M1 sia avanti di un nodo nel processo produttivo sicuramente aiuta ma non è sufficiente a chiudere la questione.

No, non lo è. Per esempio, stamattina leggevo alcune speculazioni sul fatto che la traduzione binaria non sarebbe realizzata solo in software da Rosetta, ma avrebbe il supporto di un'unità hardware specializzata nel SoC.

Quello che si sa per certo, è che i SoC Apple hanno delle pipeline estremamente ampie e sono aggressivamente superscalari, cosa strana per il mondo ARM tradizionale. E potrebbe essere dei design clockless, dato che proprio ARM ci aveva lavorato in passato per tentate di abbattere i consumi elettrici.

amd-novello
02-12-2020, 12:41
quando dici chip power intendi che hanno a che fare con i power-pc?

Pino90
02-12-2020, 13:08
Il punto di fondo è: Intel e AMD sono nel settore da 40 anni. ARM da poco meno. Arriva Apple che ha un botto di know how ma non nelle CPU (ha fatto due acquisizioni di aziende che definirei piccole) e fa l'M1 (*). Ora arriva pinco pallino e dice che la sua CPU va n volte di più dell'M1.

Infatti non sono 12 anni che Apple produce chip compatibili ARM ad altissime prestazioni. Assolutamente.

Se poi vogliamo dirla tutta, l'ISA non è nemmeno ARM ma AARCH64. Apple ha creato un processore compatibile con ISA AARCH64 ma con un design completamente diverso dai reference di ARM e dalle customizzazioni di Qualcomm e Samsung.

Sono 12 anni che i loro processori vanno molto di più di tutti gli altri compatibili ARM, solo che adesso la gente come te si è svegliata e non ci crede perché non se ne è resa conto.

Per verificare quello che dico puoi tranquillamente leggerti i benchmark degli ultimi 12 anni di tutti i top di gamma Apple, sono sicuro che ce ne siano una marea.

LMCH
02-12-2020, 13:09
LMCH: scusa ma perché non riordinano le microop al posto del codice x86? Su un M1 con Rosetta il riordino avviene ovviamente dopo aver tradotto il linguaggio macchina x86 in linguaggio macchina ARM. Immagino sarebbe anche più facile... probabilmente non dà gli stessi risultati, anche perché 5 istruzioni x86 non sono 5 istruzioni ARM.

Il programmatore o il compilatore/traduttore al massimo possono sequenziare le istruzioni dell'ISA in modo da dare più dritte che possono al decoder ed allo scheduler delle microOP riguardo cosa si può eseguire in parallelo.

Le microOp sono già ridotte ai minimi termini per quella particolare architettura e sarebbe praticamente inutile tentare di "ri-ottimizzarle"
(semmai meglio avere più buffer di riordino in modo da poter "tenere in sospeso" un maggior numero di istruzioni con interdipendenze da risolvere mentre magari si esegue codice che viene dopo di loro nella sequenza di decodifica ma che non ha dipendenze con le microOp "in attesa").

Riguardo istruzioni x86-64 ed istruzioni AArch64, la densità del codice ed il numero di microOp generate da una singola istruzione dell'ISA, da soli non sono un buon indicatore delle prestazioni.

Gli x86-64 hanno si istruzioni più "complesse" espandibili in un maggior numero di microOp, ma sono anche sequenze di microOp con interdipendenze che vanno riorganizzate a carico di decoder e scheduler invece che a più alto livello (ed in modo più efficiente) dal compilatore o dal programmatore.

Dall'altro lato, se si usano le istruzioni "semplici" degli x86-64, poi si scopre che servono più istruzioni "semplici" x86-64 per fare quello in cui magari basta una singola istruzione "semplice" di AArch64.

Ed infine c'e' il problema del numero di registri interi, x86-64 ha 16 registri interi a 64bit, quando arrivi ad usarli tutti si finisce con il dove accedere a variabili in memoria esterna, con istruzioni più lunghe e con aumento della pressione sulle unità di load/store.

Gli x86-64 più recenti hanno un sacco di ottimizzazioni interne per rendere più performante l'uso ripetuto della stessa variabile in memoria senza dover passare manco per la cache (per dirla in modo molto grossolano ed approssimativo, tengono il valore nel buffer di riordino e lo recuperano da li o dalla coda di scrittura verso la memoria se un istruzione successiva legge/scrive la stessa locazione), ma questo comunque forza ad usare istruzioni più lunghe (riducendo la densità del codice e riducendo il numero di altre istruzioni decodificabili nello stesso ciclo).

Invece un ARM Aarch64 o un Risc-V (a 32 o a 64 bit) quando un x86-64 deve cominciare a referenziare la memoria, hanno ancora altri 15 registri interi liberi che il programmatore/compilatore può utilizzare per tenere valori temporanei, puntatori, valori riutilizzabili in istruzioni successive, ecc. ed usando istruzioni "semplici" a tutto vantaggio della semplicità del decoder (quindi più facile da "allargare" per decodificare più istruzioni contemporaneamente) e del parallelismo interno in fase di esecuzione.

Ripeto, non è un caso se gli Arm di Apple già a 28nm decodificavano 6 istruzioni per ciclo, mentre gli x86-64 non vanno oltre le 4..6 istruzioni neanche ora che sono implementati a 10nm .. 7nm
(es: lo Zen3 in condizioni ottimali decodifica fino a 4 istruzioni x86-64 "semplici" per ciclo e fino ad 8 microOP per ciclo già predecodificate nella uOp Cache, ma invia in esecuzione allo scheduler solo 6 micro-op per ciclo tra i potenzialmente 12 candidati all'esecuzione, da cui la stima di "4..5 istruzioni x86 per ciclo" in condizioni ottimali).

Notare anche che, al momento solo Apple si è spinta a simili livelli di ampiezza del decoder istruzioni, i core di ARM Ltd. non sono così spinti perchè li si è scelto di privilegiare lo sviluppo delle istruzioni SVE2 in modo da rendere più semplice ai produttori su licenza la possibilità di "regolare il livello di prestazioni" cambiando l'ampiezza delle unità SVE.

cronos1990
02-12-2020, 13:59
Solo chi ha la palla di cristallo ha certezzeNo, ha solo una palla di cristallo :asd:

LMCH
02-12-2020, 14:02
L'unica caratteristica che smuove le acque e' l'isa open... ma la domanda su compatibilita' fra diversi fornitori, e fra versioni, e' una bella domanda.
Ricordiamo Linux agli inizi che molti programmi per una distro per farli funziare su di un'altra era dura?
Non e' che ti fai tutto un progetto miliardario e poi il chip nuovo non e' compatibile.

Solo chi ha la palla di cristallo ha certezze

Per ora il rischio frammentazione non c'e', le specifiche sono molto chiare e la RISC-V International Association si sta attrezzando per limitare ulteriormente i rischi di frammentazione.

Le specifiche Risc-V prevedono pure un blocco di opcode "standard" da utilizzare per estensioni custom, in questo modo i vari produttori possono aggiungere loro estensioni speciali/sperimentali senza andare ad interferire con lo standard e le sue future estensioni.

A parte questo, sarei curioso di capire cosa hanno DAVVERO realizzato quelli di Micro Magic.
Non basta dire "Risc-V a 64bit che funziona a 5GHz", perchè c'e' molta roba differente che corrisponde ad una descrizione simile.

Questo perchè "Risc-V" è una famiglia di set di istruzioni, mica solo uno, senza contare tutte le differenti implementazioni architetturali che già esistono.

Ad esempio, se hanno implementato un RV64I (la versione "minima" di un Risc-V a 64bit) con un architettura scalare inorder con pipeline lunghissima non è che sia così impressionante, mentre invece se si parla di un RV64GC superscalare la cosa è decisamente più interessante.

In linea generale i Risc-V sono molto promettenti, hanno le loro particolarità ma sono pensati bene e sopratutto sono estendibili in modo retrocompatibile senza dover fare salti mortali assurdi, ma per ora quelli "già pronti" sono gli RV32IMAC .. RV32IMAFC ... RV32GC da usare nella fascia embedded attualmente dominata dagli ARM Cortex M3/M4.

pabloski
02-12-2020, 16:25
quando dici chip power intendi che hanno a che fare con i power-pc?

Si, i PowerPC erano versioni castrate dei Power di IBM. P.A. Semi implementava SoC embedded basati sulle architetture Power.

pabloski
02-12-2020, 16:30
L'unica caratteristica che smuove le acque e' l'isa open... ma la domanda su compatibilita' fra diversi fornitori, e fra versioni, e' una bella domanda.
Ricordiamo Linux agli inizi che molti programmi per una distro per farli funziare su di un'altra era dura?
Non e' che ti fai tutto un progetto miliardario e poi il chip nuovo non e' compatibile.


E' un problema noto e l'hanno affrontato. E la soluzione è questa https://www.cnx-software.com/2019/08/27/risc-v-bases-and-extensions-explained/

Qualcuno noterà la somiglianza col modello di sviluppo di OpenGL. E con OpenGL le cose hanno funzionato alla grande.

Sp3cialFx
03-12-2020, 19:50
pabloski: apprezzo l'entusiasmo ma ho passato già quella fase e ora mi limito a interessarmi ai fatti comprovabili. Perdonami ma non hai scritto mezza ceretzza, solo tante belle ipotesi di cui personalmente me ne faccio poco

Pino90: un conto è andare più degli altri ARM, un conto è andare più di un x86

LMCH: il senso della mia provocazione è: ma se un M1 + Rosetta 2 va meglio di un x86 e consuma pure meno, perché al posto che usare soluzioni che vengono presunte come incasinate e poco performanti come il decoder ISA x86 -> microOp HW non si fa dei core come diavolo si preferisce (l'importante dopotutto è solo che vada tanto e consumi poco) che tanto poi ci pensa l'equivalente di Rosetta 2 a occuparsi di mantenere la compatibilità con l'ISA x86?

Poi non ho capito la questione 16 registri x86 / 16 registri ARM, se mi fai esempi con qualche istruzione assembler credo mi sia più chiaro.

Così come non ho capito quando parli delle ottimizzazioni, sembra quasi che siano uno svantaggio perché si allungano le istruzioni, ovviamente avranno verificato che un vantaggio c'è, non credo si divertano a complicare le cose per peggiorare i risultati :)

Cfranco
03-12-2020, 20:41
LMCH: il senso della mia provocazione è: ma se un M1 + Rosetta 2 va meglio di un x86 e consuma pure meno, perché al posto che usare soluzioni che vengono presunte come incasinate e poco performanti come il decoder ISA x86 -> microOp HW non si fa dei core come diavolo si preferisce (l'importante dopotutto è solo che vada tanto e consumi poco) che tanto poi ci pensa l'equivalente di Rosetta 2 a occuparsi di mantenere la compatibilità con l'ISA x86?

M1 12 miliardi di transistor a 5 nm
Ice lake-Y 7 miliardi di transistor a 10 nm

M1 è enormemente più grosso, complesso e incasinato di un i7, forse qualcuno pensa che essendo un ARM sia più semplice di un X86, ma l'epoca dei RISC "snelli" contro i CISC "ciccioni" è finita più di 20 anni fa, adesso la gara è tra pesi massimi, le cpu snelle vanno giusto bene per processori embedded a bassissimo consumo, ma quando esci dai tre bench sintetici dove sembrano dei fenomeni e cominci a lavorarci sopra sul serio cominciano ad arrancare di brutto.

Pino90
04-12-2020, 08:16
M1 12 miliardi di transistor a 5 nm
Ice lake-Y 7 miliardi di transistor a 10 nm

M1 è enormemente più grosso, complesso e incasinato di un i7, forse qualcuno pensa che essendo un ARM sia più semplice di un X86, ma l'epoca dei RISC "snelli" contro i CISC "ciccioni" è finita più di 20 anni fa, adesso la gara è tra pesi massimi, le cpu snelle vanno giusto bene per processori embedded a bassissimo consumo, ma quando esci dai tre bench sintetici dove sembrano dei fenomeni e cominci a lavorarci sopra sul serio cominciano ad arrancare di brutto.

Conoscendo la smania di Apple per la bellezza e l'ordine sicuramente sará il processore meno incasinato della storia di sempre! :sofico:

pabloski
04-12-2020, 09:48
pabloski: apprezzo l'entusiasmo ma ho passato già quella fase e ora mi limito a interessarmi ai fatti comprovabili. Perdonami ma non hai scritto mezza ceretzza, solo tante belle ipotesi di cui personalmente me ne faccio poco


No, ti ho detto cosa la teoria ci porta a concludere. Per i dettagli implementativi, sono noti solo alle aziende coinvolte e sono protetti dal segreto industriale.

Pino90: un conto è andare più degli altri ARM, un conto è andare più di un x86


ma se un M1 + Rosetta 2 va meglio di un x86 e consuma pure meno, perché al posto che usare soluzioni che vengono presunte come incasinate e poco performanti come il decoder ISA x86 -> microOp HW non si fa dei core come diavolo si preferisce (l'importante dopotutto è solo che vada tanto e consumi poco) che tanto poi ci pensa l'equivalente di Rosetta 2 a occuparsi di mantenere la compatibilità con l'ISA x86?


Faccio pure io una provocazione, anzi una domanda. Secondo te, è più facile la vita di un decoder che si occupa di decodificare le istruzioni di un'ISA a lunghezza fissa o di uno che si occupa di un'ISA le cui istruzioni sono a lunghezza variabile?

E quali impatto può avere tutto ciò sulla fase di fetching e sul caching ?


Poi non ho capito la questione 16 registri x86 / 16 registri ARM, se mi fai esempi con qualche istruzione assembler credo mi sia più chiaro.

I registri sono spazio di memorizzazione. Più registri = più roba che si può tenere vicino al processore = meno accessi in memoria/cache. Non è un caso se un'architettura creata per le prestazioni ( Power ) abbia una marea di registri.

The_misterious
04-12-2020, 09:49
M1 12 miliardi di transistor a 5 nm
Ice lake-Y 7 miliardi di transistor a 10 nm

M1 è enormemente più grosso, complesso e incasinato di un i7, forse qualcuno pensa che essendo un ARM sia più semplice di un X86, ma l'epoca dei RISC "snelli" contro i CISC "ciccioni" è finita più di 20 anni fa, adesso la gara è tra pesi massimi, le cpu snelle vanno giusto bene per processori embedded a bassissimo consumo, ma quando esci dai tre bench sintetici dove sembrano dei fenomeni e cominci a lavorarci sopra sul serio cominciano ad arrancare di brutto.

Sono un niubbo in queste cose, ma da quello che ho capito in M1 è integrata la GPU, l'SSD, la RAM ecc...
quindi non è tanto confrontabile il numero totale di transitor

pabloski
04-12-2020, 09:50
M1 12 miliardi di transistor a 5 nm
Ice lake-Y 7 miliardi di transistor a 10 nm

M1 è enormemente più grosso, complesso e incasinato di un i7, forse qualcuno pensa che essendo un ARM sia più semplice di un X86, ma l'epoca dei RISC "snelli" contro i CISC "ciccioni" è finita più di 20 anni fa, adesso la gara è tra pesi massimi, le cpu snelle vanno giusto bene per processori embedded a bassissimo consumo, ma quando esci dai tre bench sintetici dove sembrano dei fenomeni e cominci a lavorarci sopra sul serio cominciano ad arrancare di brutto.

Il concetto di CISC e RISC è riferito all'ISA, non al design hardware. Poi, il numero di transistor non implica maggiore complessità dell'unità di controllo. Il M1 ha dentro un sacco di acceleratori hardware, tra cui uno appositamente creato per accelerare le reti neurali. E quello è fatto di transistor.

digieffe
05-12-2020, 23:53
Ripeto che si tratta di (1) un decoder che implementa tanti circuiti, ognuno attivato da un certa istruzione/un certo set d'istruzioni dell'ISA esterna, (2) una rom con dentro delle subroutine scritte nel linguaggio macchina della CPU sottostante per alcune istruzioni dell'ISA esterna. E' totalmente diversa da come funziona un traduttore binario software.

E ribadisco che non c'è una cache, in cui mettere il codice nativo tradotto per poter riutilizzare.

la cache L0 di 4k mops di Zen3 o l'equivalente del prox intel (11xxx) di 2.25k non servono proprio a contenere le sequenze di microistruzioni già decodificate?

AlexSwitch
06-12-2020, 09:03
Sono un niubbo in queste cose, ma da quello che ho capito in M1 è integrata la GPU, l'SSD, la RAM ecc...
quindi non è tanto confrontabile il numero totale di transitor

In M1 le Ram LPDDR4X sono esterne al SoC anche se montate sullo stesso package; i chip dell'unità SSD sono saldati sulla scheda madre così come la circuiteria per l'I/O e il wireless.
Nel die monolitico del SoC sono comprese CPU, GPU, Neural Processing Unit di nuova generazione, l'Image Signal Processor per il video e il Secure Enclave, alias T2 chip, per le funzioni di sicurezza e di controller per l'SSD.

AlexSwitch
06-12-2020, 09:29
M1 12 miliardi di transistor a 5 nm
Ice lake-Y 7 miliardi di transistor a 10 nm

M1 è enormemente più grosso, complesso e incasinato di un i7, forse qualcuno pensa che essendo un ARM sia più semplice di un X86, ma l'epoca dei RISC "snelli" contro i CISC "ciccioni" è finita più di 20 anni fa, adesso la gara è tra pesi massimi, le cpu snelle vanno giusto bene per processori embedded a bassissimo consumo, ma quando esci dai tre bench sintetici dove sembrano dei fenomeni e cominci a lavorarci sopra sul serio cominciano ad arrancare di brutto.

Ti ricordo che M1 è un SoC e non una semplice CPU... I core CPU di M1 sono in configurazione 4+4 ed ogni cluster, chiamiamolo così, ha il suo corredo di cache che per i core Firestorm ad alta potenza di calcolo raggiunge il ragguardevole valore di 12 Mb per la L2.
A tutto ciò andrebbe aggiunta la SLC, System Level Cache, sfruttata anche dai cores della CPU.
Ecco spiegati così tanti transistor per la componente CPU di M1.

386DX40
06-12-2020, 10:31
...
Anzi in alcuni casi Windows richiede istruzioni che non sono incluse nel set "generic" x86_64.

Gli Intel x86 32 bit non fanno molto testo ormai, ma anche in quel caso mi sembra di ricordare che Windows richieda almeno il supporto SSE2 (cosa già inclusa di default in x86_64).
...


Credo che da un certo momento in poi (forse Win 8.x) sia richiesto qualcosa di piu' del "solo" SSE2. Provai poco tempo fa a installare Win 8.1 x86 su un Northwood P4 a 3,2Ghz (ultima cpu x86 con SSE2 e HT credo) e 2GB di ram l'installazione falliva in fase di inizio nemmeno arrivava alla schermata di installazione con un messaggio di errore complesso ma che pareva molto una incompatibilità dovuta proprio alla cpu. Comunque purtroppo l' i386 anche su linux stà vedendo i suoi ultimi momenti, si aggiornano i vecchi kernel ma non ne escono di nuovi nuovi.
Ovviamente e' inevitabile il rimpianto e' solo per passione di retrocomputing, ormai giusto il P4 sudetto era l'ultima cpu nativa x86 32bit commerciale che poteva dire la sua in moderni pesanti sistemi operativi. Ma da miei test ancora del tutto soddisfacente per una macchina generica da casa.

386DX40
06-12-2020, 10:36
M1 12 miliardi di transistor a 5 nm
Ice lake-Y 7 miliardi di transistor a 10 nm

M1 è enormemente più grosso, complesso e incasinato di un i7, forse qualcuno pensa che essendo un ARM sia più semplice di un X86, ma l'epoca dei RISC "snelli" contro i CISC "ciccioni" è finita più di 20 anni fa, adesso la gara è tra pesi massimi, le cpu snelle vanno giusto bene per processori embedded a bassissimo consumo, ma quando esci dai tre bench sintetici dove sembrano dei fenomeni e cominci a lavorarci sopra sul serio cominciano ad arrancare di brutto.
Ma per curiosità, questo M1 quanti watt consuma? Perche' in proporzione tra watt, processo produttivo e benchmark sintetici si dovrebbe avere una idea di massima se ci sia stato un sorpasso ormai "concettuale" in tutti gli ambiti o no.

386DX40
06-12-2020, 10:47
e' difficile a dirsi se avra' successo, del resto quando AMD sverniciava i vari pentium e Cyrix era una valida alternativa manco in un piccolo stagno si riusci a salire di quote.



Ma si intende nel periodo Athlon e Pentium III? Perchè se si intende negli anni prima, sverniciare e' forse un po' ottimistico se prendiamo come riferimento i vari core 386/486/K5/K6/K6-II.. :stordita:
Certamente valide alternative sul piano economico (il K6-2 per esempio fu un ottima cpu da desktop, molto meno nelle applicazioni intensive come nel 3D imho per la non eccessiva adozione del 3DNow! che avrebbe potuto compensare molto, senza parlare della mancanza della cache esterna fino al K6-III/ II+/III+).

pabloski
06-12-2020, 10:52
la cache L0 di 4k mops di Zen3 o l'equivalente del prox intel (11xxx) di 2.25k non servono proprio a contenere le sequenze di microistruzioni già decodificate?

Dipende a cosa ti riferisci. Questo termine gira da un decennio con vari significati. Ho dato uno sguardo ai manuali Intel giusto per sicurezza, ma nemmeno viene nominato una cache L0.

Altre fonti ne parlano come di un'ulteriore cache prima della L1, con lo scopo di ridurre i consumi.

Altre ancora usano questo termine per riferirsi al register file. Che però contiene i registri generali e ( in alcune famiglie di CPU ) il program counter e lo status register ( i flag ). Ma non mi risulta che l'instruction register sia contenuto nel file.

E comunque è una tecnica diffusa pure nel mondo ARM e in altre famiglie di CPU moderne. Non è un'esclusiva x86.

pabloski
06-12-2020, 10:55
Ma per curiosità, questo M1 quanti watt consuma?


15W. Ed è questo il bello. Si tratta del SoC col miglior rapporto mips/watt.


Perche' in proporzione tra watt, processo produttivo e benchmark sintetici si dovrebbe avere una idea di massima se ci sia stato un sorpasso ormai "concettuale" in tutti gli ambiti o no.

Personalmente preferisco i numeri delle prestazioni rilevate nell'uso con programmi reali. I bench sintetici non sono in grado di offrire una misura onnicomprensiva. Cioè, un Chrome che ti spara le pagine a manetta, renderizza come un matto, esegue codice JS alla velocità della luce, è molto più utile di un bench sintetico.

386DX40
06-12-2020, 12:00
15W. Ed è questo il bello. Si tratta del SoC col miglior rapporto mips/watt.



Personalmente preferisco i numeri delle prestazioni rilevate nell'uso con programmi reali. I bench sintetici non sono in grado di offrire una misura onnicomprensiva. Cioè, un Chrome che ti spara le pagine a manetta, renderizza come un matto, esegue codice JS alla velocità della luce, è molto più utile di un bench sintetico.

15W e' quindi il massimo consumo? Sono stati fatti bench sintetici e non, per confrontarlo con qualche processore x64?

pabloski
06-12-2020, 12:28
15W e' quindi il massimo consumo? Sono stati fatti bench sintetici e non, per confrontarlo con qualche processore x64?

15W è il TDP. Del resto da quando il TDP è il consumo massimo? Proprio Intel ha avviato la pratica di fregarci col TDP.

Considera però che il M1 va negli Air, per cui se non sarà 15W, sicuramente più di 20-25W non supera.

AlexSwitch
06-12-2020, 14:12
15W è il TDP. Del resto da quando il TDP è il consumo massimo? Proprio Intel ha avviato la pratica di fregarci col TDP.

Considera però che il M1 va negli Air, per cui se non sarà 15W, sicuramente più di 20-25W non supera.

I 15W di consumo massimo si riferiscono solamente alla CPU ( 13,8W per i core performance e 1.3W per i core a basso consumo ).
In totale il consumo del SoC M1, nella versione più veloce usata nel Mac Mini e secondo le prove empiriche di Anandtech, raggiunge un picco di potenza attiva di 26.8W in multithread su tutti gli 8 core.
La GPU ha raggiunto una potenza di 17.3W.

In un utilizzo reale, dove GPU e/o acceleratori intervengono al posto della CPU o ne sgravano di parecchio il carico di calcolo, M1 non dovrebbe superare i 38W di picco.

I dati della potenza assorbita sono stati rilevati direttamente da Anandtech " alla presa " di corrente, con un idle di 4.2W.

cdimauro
13-12-2020, 08:17
Guarda che ormai da 20 anni in qua i processori e l'ISA sono praticamente separati ;)
Diciamo micro-architettura e ISA per fare chiarezza, ma no: non sono affatto separati. Vedi sotto.
Non dico che puoi prendere qualsiasi processore, sostituirgli il decoder istruzioni con un' altra ISA e farlo andare uguale, ma non manca tanto ( oddio, nel caso di Transmeta l' ISA in teoria si poteva programmare al volo )
Infatti l'ISA di Transmeta aveva diversi elementi dell'ISA x86 (paginazione della memoria et similia in primis, se non ricordo male), altrimenti avrebbe avuto prestazioni ancora più scarsa.

In generale non puoi avere una micro-architettura completamente slegata dall'ISA. Se t'interessano le prestazioni, ovviamente.
E oltretutto le prestazioni migliori le ottieni con le estensioni dedicate, che son tutta roba nuova.
Sì, fanno certamente la parte del leone, ma si può fare molto anche a livello di ISA general-purpose.

Infatti ci sono benchmark in cui le scelte troppo semplicistiche di RISC-V hanno mostrato il fianco.
Un esempio è la presenza di una sola modalità d'indirizzamento verso la memoria (Registro base + piccolo offset), che pone non pochi problemi da questo punto di vista.
Problemi che a cui hanno cercato in parte di rimediare introducendo il merging di due istruzioni compatte, e dunque richiedendo sia l'estensione C/Compatta sia la modifica del frontend del processore per intercettare questi pattern e generare un'apposita istruzione interna che fa il lavoro (e quindi una modifica anche del backend).
Questo succede quando si fanno scelte miopi, andando a cercare la "purezza" a livello accademico, e dimenticandosi di come vadano le cose nel mondo reale...
Facciamo finta che siamo nel 2020 e non nel 1990.
Parlare di "ISA x86" come se fosse un vincolo non ha senso perché ormai è 25 anni che le cpu x86 usano il microcode; in altre parole l'ISA x86 non ha corrispondenza nel silicio. Gli x86 sono core RISC con una piccolissima fetta di silicio dedicata alla traduzione tra ISA x86 al microcode.
Non è affatto così: sia il backend sia il frontend dei processori x86/x64 sono (ovviamente) strettamente legati a queste ISA.

Il fatto che internamente ci sia un backend RISC è soltanto un dettaglio implementativo, e in ogni caso tale backend è legato all'ISA, per l'appunto. E non potrebbe essere altrimenti, se l'obiettivo è di avere prestazioni elevate.
Ora, se l'M1 di turno EMULANDO VIA SW un x86 gira al 80/85% del nativo, darei per scontato che il traduttore hardware ISA x86 -> microcode che è integrato nelle CPU x86 possa andare anche oltre.
Stai confrontando due cose completamente diverse.

Rosetta emula soltanto lo user-mode di x86/x64, e nemmeno tutto (e no: non mi riferisco soltanto alle istruzioni mancanti. Vedi sotto).

Un processore x86/x64 deve implementare & eseguire invece TUTTO: dall'hypervisor fino agli "anelli di protezione" (ring mode), passando per la segmentazione e la paginazione.

Se Rosetta dovesse emulare TUTTO ciò che è specificato nell'ISA x86/x64 andrebbe a manovella. Provate a realizzare un emulatore x86/x64 pienamente compatibile con tutte le specifiche dell'ISA, e lo vedrete voi stessi come andranno poi le prestazioni, anche girando sui futuri M10 di Apple...

Comunque non è quello lo scopo di Rosetta, e per quello che fa va benissimo così.
Fatta tutta questa lunga premessa la mia domanda è:
con le risorse / esperienza di Intel e AMD, e con la possibilità che hanno gli x86 di avere sotto il cofano qualsiasi tipo di core piaccia loro, com'è che Apple tira fuori M1, questi tirano fuori un RISC-V, domani arriva Qualcomm con gli 865 e rimangono al palo?
La mia risposta la trovi proprio qui sopra.
Disclaimer: gradirei risposte TECNICHE per capire qual è il tassello che mi manca, di chiacchiera da bar ne ho già letta a sufficienza quindi i pipponi su innovazione / ISA x86 / memoria unificata e bla bla anche no grazie
Spero che la mia breve risposta sia stata sufficiente ad appagare la tua curiosità.
E c'è la questione di quanta incide il legacy. Cioè tu hai transistor che sono presenti solo perchè ci sono funzionalità legacy da mantenere. Questi transistor sono attivi, consumano corrente. Ciò può limitare la quantità di corrente che puoi dare ad altre subunità ( i processori sono oggetti fisici, attraversati da quantità di elettricità notevoli, che vanno dissipate...e la gestione dell'energia implementata nei moderni processori fa i salti mortali, aumentando/diminuendo tensioni e frequenze dinamicamente nelle varie zone del chip ) e quindi le relative prestazioni.
[...]
In soldoni, meglio bagaglio legacy ti dà (1) più libertà nella progettazione delle unità funzionali ( e se sei bravo le rendi più efficienti ), (2) meno zavorra elettronica da portarsi dietro solo per mantenere cose come la segmentazione ( che non è usata manco per sbaglio in modalità long, cioè quella x86_64 ).
Il legacy non incide molto. Ho postato un link giusto poco fa in un altro thread.

Quando lavoravo alla Intel ho avuto la possibilità di visionare dei webinar interni che analizzavano proprio queste cose, e la percentuale sia di silicio sia di consumi relativi strettamente al legacy erano basse. Non posso dire altro perché è tutta roba riservata.

Comunque ci si può arrivare lo stesso induttivamente. I complessi decoder x86/x64 sono cresciuti relativamente poco dai tempi del PentiumPro, e idem la parte legacy del backend (vecchie istruzioni, FPU x87, segmentazione, registri controllo/debug/machine, ecc.). Oggi abbiamo chip con decine di miliardi transistor: quanto pensi che possa incidere ancora quella roba sia in termini di transistor/silicio sia in termini di consumi?

Queste valutazioni le avevo già fatte in un mio vecchio articolo su Appunti Digitali, che rimane ancora attualissimo. In sintesi: più è piccolo un core x86/x64, e più incide il legacy. E' qui, in questo contesto, che i processori basati su questa vecchia ISA perdono.
Il motivo per cui i core Apple sono così è che il rapporto costo/benefici è a favore di decoder più ampi perchè si riesce ad estrarre un maggior numero di istruzioni senza troppe interdipendenze rispetto allo stesso codice compilato per x86-64 (i 16 registri interi in più e le istruzioni più semplici da decodificare velocemente aiutano parecchio) e questo poi ha conseguenze anche sul numero di buffer di riordino ed altre cose a valle del decoder.
L'M1 ha oggettivamente di gran lunga più risorse interne votate al raggiungimento di prestazioni elevate, a prescindere dal confronto con l'ISA x86/x64. Lo si può vedere anche confrontandolo con altri processori ARM di altre aziende (Qualcomm in primis): non c'è storia.

Quanto a x86/x64, essendo CISC ha, invece, minori interdipendenze rispetto ai RISC, visto che consente alla maggior parte delle istruzioni di operare direttamente con la memoria.
Anche per questo richiede meno registri, e tempo fa ho postato uno studio in cui un x64 con 12 registri aveva quasi le stesse prestazioni della versione normale con 16 registri (a fronte di una maggior pressione verso la memoria, ovviamente, ma non era nemmeno tanto).
Infine x86/x64 ha diverse modalità d'indirizzamento verso la memoria, e anche queste aiutano.
Certamente avere istruzioni a lunghezza variabile, ma soprattutto facenti uso dei famigerati prefissi (è questo il vero problema), richiede decoder di gran lunga più complessi rispetto a ARM, specialmente se il processore implementa esclusivamente l'ISA AArch64. Ecco perché Apple riesce a decodificare ben 8 istruzioni per ciclo di clock contro 4 (non 5. Nel diagramma di Skylake sono riportate 5uop: non 5 istruzioni) di Intel/AMD.
Scusate la domanda da non programmatore, ma se si ha una architettura diversa (x86, arm, questa nuova), il problema per avere dei programmi che vi girano non sta soprattutto nel supporto da parte del compilatore? Cioè, se io ho il sorgente di un programma, il porting su un architettura diversa non dipende solamente dal fatto che uso un compilatore che sa tradurre in linguaggio macchina specifico per quell'architettura? Ovviamente se il programma necessità di set di istruzioni che non sono presenti in quella specifica CPU il discorso cambia, bisogno modificare il sorgente. O sbaglio?
Visto che nessuno t'ha risposto, lo faccio io: non sbagli. E' proprio come hai detto.
E poi c'è tutto il discorso sulla parte hardware, che ho fatto sopra, che ti fa capire perchè ha senso usare qualcos'altro ( magari realizzato ex novo ) rispetto a x86 o anche ARM, che pure ha il suo legacy.
E' vero, e anche ovvio: se parti da zero e hai le mani completamente libere puoi realizzare un'ISA particolarmente efficiente.

Ma anche avendo dei vincoli importanti si possono realizzare delle ISA "migliori" / più efficienti. Un esempio è proprio l'8086, che era quasi al 100% compatibile a livello di sorgente con l'8085 (traducendo meccanicamente i sorgenti assembly di quest'ultimo in quelli 8086), ma la nuova ISA era a 16 bit e molto migliorata.
Si parlava di RISC-V e di come potrebbe fare le scarpe pure ad ARM. Ed è possibilissimo. E non è semplicemente una questione di microdice, ma di quanti transistor puoi liberare, non dovendo supportare funzionalità legacy.
Il vantaggio di RISC-V, come dicono gli stessi creatori, non è in una qualche sua intrinseca efficienza, ma per il fatto di essere open / senza licenze.

RISC-V si porta anch'essa dei problemi / errori di progettazione, e non da poco.
Esempio banale: se ritornassimo indietro, levassimo il microcodice, e progammassimo direttamente nel linguaggio macchina della CPU, avremmo un miglioramento? Si, perchè avremmo meno transistor/li potrebbe usare per implementare ulteriori unità funzionali, utili a scopi pratici.
Se ti riferisci alla programmazione diretta del processore che sta nel backend di x86/x64, allora scordatelo: oltre a essere molto più complicato da programmare, le prestazioni crollerebbero drasticamente.
Arriva Apple che ha un botto di know how ma non nelle CPU (ha fatto due acquisizioni di aziende che definirei piccole) e fa l'M1 (*)
Ma assolutamente no. Apple ha parecchia esperienza nello sviluppo di CPU/processori, anche perché s'è portata dietro delle eccellenza in questo campo.

Le due acquisizioni di cui parli saranno state pure piccole, ma estremamente importanti.
PaSemi era costituita da eccellenze, per l'appunto, e aveva sviluppato processori PowerPC a uso embedded / militare con un'elevata efficienza energetica.
Intrinsity (se non ricordo male il nome) era specializzata nell'ottimizzazione di circuiti integrati per migliorare le prestazioni (inclusi i consumi).
Dire un'eccellente combinazione, soprattutto funzionale agli scopi di Apple.
Il fatto che l'M1 sia avanti di un nodo nel processo produttivo sicuramente aiuta ma non è sufficiente a chiudere la questione.
Incide molto anche quello.
Ecco. Questo è uno dei punti da chiarire. M1 e tutti i SoC Apple NON SONO ARM!! Implementano l'ISA ARM, ma i design hardware sono totalmente diversi e molto probabilmente ( e ripeto, si può solo supporre, perchè è roba protetta da segreto industriale ) si tratta di chip Power o Power-like, dato che gli ingegneri della PA Semi lavorano su chip Power.
Assolutamente no: sono ARM. Il fatto che PASemi avesse sviluppato PowerPC non vuol dire proprio nulla.
Quello che si sa per certo, è che i SoC Apple hanno delle pipeline estremamente ampie e sono aggressivamente superscalari, cosa strana per il mondo ARM tradizionale.
Anche per x86/x64, se è per questo. Il backend di M1 è a dir poco mostruoso.
E potrebbe essere dei design clockless, dato che proprio ARM ci aveva lavorato in passato per tentate di abbattere i consumi elettrici.
No, non era quello il lavoro che faceva Intrinsity.
Riguardo istruzioni x86-64 ed istruzioni AArch64, la densità del codice ed il numero di microOp generate da una singola istruzione dell'ISA, da soli non sono un buon indicatore delle prestazioni.
Premesso che x86-64 non ha una buona densità di codice e che AArch64, pur a lunghezza fissa, si difende molto bene, invece la densità di codice è molto importante.

A riguardo c'è uno studio proprio di uno dei creatori di RISC-V, che afferma che un processore con codice del 25% più denso può usare una cache istruzioni dimezzata (sì, hai letto bene) ottenendo le stesse prestazioni (della cache). Quindi, come vedi, è MOLTO importante. E non è un caso che praticamente i produttori di processori abbiano cercato di migliorare la densità di codice, proponendo estensioni alle loro ISA, o anche ISA realizzate ad hoc.

Sul numero di micro-op generate, invece, non si può dire niente, perché dipende tutto dall'ISA e dal "lavoro utile" che fanno. E questo difficilmente si può quantizzare (magari si dovrebbe vedere il totale delle micro-op eseguite da una precisa applicazione con un preciso set di dati).
Gli x86-64 hanno si istruzioni più "complesse" espandibili in un maggior numero di microOp, ma sono anche sequenze di microOp con interdipendenze che vanno riorganizzate a carico di decoder e scheduler invece che a più alto livello (ed in modo più efficiente) dal compilatore o dal programmatore.

Dall'altro lato, se si usano le istruzioni "semplici" degli x86-64, poi si scopre che servono più istruzioni "semplici" x86-64 per fare quello in cui magari basta una singola istruzione "semplice" di AArch64.
Succede anche (e soprattutto) il contrario, come già detto prima, perché la maggior parte delle istruzioni x86/x64 possono referenziare direttamente la memoria. E questo crea meno dipendenze, rispetto ai RISC che devono ricorrere a Load + Op, con annessa dipendenza fra le due istruzioni (nonché aumento dello spazio richiesto per contenere le due istruzioni).
Ed infine c'e' il problema del numero di registri interi, x86-64 ha 16 registri interi a 64bit, quando arrivi ad usarli tutti si finisce con il dove accedere a variabili in memoria esterna, con istruzioni più lunghe e con aumento della pressione sulle unità di load/store.
Sì, ma ne servono anche molto meno per quanto detto prima e proprio qui sopra.
Gli x86-64 più recenti hanno un sacco di ottimizzazioni interne per rendere più performante l'uso ripetuto della stessa variabile in memoria senza dover passare manco per la cache (per dirla in modo molto grossolano ed approssimativo, tengono il valore nel buffer di riordino e lo recuperano da li o dalla coda di scrittura verso la memoria se un istruzione successiva legge/scrive la stessa locazione), ma questo comunque forza ad usare istruzioni più lunghe (riducendo la densità del codice e riducendo il numero di altre istruzioni decodificabili nello stesso ciclo).
E' l'esatto contrario, invece: la densità di codice migliora, invece, perché il numero di byte occupati da un'istruzione che referenzia la memoria è sempre ben più ridotto rispetto allo stesso numero di byte richiesti da ALMENO due istruzioni RISC (non solo ARM) che debbano fare la stessa cosa.
Parimenti è ridotto anche il numero di istruzioni da codificare, proprio perché x86/x64 ne decodifica una, mentre un RISC per fare lo stesso ne decodificare ALMENO due.

Qui il vantaggio di un CISC come x86/x64 è nettissimo rispetto ai RISC. Non c'è proprio storia.
Invece un ARM Aarch64 o un Risc-V (a 32 o a 64 bit) quando un x86-64 deve cominciare a referenziare la memoria, hanno ancora altri 15 registri interi liberi che il programmatore/compilatore può utilizzare per tenere valori temporanei, puntatori, valori riutilizzabili in istruzioni successive, ecc. ed usando istruzioni "semplici" a tutto vantaggio della semplicità del decoder (quindi più facile da "allargare" per decodificare più istruzioni contemporaneamente) e del parallelismo interno in fase di esecuzione.
Vedi sopra: è un vantaggio dei CISC, invece, perché non gli servono né registri addizionali né devono eseguire più istruzioni per fare la stessa cosa.

Non parliamo poi delle istruzioni in cui il risultato dell'operazione è in memoria, dove il vantaggio diventa ancora più grande, visto che in questo caso i RISC necessitano di Load + Op + Store, mentre x86/x64 fa tutto con UNA sola istruzione.

Infine, e non meno importante, ci sono istruzioni x86/x64 il cui la destinazione è la memoria e la sorgente è un valore immediato. Qui il vantaggio rispetto ai RISC si fa addirittura imbarazzante, visto che x86/x64 non spreca un solo registro e fa tutto con una sola istruzione, mentre un RISC richiede più registri (anche più di 2) e MOLTE più istruzioni (specialmente se l'immediato non è piccolo).

Non è che x86/x64 sia arrivato a prestazioni elevatissime per puro caso, eh! E l'ISA CISC ha aiutato, e parecchio.
Ripeto, non è un caso se gli Arm di Apple già a 28nm decodificavano 6 istruzioni per ciclo, mentre gli x86-64 non vanno oltre le 4..6 istruzioni neanche ora che sono implementati a 10nm .. 7nm
(es: lo Zen3 in condizioni ottimali decodifica fino a 4 istruzioni x86-64 "semplici" per ciclo e fino ad 8 microOP per ciclo già predecodificate nella uOp Cache, ma invia in esecuzione allo scheduler solo 6 micro-op per ciclo tra i potenzialmente 12 candidati all'esecuzione, da cui la stima di "4..5 istruzioni x86 per ciclo" in condizioni ottimali).
Sono sempre 4 istruzioni decodificate per Intel e AMD.
Notare anche che, al momento solo Apple si è spinta a simili livelli di ampiezza del decoder istruzioni, i core di ARM Ltd. non sono così spinti perchè li si è scelto di privilegiare lo sviluppo delle istruzioni SVE2 in modo da rendere più semplice ai produttori su licenza la possibilità di "regolare il livello di prestazioni" cambiando l'ampiezza delle unità SVE.
Le due cose non sono legate. In futuro Apple continuerà ad avere grande ampiezza dei decoder e molto probabilmente aggiungerà il supporto alle SVE/2.
Per ora il rischio frammentazione non c'e', le specifiche sono molto chiare e la RISC-V International Association si sta attrezzando per limitare ulteriormente i rischi di frammentazione.
E invece c'è eccome. Quando sono partiti con le estensioni ne avevano fissate alcune perché pensavano che andasse bene così. Poi si sono accorti (troppo tardi: ormai le estensioni erano state ratificate) e hanno iniziato a suddividere tali istruzioni in più sottoinsiemi, generando ancora più confusione.

I soliti accademici idealisti che non tengono conto della realtà...
A parte questo, sarei curioso di capire cosa hanno DAVVERO realizzato quelli di Micro Magic.
Non basta dire "Risc-V a 64bit che funziona a 5GHz", perchè c'e' molta roba differente che corrisponde ad una descrizione simile.

Questo perchè "Risc-V" è una famiglia di set di istruzioni, mica solo uno, senza contare tutte le differenti implementazioni architetturali che già esistono.

Ad esempio, se hanno implementato un RV64I (la versione "minima" di un Risc-V a 64bit) con un architettura scalare inorder con pipeline lunghissima non è che sia così impressionante, mentre invece se si parla di un RV64GC superscalare la cosa è decisamente più interessante.
Per arrivare a quelle frequenze probabilmente i core saranno in-order. Nulla di impressionante, quindi.
In linea generale i Risc-V sono molto promettenti, hanno le loro particolarità ma sono pensati bene e sopratutto sono estendibili in modo retrocompatibile senza dover fare salti mortali assurdi, ma per ora quelli "già pronti" sono gli RV32IMAC .. RV32IMAFC ... RV32GC da usare nella fascia embedded attualmente dominata dagli ARM Cortex M3/M4.
Ehm... no. Stanno pensando (se non l'hanno già fatto) di cambiare alcune parti dell'ISA in maniera non-retrocompatibile, perché si sono accorti, di nuovo, di aver fatto una stupidaggine. Ovviamente nasconderanno il tutto in un'altra nuova estensione, com'è loro abitudine ormai.
Faccio pure io una provocazione, anzi una domanda. Secondo te, è più facile la vita di un decoder che si occupa di decodificare le istruzioni di un'ISA a lunghezza fissa o di uno che si occupa di un'ISA le cui istruzioni sono a lunghezza variabile?

E quali impatto può avere tutto ciò sulla fase di fetching e sul caching ?
Te ne faccio un'altra io: quale impatto può avere un'ISA con minor densità di codice su fetching e caching? La risposta in buona parte te l'ho già fornita sopra.
I registri sono spazio di memorizzazione. Più registri = più roba che si può tenere vicino al processore = meno accessi in memoria/cache. Non è un caso se un'architettura creata per le prestazioni ( Power ) abbia una marea di registri.
E non è nemmeno un caso che POWER abbia in media prestazioni nettamente inferiori a x86/x64, che di registri ne ha molti meno...
la cache L0 di 4k mops di Zen3 o l'equivalente del prox intel (11xxx) di 2.25k non servono proprio a contenere le sequenze di microistruzioni già decodificate?
E' esattamente quello.
Dipende a cosa ti riferisci. Questo termine gira da un decennio con vari significati. Ho dato uno sguardo ai manuali Intel giusto per sicurezza, ma nemmeno viene nominato una cache L0.

Altre fonti ne parlano come di un'ulteriore cache prima della L1, con lo scopo di ridurre i consumi.

Altre ancora usano questo termine per riferirsi al register file. Che però contiene i registri generali e ( in alcune famiglie di CPU ) il program counter e lo status register ( i flag ). Ma non mi risulta che l'instruction register sia contenuto nel file.
Cerca meglio: nella documentazione di Intel questa cache L0 si chiama LSD. Ma NON è quello che pensi. :asd:
E comunque è una tecnica diffusa pure nel mondo ARM e in altre famiglie di CPU moderne. Non è un'esclusiva x86.
Beh, hanno copiato. E non è mica la prima volta che copiano soluzioni di progetti CISC (vedi anche micro-op e macro-op fusion). ;)
Personalmente preferisco i numeri delle prestazioni rilevate nell'uso con programmi reali. I bench sintetici non sono in grado di offrire una misura onnicomprensiva. Cioè, un Chrome che ti spara le pagine a manetta, renderizza come un matto, esegue codice JS alla velocità della luce, è molto più utile di un bench sintetico.
Dipende da quello che vuoi testare. I benchmark web fanno uso ANCHE della GPU per accelerare alcune operazioni.

Se vuoi testare/confrontare la sola CPU/ISA/microarchitettura ti devi rivolgere ad altri benchmark.

P.S. Scusate ma ho perso un sacco di tempo a scrivere, e non ho nessuna voglia di leggere e correggere eventuali errori. Spero che sia tutto chiaro.

386DX40
13-12-2020, 11:02
I 15W di consumo massimo si riferiscono solamente alla CPU ( 13,8W per i core performance e 1.3W per i core a basso consumo ).
In totale il consumo del SoC M1, nella versione più veloce usata nel Mac Mini e secondo le prove empiriche di Anandtech, raggiunge un picco di potenza attiva di 26.8W in multithread su tutti gli 8 core.
La GPU ha raggiunto una potenza di 17.3W.

In un utilizzo reale, dove GPU e/o acceleratori intervengono al posto della CPU o ne sgravano di parecchio il carico di calcolo, M1 non dovrebbe superare i 38W di picco.

I dati della potenza assorbita sono stati rilevati direttamente da Anandtech " alla presa " di corrente, con un idle di 4.2W.
Ecco dove immaginavo si arrivasse..;)

LMCH
14-12-2020, 23:32
L'M1 ha oggettivamente di gran lunga più risorse interne votate al raggiungimento di prestazioni elevate, a prescindere dal confronto con l'ISA x86/x64. Lo si può vedere anche confrontandolo con altri processori ARM di altre aziende (Qualcomm in primis): non c'è storia.
E può arrivare ad averne così tante perche il set d'istruzioni permette di trarne vantaggio senza dover ricorrere a contorsionisi implementativi come succede con x86-64.


Quanto a x86/x64, essendo CISC ha, invece, minori interdipendenze rispetto ai RISC, visto che consente alla maggior parte delle istruzioni di operare direttamente con la memoria.
Anche per questo richiede meno registri, e tempo fa ho postato uno studio in cui un x64 con 12 registri aveva quasi le stesse prestazioni della versione normale con 16 registri (a fronte di una maggior pressione verso la memoria, ovviamente, ma non era nemmeno tanto).
Infine x86/x64 ha diverse modalità d'indirizzamento verso la memoria, e anche queste aiutano.


Quando sento cose tipo "con 12 registri aveva quasi le stesse prestazioni" di solito lo interpreto come "ma averne 16 permette di avere prestazioni più elevate già ora e maggiori margini in futuro". :D

Allo stesso modo averne 32 è stato considerato uno sweet spot già con le tecnologie di implementazione e compilazione disponibili negli anni '90 (più di 20 anni fa), non è un caso se sia Alpha che MIPS e PowerPC siano partiti da subito con 32 registri interi e che poi anche ARM con Aarch64 abbia scelto di avere 32 registri interi a 64bit.

Se ARM a più di un decennio di distanza ha privilegiato i 32 registri rispetto ad avere da 1 a 3bit extra da usare ad esempio per ulteriori modalità di indirizzamento ed operandi letti/scritti dalla memoria mi sa che qualche motivo serio ci sia stato.


Certamente avere istruzioni a lunghezza variabile, ma soprattutto facenti uso dei famigerati prefissi (è questo il vero problema), richiede decoder di gran lunga più complessi rispetto a ARM, specialmente se il processore implementa esclusivamente l'ISA AArch64. Ecco perché Apple riesce a decodificare ben 8 istruzioni per ciclo di clock contro 4 (non 5. Nel diagramma di Skylake sono riportate 5uop: non 5 istruzioni) di Intel/AMD.

Forse ti confondi con le architetture precedenti, se non sbaglio una delle caratteristiche di Skylake è che il decoder istruzioni x86/x86-64 può decodificare simultaneamente fino a 5 istruzioni x86 "fresche" (di cui 4 "semplici" che si traducono in una singola uOP ed 1 complessa che viene scomposta in più uOP emesse in sequenza). INOLTRE se le istruzioni x86 sono già presenti in forma decodificata nell uOP cache, possono essere inviate in esecuzione fino a 6 uOP.



Premesso che x86-64 non ha una buona densità di codice e che AArch64, pur a lunghezza fissa, si difende molto bene, invece la densità di codice è molto importante.
A riguardo c'è uno studio proprio di uno dei creatori di RISC-V, che afferma che un processore con codice del 25% più denso può usare una cache istruzioni dimezzata (sì, hai letto bene) ottenendo le stesse prestazioni (della cache). Quindi, come vedi, è MOLTO importante. E non è un caso che praticamente i produttori di processori abbiano cercato di migliorare la densità di codice, proponendo estensioni alle loro ISA, o anche ISA realizzate ad hoc.

Se l'aumento della densità del codice penalizza troppo l'espressività, il guadagno che si ha a livello di dimensione della cache istruzioni viene vanificato.
Inoltre non è una cosa "vera in assoluto", dipende molto dalle latenze negli accessi a registri, cache e memoria e dalla banda di I/O, nel senso che sono cose da valutare caso per caso e con il cambiare delle opzioni implementative.


Succede anche (e soprattutto) il contrario, come già detto prima, perché la maggior parte delle istruzioni x86/x64 possono referenziare direttamente la memoria. E questo crea meno dipendenze, rispetto ai RISC che devono ricorrere a Load + Op, con annessa dipendenza fra le due istruzioni (nonché aumento dello spazio richiesto per contenere le due istruzioni).

D'altro canto, a differenza che negli x86-64, in un risc con un sufficiente numero di registri, il compilatore o il programmatore possono schedulare la load in anticipo ed hanno maggiori possibilità di riuscire ad inserire altre istruzioni da eseguire rima di arrivare all'eseguire l'operazione sul dato.
E' un vantaggio non da poco visto che agli x86 sono state aggiunte istruzioni di prefetch proprio per poter fare la stessa cosa (annullando il "vantaggio" teorico che hanno referenziando direttamente la memoria ... per avere un vantaggio concreto).


Sì, ma ne servono anche molto meno per quanto detto prima e proprio qui sopra.

Skylake: 1 istruzione complessa e 4 semplici oppure ... giù di prestazioni fino al worst case di una istruzione complessa in parziale decodifica.
M1: 8 istruzioni e giù fino a ... diciamo almeno 4 istruzioni se si usa un compilatore con attivati loop unrolling ed auto-inlining.


E' l'esatto contrario, invece: la densità di codice migliora, invece, perché il numero di byte occupati da un'istruzione che referenzia la memoria è sempre ben più ridotto rispetto allo stesso numero di byte richiesti da ALMENO due istruzioni RISC (non solo ARM) che debbano fare la stessa cosa.
Parimenti è ridotto anche il numero di istruzioni da codificare, proprio perché x86/x64 ne decodifica una, mentre un RISC per fare lo stesso ne decodificare ALMENO due.

Qui il vantaggio di un CISC come x86/x64 è nettissimo rispetto ai RISC. Non c'è proprio storia.


Ma quanto è frequente questo caso ideale per i CISC ? E quanta pressione viene fatta sulle unità di load-store ? Perchè poi se vai a saturare la capacità delle unità di load/store vanifichi tutti i potenziali vantaggi.


Vedi sopra: è un vantaggio dei CISC, invece, perché non gli servono né registri addizionali né devono eseguire più istruzioni per fare la stessa cosa.

Con un aggravio sulla complessità del decoder di istruzioni, della rappresentazione delle uOP e della circuiteria di scheduling e ritiro delle uOP.


Non parliamo poi delle istruzioni in cui il risultato dell'operazione è in memoria, dove il vantaggio diventa ancora più grande, visto che in questo caso i RISC necessitano di Load + Op + Store, mentre x86/x64 fa tutto con UNA sola istruzione.

Correzione, su un x86-64 codifichi il tutto in un unica istruzione che se non sbaglio viene scomposta in 3 uOP il cui scheduling non è detto sia ottimale.


Infine, e non meno importante, ci sono istruzioni x86/x64 il cui la destinazione è la memoria e la sorgente è un valore immediato. Qui il vantaggio rispetto ai RISC si fa addirittura imbarazzante, visto che x86/x64 non spreca un solo registro e fa tutto con una sola istruzione, mentre un RISC richiede più registri (anche più di 2) e MOLTE più istruzioni (specialmente se l'immediato non è piccolo).

Una sola istruzione x86-64 ... che viene espansa in una sequenza di uOP non necessariamente ottimali che aumentano la pressione sulle unità load-store.
Mentre con un RISC con il doppio dei registri, in una sequenza "calda" tipo un loop poni meno pressione sulle unità load/store e vai via molto più veloce.


Non è che x86/x64 sia arrivato a prestazioni elevatissime per puro caso, eh! E l'ISA CISC ha aiutato, e parecchio.

La cosa che più ha aiutato gli x86-64 è stato l'Itanium, di fatto eliminando Alpha e MIPS tramite accordi commerciali riguardo l'adozione di Itanium
si è aperta per AMD la finestra di opportunità in cui proporre con successo x86-64.
Ed una delle innovazione fondamentali di x86-64 è stata estendere il numero di registri interi, non lo dimenticare, altrimenti sai che bello avere le istruzioni CISC con uno dei due operandi in memoria.
E poi diciamolo, x86-64 è arrivato dove è arrivato anche perchè Intel ha spinto l'acceleratore sui processi produttivi, infatti ora che Apple ha fatto la stessa cosa ne è con l'M1 che può permettersi cache più grandi ed un parallelismo interno maggiore grazie al processo produttivo più avanzato (ed al set d'istruzioni Aarch64 che permette di avere un miglior rapporto costi/benefici dall'avere un maggior numero di unità di esecuzione e di buffer di riordino).


Le due cose non sono legate. In futuro Apple continuerà ad avere grande ampiezza dei decoder e molto probabilmente aggiungerà il supporto alle SVE/2.

Molto probabile, ma già ora con "solo" le estensioni Neon si difende bene, figurarsi dopo.


E invece c'è eccome. Quando sono partiti con le estensioni ne avevano fissate alcune perché pensavano che andasse bene così. Poi si sono accorti (troppo tardi: ormai le estensioni erano state ratificate) e hanno iniziato a suddividere tali istruzioni in più sottoinsiemi, generando ancora più confusione.

I soliti accademici idealisti che non tengono conto della realtà...

Non capisco, al momento Risc V è una famiglia di set di istruzioni progettata per essere relativamente semplice, efficiente da implementare e libera da IP e brevetti difendibili che creino problemi di implementazione.

E' ancora in evoluzione ed ha ancora un sacco di margini di crescita, inoltre come i due set "base" RV32 e RV64 sono simili ma non compatibili tra loro, nulla vieta di introdurre una nuova sottofamiglia se necessario.
L'unica cosa che creerebbe veri problemi sarebbero breaking changes agli attuali set d'istruzioni "base" (RV32I, RV32E, RV64I e RV128I, di cui RV32E e RV128I non sono stati ancora definiti)


Ehm... no. Stanno pensando (se non l'hanno già fatto) di cambiare alcune parti dell'ISA in maniera non-retrocompatibile, perché si sono accorti, di nuovo, di aver fatto una stupidaggine. Ovviamente nasconderanno il tutto in un'altra nuova estensione, com'è loro abitudine ormai.


Ma tali modifiche vanno a toccare i set d'istruzione base ? Perchè è un vero problema di retrocompatibilità solo che si ha perdita di retrocompatibilità li.

cdimauro
18-12-2020, 22:25
E può arrivare ad averne così tante perche il set d'istruzioni permette di trarne vantaggio senza dover ricorrere a contorsionisi implementativi come succede con x86-64.
Direi proprio di, e sulla "x86 tax" ho già parlato in un altro thread in cui si sono confrontati diversi processori.

M1 ha oggettivamente una montagna di risorse, a prescindere da qualunque altro chip con cui venga confrontato, inclusi quelli di casa ARM.
Quando sento cose tipo "con 12 registri aveva quasi le stesse prestazioni" di solito lo interpreto come "ma averne 16 permette di avere prestazioni più elevate già ora e maggiori margini in futuro". :D
C'è poco da interpretare: basta semplicemente leggere lo studio e i dati, che ho riportato in un altro (ancora) thread. ;)

Poi ti posso dire che personalmente se ci fossero anche più di 16 registri farebbero comodo in alcuni ambiti, ma oggettivamente un CISC (come x86 e, soprattutto, 68K) in genere ne necessita molti di meno per avere comunque buone prestazioni, paragonato a un RISC, per le motivazioni che ho già esposto.
Allo stesso modo averne 32 è stato considerato uno sweet spot già con le tecnologie di implementazione e compilazione disponibili negli anni '90 (più di 20 anni fa), non è un caso se sia Alpha che MIPS e PowerPC siano partiti da subito con 32 registri interi e che poi anche ARM con Aarch64 abbia scelto di avere 32 registri interi a 64bit.
Non è nemmeno un caso che siano tutti RISC, che per loro natura hanno oggettivamente bisogno di più registri per fare le stesse cose. :O
Se ARM a più di un decennio di distanza ha privilegiato i 32 registri rispetto ad avere da 1 a 3bit extra da usare ad esempio per ulteriori modalità di indirizzamento ed operandi letti/scritti dalla memoria mi sa che qualche motivo serio ci sia stato.
Son due cose completamente separate / diverse.

Per le modalità d'indirizzamento parliamo esclusivamente di istruzioni di load / store, e non dell'intero insieme di istruzioni. Per questo tipo di istruzioni nessuno t'impedisce di mettere a disposizione più modalità d'indirizzamento, pur preservando tutto il resto dell'ISA, inclusi l'utilizzo di 32 registri.

Difatti uno dei grossi vantaggi di ARM rispetto a tanti altri RISC è stato quello di avere modalità d'indirizzamento molto complicate, persino più complicate di x86 (mi riferisco a quelle di pre-post de/incremento), con innegabili benefici a livello di densità del codice E prestazionali.

Già soltanto per questo ARM vince a mani basse su RISC-V, che una delle ISA più povere e semplici in assoluto, da questo punto di vista (e infatti paga pegno).
Forse ti confondi con le architetture precedenti, se non sbaglio una delle caratteristiche di Skylake è che il decoder istruzioni x86/x86-64 può decodificare simultaneamente fino a 5 istruzioni x86 "fresche" (di cui 4 "semplici" che si traducono in una singola uOP ed 1 complessa che viene scomposta in più uOP emesse in sequenza).
Non penso di sbagliare. :) Ti confondi con le uop che vengono inviate dal decoder alla coda delle istruzioni decodificate, ma le uop non rappresentano il numero di istruzioni decodificate. Il manuale delle ottimizzazioni di Intel non parla mai di quante istruzioni vengano decodificate, ma sempre di uop. Nello specifico: "Legacy Decode Pipeline delivery of 5 uops per cycle to the IDQ compared to 4 uops in previous generations"

Fortunatamente c'è Agner Fog che si passa il tempo a studiare micro-architetture x86/x64, e a fornire i risultati di tali studi. Nello specifico, per Skylake: "There are four decoders, which can handle four instructions (five or six with fusion) generating up to four µops per clock cycle". Quindi più di quattro istruzioni possono essere decodificate soltanto in presenza di macro-op fusion. Normalmente il massimo rimane quattro.
INOLTRE se le istruzioni x86 sono già presenti in forma decodificata nell uOP cache, possono essere inviate in esecuzione fino a 6 uOP.
Questo è un altro discorso, che non c'entra coi decoder (era ciò di cui stavamo parlando qui).
Se l'aumento della densità del codice penalizza troppo l'espressività, il guadagno che si ha a livello di dimensione della cache istruzioni viene vanificato.
Non so a cosa ti riferisca: potresti chiarire e/o fare degli esempi?
Inoltre non è una cosa "vera in assoluto", dipende molto dalle latenze negli accessi a registri, cache e memoria e dalla banda di I/O, nel senso che sono cose da valutare caso per caso e con il cambiare delle opzioni implementative.
No, non è così. Lo studio è stato fatto a parità di tutti gli elementi che hai elencato, e con la sola differenza rappresentata dalla stessa ISA con o senza istruzioni compresse. Quando cambia soltanto una variabile è facile fare confronti, ed è quello che è stato fatto, per l'appunto.
D'altro canto, a differenza che negli x86-64, in un risc con un sufficiente numero di registri, il compilatore o il programmatore possono schedulare la load in anticipo ed hanno maggiori possibilità di riuscire ad inserire altre istruzioni da eseguire rima di arrivare all'eseguire l'operazione sul dato.
Questo lo puoi fare anche con gli x86/x64. Peraltro è ancora più facile, visto che non esistono dipendenze coi registri fisici (il dato caricato dalla memoria andrà a finire in uno dei registri interni).
E' un vantaggio non da poco visto che agli x86 sono state aggiunte istruzioni di prefetch proprio per poter fare la stessa cosa (annullando il "vantaggio" teorico che hanno referenziando direttamente la memoria ... per avere un vantaggio concreto).
Ma anche no, non ci siamo proprio. Le istruzioni di prefetch servono a tutt'altro, sono presenti anche nei RISC, e non servono a questo, ma ad istruire la logica di prefetch quando ci sono stream di dati a cui dover accedere o manipolare, in modo che le successive (ma molto successive: si parla di decine o anche centinaia di clock "in avanti") si possano trovare quello che gli serve senza o con minime attese.

Le singole istruzioni "general purpose" non fanno uso e non hanno bisogno (in genere) di istruzioni di prefetch. Altrimenti il codice sarebbe letteralmente farcito di queste istruzioni (con notevole crollo prestazionale, visto che la logica di prefetch può "seguire" un numero limitato di stream).
Skylake: 1 istruzione complessa e 4 semplici oppure ... giù di prestazioni fino al worst case di una istruzione complessa in parziale decodifica.
M1: 8 istruzioni e giù fino a ... diciamo almeno 4 istruzioni se si usa un compilatore con attivati loop unrolling ed auto-inlining.
OK, e quindi? Ciò non toglie che un CISC come x86/x64 abbia bisogno di meno istruzioni da eseguire rispetto a un RISC, e quindi di meno decoder.

Peraltro se il frontend è organizzato per decodificare un'istruzione complessa e 3 più semplici, è perché si è visto che nel codice reale le istruzioni complesse sono ben più rare di quelle più semplici, e intervallate. Per cui Intel ha organizzato così il frontend.
Ma quanto è frequente questo caso ideale per i CISC ?
Direi molto, molto frequente:
https://www.appuntidigitali.it/18192/statistiche-su-x86-x64-parte-5-indirizzamento-verso-la-memoria/
Guarda pure le tabelle che ho riportato sia per x86 sia per x64, e vedi un po' quante sono le istruzioni che referenziano la memoria.
Poi confrontali con questi numeri: https://www.appuntidigitali.it/18054/statistiche-su-x86-x64-parte-1-macrofamiglie-di-istruzioni/
Sono state analizzate circa 1,75 milioni di istruzioni (1.746.569 per la precisione) per PS32, e circa 1,74 milioni (1.737.331) per PS64
E quanta pressione viene fatta sulle unità di load-store ? Perchè poi se vai a saturare la capacità delle unità di load/store vanifichi tutti i potenziali vantaggi.
La pressione sulle unità di load-store si verifica esclusivamente quando non ci sono abbastanza registri liberi, e quindi si deve salvarne il contenuto nello stack e poi recuperarlo.

Cosa che succede spesso su x86, coi suoi soli 8 registri (nemmeno tutti liberi: uno è lo stack pointer), ma di gran lunga meno con x64 e i suoi 16 registri.
Con un aggravio sulla complessità del decoder di istruzioni,
Vero, ma questo attiene soltanto a x86/x64, a causa del modo in cui viene indicata la presenza di un operando verso la memoria, e anche del tipo di operando.

Altri CISC possono fare, e fanno, di gran lunga meglio, con un leggero costo da sostenere per consentire alle istruzioni di referenziare la memoria.
della rappresentazione delle uOP e della circuiteria di scheduling e ritiro delle uOP.
Qui, invece, non c'è alcuna differenza coi RISC: una volta trasformate le istruzioni in uOP, il backend le "digerisce" allo stesso modo. Non è un caso che il backend dei moderni processori x86/x64 sia RISC, infatti. ;)
Correzione, su un x86-64 codifichi il tutto in un unica istruzione che se non sbaglio viene scomposta in 3 uOP il cui scheduling non è detto sia ottimale.
Sì, vengono divise in 3 uOP, ma lo scheduling rimane ottimale. Non foss'altro perché è il backend a occuparsene, come meglio crede, e certamente e sempre meglio di come farebbe qualunque compilatore. Che poi è anche il motivo per cui le micro-architetture in-order hanno dovuto il cedere il passo a quelle OoO, e perfino ISA (VLIW/EPIC) pensate per essere in-order. :cool:
Una sola istruzione x86-64 ... che viene espansa in una sequenza di uOP non necessariamente ottimali che aumentano la pressione sulle unità load-store.
Mentre con un RISC con il doppio dei registri, in una sequenza "calda" tipo un loop poni meno pressione sulle unità load/store e vai via molto più veloce.
No, assolutamente: è l'esatto contrario.
Intanto la sequenza di uOP è ottimale (poi se la smazza il backend).
Poi le unità di load/store hanno, invece, pressione minima, perché devono soltanto leggere una volta dalla memoria (il primo operando sorgente; il secondo ce l'hanno già, perché è il valore immediato), e parimenti scrivere (sulla stessa locazione!) una sola volta nella memoria.

Immagina cosa dev'essere costretto a fare un RISC per fare la stessa cosa: o impiega più registri e/o istruzioni già soltanto per costruirsi la costante necessaria, o deve eseguire almeno una load per caricarla dalla memoria. Se ci aggiungiamo anche una modalità d'indirizzamento della memoria più complessa, allora servono altre istruzioni già soltanto per calcolare l'indirizzo desiderato.
La cosa che più ha aiutato gli x86-64 è stato l'Itanium, di fatto eliminando Alpha e MIPS tramite accordi commerciali riguardo l'adozione di Itanium
Alpha è morta, ma MIPS è rimasta: non mi sembra che abbia impensierito un granché x86/x64, sebbene sia stata una delle più veloci ISA RISC.
si è aperta per AMD la finestra di opportunità in cui proporre con successo x86-64.
AMD non aveva altra scelta, ed è stata fortunata perché Itanium è colato a picco.
Ed una delle innovazione fondamentali di x86-64 è stata estendere il numero di registri interi, non lo dimenticare, altrimenti sai che bello avere le istruzioni CISC con uno dei due operandi in memoria.
Sì, i 16 registri general purpose di x64 fanno sicuramente comodo, ma se vedi le statistiche sono ancora parecchie le istruzioni che fanno riferimento alla memoria. ;)
E poi diciamolo, x86-64 è arrivato dove è arrivato anche perchè Intel ha spinto l'acceleratore sui processi produttivi,
Che è la stessa cosa che ha sempre fatto IBM coi suoi POWER, e anch'essi RISC ad alte prestazioni.
infatti ora che Apple ha fatto la stessa cosa ne è con l'M1 che può permettersi cache più grandi ed un parallelismo interno maggiore grazie al processo produttivo più avanzato
Infatti è in netto vantaggio. E solo lei, visto che s'è accaparrata tutti i wafer a 5nm.
(ed al set d'istruzioni Aarch64 che permette di avere un miglior rapporto costi/benefici dall'avere un maggior numero di unità di esecuzione e di buffer di riordino).
Qui non concordo, per quanto già detto: non riguarda l'ISA, ma la micro-architettura di M1 di per sé.
Non capisco, al momento Risc V è una famiglia di set di istruzioni progettata per essere relativamente semplice, efficiente da implementare e libera da IP e brevetti difendibili che creino problemi di implementazione.

E' ancora in evoluzione ed ha ancora un sacco di margini di crescita, inoltre come i due set "base" RV32 e RV64 sono simili ma non compatibili tra loro, nulla vieta di introdurre una nuova sottofamiglia se necessario.
L'unica cosa che creerebbe veri problemi sarebbero breaking changes agli attuali set d'istruzioni "base" (RV32I, RV32E, RV64I e RV128I, di cui RV32E e RV128I non sono stati ancora definiti)
Non la segui, mentre io lo faccio da tempo, per cui ho potuto vedere l'evoluzione di questa ISA, delle sue estensioni, delle loro ratifiche / standardizzazioni, e delle ultime "sotto-estensioni" che sono nate per sopperire alle decisioni sbagliate prese con quelle da cui derivano.

Son tutte cose che puoi vedere tu stesso se riesci a recuperare le varie versioni / revisioni del documento delle specifiche dell'ISA.
Ma tali modifiche vanno a toccare i set d'istruzione base ? Perchè è un vero problema di retrocompatibilità solo che si ha perdita di retrocompatibilità li.
Le modifiche vanno (o andranno: non so sono state ratificate) a toccare alcune estensioni. In particolare mio riferisco a quella compressa, per la quale si vogliono liberare opcode attualmente allocati per istruzioni FP, in modo da riutilizzarli per altre istruzioni più utili.

Si sono accorti (troppo tardi) che le operazioni di load/store dei registri FP sono molto più rare e incidono meno rispetto ad altre istruzioni.

Per salvare capra (retrocompatibilità) e cavoli (riutilizzo degli opcode) stanno cercando di porvi rimedio con una nuova estensione compressa. Formalmente la retrocompatibilità è salva, perché quei processori non useranno l'estensione compressa standard, ma quella nuova. Di fatto è una presa in giro, perché stanno riutilizzando gli stessi opcode per cose completamente diverse, e quindi si tratta di una modifica non retrocompatibilità. Immagina il lavoro che dovranno fare i disassemblatori per questo giochetto...

LMCH
22-12-2020, 01:50
C'è poco da interpretare: basta semplicemente leggere lo studio e i dati, che ho riportato in un altro (ancora) thread. ;)

Poi ti posso dire che personalmente se ci fossero anche più di 16 registri farebbero comodo in alcuni ambiti, ma oggettivamente un CISC (come x86 e, soprattutto, 68K) in genere ne necessita molti di meno per avere comunque buone prestazioni, paragonato a un RISC, per le motivazioni che ho già esposto.

Ti riferisci a questa pubblicazione del 2006 ?
https://www.semanticscholar.org/paper/Performance-Characterization-of-the-64-bit-x86-from-Liu-Wu/c9e7976e3be3eed6cf843f1148f17059220c2ba4

Nota bene cosa hanno usato per i vari benchmark:
" In this paper, we conducted all the experiments on a Dell Precision Work-
station 370 MiniTower containing a 3.8 GHz Intel Pentium 4 processor." :(
Un maggior numero di registri "visibili" torna utile al crescere del parallelismo interno, ti credo che con un Pentium 4 passare da 12 a 16 non c'era lo stesso miglioramento che passando da 8 a 12, senza contare che l'ABI prevedeva solo registri caller-saved (mentre di solito quando si hanno molti registri interni le ABI sensate prevedono solo una parte di registri caller-saved ed il resto sono callee-saved proprio per evitare il problema descritto nella pubblicazione). :rolleyes:


Non è nemmeno un caso che siano tutti RISC, che per loro natura hanno oggettivamente bisogno di più registri per fare le stesse cose. :O

Oppure la cosa può essere vista come, avere più registri visibili costa meno a livello implementativo che avere istruzioni più complesse che poi vanno risc-izzate. ;)


Per le modalità d'indirizzamento parliamo esclusivamente di istruzioni di load / store, e non dell'intero insieme di istruzioni. Per questo tipo di istruzioni nessuno t'impedisce di mettere a disposizione più modalità d'indirizzamento, pur preservando tutto il resto dell'ISA, inclusi l'utilizzo di 32 registri.

Difatti uno dei grossi vantaggi di ARM rispetto a tanti altri RISC è stato quello di avere modalità d'indirizzamento molto complicate, persino più complicate di x86 (mi riferisco a quelle di pre-post de/incremento), con innegabili benefici a livello di densità del codice E prestazionali.

Questo perchè sia i primi ARM a 32bit e che più recenti ARM a 64bit sono stati progettati valutando pro e contro delle possibili opzioni a livello di set d'istruzioni ed implementazione ed anche dei target di mercato.

Così hai i Cortex-M0 (con set d'istruzioni Thumb-2 e varianti successive) che quanto a costo di produzione sono concorrenziali pure con le vecchie cpu ad 8bit, poi i Cortex-M3 e successivi pensati come microcontroller più potenti ma sempre per applicazioni embedded, per salire poi ai Cortex-R (che implementano il set "base" completo di istruzioni ARM a 32bit, hanno varianti dual lockstep, ecc. ) per poi arrivare ai Cortex-A a 32bit e poi a 64bit pensati più per far girare codice applicativo su un S.O. che per roba embedded di fascia bassa).
Guardacaso le cpu con solo Thumb-2 hanno modalità di indirizzamento più "semplici" seppur siano state introdote molti anni dopo le istruzioni ARM a 32bit originali.
Mentre invece le cpu Aarch64 essendo pensate per roba più grossa implementano modalità più complesse (perchè si parte dal presupposto di avere molte più risorse in termini di area e gate per implementare tali cpu).
Con Risc-V invece sono partiti definendo inizialmente il nucleo di istruzioni più semplici e solo ora sta cominciando a venir ratificata la roba più sofisticata.
Non è un caso se la maggior parte delle cpu Risc-V disponibili sul mercato attualmente siano degli RV32IMAC che mirano a scontrarsi al massimo con gli ARM Cortex-M3.


Già soltanto per questo ARM vince a mani basse su RISC-V, che una delle ISA più povere e semplici in assoluto, da questo punto di vista (e infatti paga pegno).

Risc-V è ancora in fase di completamento a livello di estensioni, nulla gli vieta di introdurre un estensione relativa a load/store "con modalità di indirizzamento extra" se proprio risultassero più convenienti.

Ma ho il forte sospetto che per ora non sarà così, per un motivo molto semplice, ovvero che implementa già le modalità di indirizzamento più utilizzate.

Mi riferisco ad esempio a quanto riportato in questa analisi:
http://www.cs.unc.edu/~porter/pubs/instrpop-systor19.pdf
Nota che è codice x86-64 e che le modalità di indirizzamento indexed e scaled (che Risc-V non ha) sono usate rispettivamente nel 0.85% e nel 0,44% dei casi ( contro un 7,28% del register-indirect ed un 32,5% del base+offset).


Non penso di sbagliare. :) Ti confondi con le uop che vengono inviate dal decoder alla coda delle istruzioni decodificate, ma le uop non rappresentano il numero di istruzioni decodificate. Il manuale delle ottimizzazioni di Intel non parla mai di quante istruzioni vengano decodificate, ma sempre di uop. Nello specifico: "Legacy Decode Pipeline delivery of 5 uops per cycle to the IDQ compared to 4 uops in previous generations"

Fortunatamente c'è Agner Fog che si passa il tempo a studiare micro-architetture x86/x64, e a fornire i risultati di tali studi. Nello specifico, per Skylake: "There are four decoders, which can handle four instructions (five or six with fusion) generating up to four µops per clock cycle". Quindi più di quattro istruzioni possono essere decodificate soltanto in presenza di macro-op fusion. Normalmente il massimo rimane quattro.

Fuochino, il decoder può processare fino a 5 istruzioni x86 per ciclo, ma POI più a valle c'e' il renamer che è limitato ad un output di 4 micro-op per ciclo.
https://www.agner.org/optimize/blog/read.php?i=583


Questo è un altro discorso, che non c'entra coi decoder (era ciò di cui stavamo parlando qui).

C'entra in termini di istruzioni x86 "pre-decodificate" nella micro-op cache che possono teoricamente essere inviate in esecuzione (se non fosse per il collo di bottiglia del renamer).
Se non sbaglio è il decoder che "comanda" la micro-op cache, in un certo senso è una forma ottimizzata di decodifica.


Non so a cosa ti riferisca: potresti chiarire e/o fare degli esempi?

Guardando sul documento che ho linkato sopra, x86-64 sembra più compatto del codice per ARMv8 ma poi se si analizzano le tipologie di istruzioni si vede che le istruzioni ampie meno di 4 byte sono il 42.4% (di cui il 23.1% ampie 3 byte) , quelle ampie 4 byte sono il 15.9%, quelle da 5 a 7 byte sono il 34.4% e quelle da 8 a 12 byte sono 6.3%.
Mediamente un istruzione x86-64 occupa 4 byte, inoltre lo stesso codice richiede molte più istruzioni move rispetto ad ARMv8, questo significa che i vantaggi legati alle istruzioni più "compatte" degli x86-64 vengono vanificati dalla minor espressività delle istruzioni "più corte" che possono accedere a meno registri e non hanno un move "gratis" come le istruzioni a 3 operandi di ARMv8.
Ovviamente il codice x86 (a 32bit) è più compatto di x86-64, ma seguendo lo stesso ragionamento il codice a 32bit degli ARM lo è ancora di più (istruzioni ARM "classiche" + istruzioni Thumb-2 a 16bit utilizzabili nello stesso codice applicativo).


Questo lo puoi fare anche con gli x86/x64. Peraltro è ancora più facile, visto che non esistono dipendenze coi registri fisici (il dato caricato dalla memoria andrà a finire in uno dei registri interni).

Lo puoi fare se rinunci al "vantaggio" di usare gli operandi in memoria e caricando i valori da utilizzare su registri interni MOLTO PRIMA di quando poi li utilizzerai (in modo da effettuare il load out-of-order insieme ad altre istruzioni che non dipendono dal valore che stai caricando), solo che questo diventa meno vantaggioso quando si hanno meno registri.
Inoltre lo stesso giochino di caricamento dei valori in memoria lo possono fare anche i RISC facendo molto più semplicemente ed efficientemente il renaming dei registri interni rispetto ad un CISC.


Ma anche no, non ci siamo proprio. Le istruzioni di prefetch servono a tutt'altro, sono presenti anche nei RISC, e non servono a questo, ma ad istruire la logica di prefetch quando ci sono stream di dati a cui dover accedere o manipolare, in modo che le successive (ma molto successive: si parla di decine o anche centinaia di clock "in avanti") si possano trovare quello che gli serve senza o con minime attese.

Le istruzioni di prefetch "esplicito" servono per ottimizzare gli accessi alla cache, mentre le "load con molto anticipo" in architetture load-store fanno semplicemente il prefetch di valori "ottimizzato dal programmatore/compilatore".
Ma resta il fatto che se vuoi ottimizzare l'uso di istruzioni x86-64 con operandi in memoria, a livello di compilatore ti servono le istruzioni di prefetch per limitare i problemi causati dal minor numero di registri visibili al programmatore/compilatore.


Le singole istruzioni "general purpose" non fanno uso e non hanno bisogno (in genere) di istruzioni di prefetch. Altrimenti il codice sarebbe letteralmente farcito di queste istruzioni (con notevole crollo prestazionale, visto che la logica di prefetch può "seguire" un numero limitato di stream).

Mentre questo problema non è così impattante sui RISC per la possibilità di schedulare le load con maggior anticipo tenendo tutto su registri interni.


OK, e quindi? Ciò non toglie che un CISC come x86/x64 abbia bisogno di meno istruzioni da eseguire rispetto a un RISC, e quindi di meno decoder.

Questo nel caso in cui si riescano a sfruttare le istruzioni più complesse ed i modi di indirizzamento più complessi, mentre a quanto vedo, gli attuali compilatori per x86-64 quando ottimizzano ai settaggi più estremi usano le istruzioni "semplici" che hanno anche i RISC ma con molte più move tra registri.


Peraltro se il frontend è organizzato per decodificare un'istruzione complessa e 3 più semplici, è perché si è visto che nel codice reale le istruzioni complesse sono ben più rare di quelle più semplici, e intervallate. Per cui Intel ha organizzato così il frontend.

E qui si ricade nel caso di CISC in cui si privilegiano le istruzioni Risc, ma con limiti nel numero massimo di istruzioni eseguibili in parallelo.
Altrimenti quelli di ARM avrebbero implementato Aarch64 come un CISC "riscritto da zero e moderno" mentre invece hanno considerata molto più vantaggiosa un architettura "simil-RISC".


La pressione sulle unità di load-store si verifica esclusivamente quando non ci sono abbastanza registri liberi, e quindi si deve salvarne il contenuto nello stack e poi recuperarlo.

Cosa che succede spesso su x86, coi suoi soli 8 registri (nemmeno tutti liberi: uno è lo stack pointer), ma di gran lunga meno con x64 e i suoi 16 registri.

Io aggiungerei anche che i compilatori per x86-64 tengono conto delle limitazioni di tale architettura e quindi generano sequenze di codice in cui si hanno meno pre-caricamenti di valori nei registri interni, privilegiano l'uso dei primi 8 registri, ecc. ecc.


Vero, ma questo attiene soltanto a x86/x64, a causa del modo in cui viene indicata la presenza di un operando verso la memoria, e anche del tipo di operando.

Altri CISC possono fare, e fanno, di gran lunga meglio, con un leggero costo da sostenere per consentire alle istruzioni di referenziare la memoria.

Qui, invece, non c'è alcuna differenza coi RISC: una volta trasformate le istruzioni in uOP, il backend le "digerisce" allo stesso modo. Non è un caso che il backend dei moderni processori x86/x64 sia RISC, infatti. ;)

Il problema è che per arrivare al backend Risc serve una "digestione" più lunga e complessa delle istruzioni CISC, cosa che a parità di tecnologia ha il suo peso. ;)


Immagina cosa dev'essere costretto a fare un RISC per fare la stessa cosa: o impiega più registri e/o istruzioni già soltanto per costruirsi la costante necessaria, o deve eseguire almeno una load per caricarla dalla memoria. Se ci aggiungiamo anche una modalità d'indirizzamento della memoria più complessa, allora servono altre istruzioni già soltanto per calcolare l'indirizzo desiderato.

Con la differenza che un Risc HA più registri disponibili per precaricare valori e che i valori immediati nella maggior parte dei casi sono piccoli oppure è vantaggioso caricarli su un registro e utilizzare più volte il registro. ;)


Alpha è morta, ma MIPS è rimasta: non mi sembra che abbia impensierito un granché x86/x64, sebbene sia stata una delle più veloci ISA RISC.

Alpha è morta perchè Compaq ed HP avevano deciso di puntare tutto su Itanium.
A spingere MIPS sui server era SGI, che pure essa è passata ad Itanium e poi ha fatto la fine che ha fatto. MIPS è sopravvissuto nel settore embedded ma ormai è usato principalmente in roba legacy visto che ARM ha confinato MIPS e PowerPC a nicchie ridotte di mercato.
I produttori di cpu/microcontroller embedded per roba nuova a 32bit e 64bit propongono principalmente ARM.
PowerPC resiste come architettura legacy specialmente nell'automotive ma al massimo si vedono degli shrink dei core, niente roba davvero nuova.


Che è la stessa cosa che ha sempre fatto IBM coi suoi POWER, e anch'essi RISC ad alte prestazioni.

Solo che IBM i POWER li propone solo per supercomputer e server di fascia alta, una nicchia molto remunerativa ma nicchia rimane.


Non la segui, mentre io lo faccio da tempo, per cui ho potuto vedere l'evoluzione di questa ISA, delle sue estensioni, delle loro ratifiche / standardizzazioni, e delle ultime "sotto-estensioni" che sono nate per sopperire alle decisioni sbagliate prese con quelle da cui derivano.

Son tutte cose che puoi vedere tu stesso se riesci a recuperare le varie versioni / revisioni del documento delle specifiche dell'ISA.

Le modifiche vanno (o andranno: non so sono state ratificate) a toccare alcune estensioni. In particolare mio riferisco a quella compressa, per la quale si vogliono liberare opcode attualmente allocati per istruzioni FP, in modo da riutilizzarli per altre istruzioni più utili.

Si sono accorti (troppo tardi) che le operazioni di load/store dei registri FP sono molto più rare e incidono meno rispetto ad altre istruzioni.

Per salvare capra (retrocompatibilità) e cavoli (riutilizzo degli opcode) stanno cercando di porvi rimedio con una nuova estensione compressa. Formalmente la retrocompatibilità è salva, perché quei processori non useranno l'estensione compressa standard, ma quella nuova. Di fatto è una presa in giro, perché stanno riutilizzando gli stessi opcode per cose completamente diverse, e quindi si tratta di una modifica non retrocompatibilità. Immagina il lavoro che dovranno fare i disassemblatori per questo giochetto...

Forse ho capito male, ma non mi sembra che sia un vero problema (almeno per ora) visto che al momento il grosso degli utilizzi pratici sono incentrati su core con estensioni IMAC (senza floating point) oppure roba embedded compilata ad hoc, quindi sarebbe una perdita di retrocompatibilità accettabile. In fin dei conti Risc-V non è UN unico set di istruzioni ma una famiglia di set di istruzioni.

amd-novello
22-12-2020, 10:48
wall of text versus wall of text

lol

cdimauro
23-12-2020, 10:23
@amd-novello Ah, bene. Allora divertiti con quest'altro, visto che ti piacciono tanto. :D
Ti riferisci a questa pubblicazione del 2006 ?
https://www.semanticscholar.org/paper/Performance-Characterization-of-the-64-bit-x86-from-Liu-Wu/c9e7976e3be3eed6cf843f1148f17059220c2ba4

Nota bene cosa hanno usato per i vari benchmark:
" In this paper, we conducted all the experiments on a Dell Precision Work-
station 370 MiniTower containing a 3.8 GHz Intel Pentium 4 processor." :(
Un maggior numero di registri "visibili" torna utile al crescere del parallelismo interno, ti credo che con un Pentium 4 passare da 12 a 16 non c'era lo stesso miglioramento che passando da 8 a 12, senza contare che l'ABI prevedeva solo registri caller-saved (mentre di solito quando si hanno molti registri interni le ABI sensate prevedono solo una parte di registri caller-saved ed il resto sono callee-saved proprio per evitare il problema descritto nella pubblicazione). :rolleyes:
Scusa, che c'entra il fatto che abbiano usato un P4? E' stato fatto soltanto per estrarre i dati delle ricerche, ma l'ABI usata è quella di x86-64, e non quella di x86, quindi register-based anziché stack-based, anche quando sono stati ridotti i registri a 12.

Ciò che era importante evidenziare è che il passaggio da 12 a 16 registri sostanzialmente non abbia inciso a livello prestazionale. :read:
Oppure la cosa può essere vista come, avere più registri visibili costa meno a livello implementativo che avere istruzioni più complesse che poi vanno risc-izzate. ;)
Se le istruzioni complesse "da rischizzare" sono tutte dello stesso tipo (con Mod/RM nel caso di x86/x86-64), il costo è irrisorio: si tratta di emettere uop di load/store oltre a quella di calcolo vero e proprio, e si applica sistematicamente a tutte le istruzioni di questo tipo (basta soltanto sapere che lo siano).
Questo perchè sia i primi ARM a 32bit e che più recenti ARM a 64bit sono stati progettati valutando pro e contro delle possibili opzioni a livello di set d'istruzioni ed implementazione ed anche dei target di mercato.
Opinabile. Anche coi primi processori a 32 bit ARM ha commesso degli errori, alcuni madornali: vedi il registro PC a soli 26 bit (quindi max 64MB di memoria indirizzabili), perché gli aveva aggiunto anche i bit del registro di flag/stato. Infatti è stata poi costretta a separarli con la v2 (se non erro), con una modifica all'ISA assolutamente non retro-compatibile. E' stata una visione davvero molto, molto miope.
Così hai i Cortex-M0 (con set d'istruzioni Thumb-2 e varianti successive) che quanto a costo di produzione sono concorrenziali pure con le vecchie cpu ad 8bit, poi i Cortex-M3 e successivi pensati come microcontroller più potenti ma sempre per applicazioni embedded, per salire poi ai Cortex-R (che implementano il set "base" completo di istruzioni ARM a 32bit, hanno varianti dual lockstep, ecc. ) per poi arrivare ai Cortex-A a 32bit e poi a 64bit pensati più per far girare codice applicativo su un S.O. che per roba embedded di fascia bassa).
Guardacaso le cpu con solo Thumb-2 hanno modalità di indirizzamento più "semplici" seppur siano state introdote molti anni dopo le istruzioni ARM a 32bit originali.
ARM ha commesso degli errori anche con le estensioni (Thumb-EE e Jazilla che sono sostanzialmente morte, per citarne due abbastanza note).

In particolare Thumb e Thumb-2 sono l'esempio del pastrocchio che ARM ha realizzato quando ha definito la prima, mentre avrebbe potuto semplicemente prendere gli allora opcode ARM, rimuovere i 4 bit per l'esecuzione condizionale, lasciare la sola "condizione" (sempre vera) per l'esecuzione tout-court delle istruzioni, e riutilizzare le altre 15 configurazioni per definire in maniera pulita e semplice le istruzioni compatte a 16-bit. Invece è partita abbozzando malamente la prima, per poi metterci una pezza dopo con la seconda.
Mentre invece le cpu Aarch64 essendo pensate per roba più grossa implementano modalità più complesse (perchè si parte dal presupposto di avere molte più risorse in termini di area e gate per implementare tali cpu).
Ma anche qui ARM ha peccato, non avendo definito un'ISA compatta. Vedrai meglio dopo il perché, nel paper dei progettisti di RISC-V che riporterò.
Con Risc-V invece sono partiti definendo inizialmente il nucleo di istruzioni più semplici e solo ora sta cominciando a venir ratificata la roba più sofisticata.
Non è così, e ripeto: è perché non hai seguito l'evoluzione di quest'architettura. Infatti diverse estensioni importanti sono già state ratificate, e pure da tempo.

La grossa mancanza riguarda le estensioni vettoriali, perché sono anni che gli accademici sbattono le corna alla ricerca di qualcosa di utilizzabile concretamente nella realtà, e che non li faccia soffrire troppo nello scardinare i loro ideali di "bellezza" dell'ISA che s'erano costruiti (i famigerati soli 3 formati di opcode sono un lontano ricordo, infatti: rimangono un proclama di pura propaganda).
E meno male che a questo comitato si sono uniti diversi ingegneri provenienti da aziende, che hanno i piedi ben piantati per terra, altrimenti sarebbero state ratificate delle colossali stupidaggini, come la definizione dinamica, a runtime, del tipo di dati utilizzato dai registri vettoriali (come da originale proposta, di diversi anni fa), che avrebbe fatto piangere lacrime amare a chi avrebbe dovuto implementarle...
Non è un caso se la maggior parte delle cpu Risc-V disponibili sul mercato attualmente siano degli RV32IMAC che mirano a scontrarsi al massimo con gli ARM Cortex-M3.
Ci sono anche altre estensioni già ratificate da tempo. Se non vengono usate è proprio perché al momento le aziende più interessate sono quelle che operano in ambito embedded, a cui bastano quelle istruzioni.

Anzi, quella M e A erano e sono anche di troppo (su quella C mi sono già espresso), ed è proprio il motivo per cui sono poi nate delle loro versioni castrate, aumentando di fatto la frammentazione (visto che M ed A erano già state ratificate, e non si poteva più tornare indietro).
Risc-V è ancora in fase di completamento a livello di estensioni, nulla gli vieta di introdurre un estensione relativa a load/store "con modalità di indirizzamento extra" se proprio risultassero più convenienti.
Non lo faranno mai perché per loro l'architettura base è stata definita ed è intoccabile, incluse le istruzioni di load/store. Ti posto già qui il paper di cui ti ho parlato prima, così puoi cominciare a prendere visione di cosa ne pensano e perché sono irremovibili nel difendere le loro scelte: The Renewed Case for the Reduced Instruction Set Computer: Avoiding ISA Bloat with Macro-Op Fusion for RISC-V (https://people.eecs.berkeley.edu/~krste/papers/EECS-2016-130.pdf)
Come puoi vedere già il titolo è tutto un programma, e il contenuto non si smentisce.
Ma ho il forte sospetto che per ora non sarà così, per un motivo molto semplice, ovvero che implementa già le modalità di indirizzamento più utilizzate.
No. Vedi sopra. Istruzioni di load/store più avanzate sono state proposte da progetti esterni, come il PULP dell'università di Zurigo (l'estensione / progetto più diffuso, e che praticamente è diventato uno standard parallelo), ma rimarranno non standardizzate / ratificate dal comitato RISC-V.
Mi riferisco ad esempio a quanto riportato in questa analisi:
http://www.cs.unc.edu/~porter/pubs/instrpop-systor19.pdf
Nota che è codice x86-64 e che le modalità di indirizzamento indexed e scaled (che Risc-V non ha) sono usate rispettivamente nel 0.85% e nel 0,44% dei casi ( contro un 7,28% del register-indirect ed un 32,5% del base+offset).
Francamente è una ricerca che lascia il tempo che trova per le modalità utilizzate per estrarre l'elenco delle istruzioni, visto che fanno uso del comando objdump, che per limiti intrinseci disassembla anche blocchi dati, falsando le statistiche.
E' il motivo per cui, ad esempio, trovi un così elevato numero di istruzioni ADD, come puoi vedere anche dal loro sito (http://x86instructionpop.com) che consente di consultare il database con le informazioni raccolte. Infatti la ADD è così inflazionata perché si tratta dell'istruzione avente 0x00 come uno dei suoi opcode: dato estremamente comune negli eseguibili, come certamente sai.

Altri paper mostrano risultati abbastanza diversi:
https://www.strchr.com/x86_machine_code_statistics
http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=23D681327E0B647562223062ED5E0833?doi=10.1.1.407.5071&rep=rep1&type=pdf
http://people.umass.edu/cmutigwe/research/ICETCIT-2013/Instruction%20Set%20Usage%20Analysis%20for%20Application-Specific%20Systems%20Design.pdf
e soprattutto il paper degli autori di RISC-V (https://people.eecs.berkeley.edu/~krste/papers/EECS-2016-130.pdf) che ti ho già passato che, sebbene sia ovviamente (fortemente) "biased", mostra dei dati grezzi che sono molti utili di per sé, oltre al fatto che riporta esclusivamente istruzioni reali, e soprattutto le statistiche sono di quelle dinamiche (quindi tutte e soltanto quelle eseguite realmente in quelle applicazioni) e non statiche (quelle del paper che hai postato).

Tra l'altro anche il bouquet di applicazioni che ho usato per le mie statistiche (anche statiche, sia chiaro) mostra un quadro diverso da quello del tuo paper, e più in linea con gli altri paper. Inoltre non ho disassemblato roba a caso, ma sono partito dall'entry point dell'eseguibile, e ho disassemblato tutto ciò che era possibile, tracciando le istruzioni di salto. Quindi niente spazzatura/dati grezzi disassemblati come istruzioni. Le statistiche le trovi nella mia ultima serie di articoli su Appunti Digitali, dove puoi vedere i dati della beta pubblica di Photoshop CS6, sia a 32 sia a 64-bit.

Ciò precisato, t'invito a leggere il paper che ho postato, e così vedrai che, sebbene la modalità d'indirizzamento indicizzata non sia così diffusa, è molto usata (dinamicamente) in alcune applicazioni ed è il motivo per cui RISC-V ha un crollo a livello prestazionale, di cui gli autori propongo una soluzione (macro-op fusion) per alleviare il problema.

Che il paper sia biased lo si capisce anche dal fatto che si lamentano della scarsa qualità del codice generato per RISC-V (che ci può stare. Anche se loro hanno attivato soltanto per RISC-V un'opzione di GCC per disabilitare la generazione di routine di prologo/epilogo, che altrimenti avrebbero prodotto PIU' istruzioni e micro-op eseguite), ma analizzando il disassemblato x86-x64 in alcuni casi si può vedere come vengano generate istruzioni non necessarie, che ovviamente penalizzano quest'ISA sia a livello prestazionale sia di densità di codice.

Dai pattern che ho rilevato (dagli esempi nel paper) mi sembra evidente che GCC non sia capace di riconoscere quando può evitare di omettere la generazione di istruzioni di confronto quando la precedente istruzione ha già impostato correttamente i flag, che quindi possono essere immediatamente "consultabili" (con un salto condizionale).
E qui parliamo di roba da manuale, eh! Perché per me è OVVIO che l'ottimizzatore del backend x86/x86-64 avrebbe dovuto tenere conto di questi casi molto comuni. Non capisco come sia potuto sfuggire agli sviluppatori di GCC.

Questo per dirti che non è soltanto RISC-V che può lamentare che non sia stato generato codice adeguato, ma persino ISA rodate come x86/x86-64.

Altra cosa non meno importante, i paper in genere fanno soltanto uso di GCC come compilatore, mentre nelle applicazioni reali si usano, e sono pure molto comuni, anche altri compilatori, come quello di Intel e, soprattutto, di Microsoft in Windows.
Questi compilatori ottimizzano molto meglio il codice rispetto a GCC, sia a livello di istruzioni generate sia a livello di densità di codice.
Infatti da ciò che ho visto finora GCC predilige la generazione di codice più "RISC-like", anche quando deve farlo per x86/x86-64. E lo fa a danno soprattutto della densità di codice, che è di gran lunga più scarsa rispetto agli compilatori.

Giusto per rendere l'idea, la lunghezza media delle istruzioni x86 è di 3,42 byte per l'intero bouquet di applicazioni che ho usato (31, delle più svariate: da arm-none-eabi-gdb.exe a WinUAE.exe, passando per ffmpeg_32.exe, Neverwinter.exe, Skype.exe, sublime_text_32.exe, ecc.). Se di queste seleziono soltanto quelle compilate con GCC (sono 6: arm-none-eabi-gdb.exe, cc1.exe, cc1plus.exe, ffmpeg_32.exe, Kodi.exe, lto1.exe), la lunghezza media è di ben 3,93 byte.
Per x86-64, invece, la lunghezza media è di 4,05 byte (su 25 applicazioni), mentre prendendo le sole due applicazioni GCC (soltanto 2: ffmpeg_64.exe, mame64.exe) diventa di ben 5,18 byte (colpa di MAME, che ha lunghezza media molto alta: ben 5,52 byte). Posto che quelle GCC sono troppo poche, il trend rimane comunque superiore a quello delle applicazioni non compilate con GCC.

E ti posso dire che se dovessi tenere conto soltanto di GCC come benchmark da usare per la densità di codice, potrei andare a stappare subito una bottiglia di buon Dom Pérignon, visto che la mia architettura attualmente mostra una lunghezza media nettamente migliore rispetto a GCC (3,25 byte: -17,28% per x86. 3,76 byte: -27,35% su x86-64) che rispetto a tutti i compilatori (incluso GCC. 3,12 byte: -8,72% per x86. 3,26 byte: -19,35% su x86-64).

Questa lunga digressione per chiarire meglio diversi concetti, che poi vengono ripresi anche in altre parti di questa discussione, così si può usare questa parte come comodo punto di riferimento generale.
Fuochino, il decoder può processare fino a 5 istruzioni x86 per ciclo, ma POI più a valle c'e' il renamer che è limitato ad un output di 4 micro-op per ciclo.
https://www.agner.org/optimize/blog/read.php?i=583
Sono sempre 4 istruzioni decodificate al massimo (max 5 o 6 col macro-op fusion), ma quello che hai riportato riguarda soltanto il limite dell'attuale implementazione del register renamer, appunto.

C'è qualche altro commento che riporta delle informazioni interessanti. Non riporto tutto il messaggio, ma soltanto la parte iniziale, che è anche la più importante in questo contesto:
Haswell register renaming / unfused limits
Author: Peter Cordes Date: 2017-05-11 09:32
Tacit Murky wrote:
Looks like it's about the number of renamed registers.
Agreed. Simply changing Nathan's loops to use an immediate instead of a register for `max` produces a dramatic speedup on HSW:
Nathan's 2 micro / 2 macro on my HSW: one iteration per 1.42275c (~4.21 unfused-domain uops per clock). Very consistent, +- 0.0001 cycles per iter (for 1G iterations).
cmp r,imm instead of cmp r,max for both compares : one iteration per ~1.12c (~5.35 unfused-domain uops per clock). Pretty noisy, from 1.116c to 1.124c per iter.
Come vedi usare immediati porta dei vantaggi, perché NON si usano registri, e quindi non si applica il limite del register renamer. ;)
C'entra in termini di istruzioni x86 "pre-decodificate" nella micro-op cache che possono teoricamente essere inviate in esecuzione (se non fosse per il collo di bottiglia del renamer).
Sì, ma non attiene ai decoder veri e propri, che hanno già fatto il loro lavoro, e in questa parte dell'esecuzione non c'entrano più.
Se non sbaglio è il decoder che "comanda" la micro-op cache, in un certo senso è una forma ottimizzata di decodifica.
La decodifica è sempre la stessa, e non è ottimizzata da questo punto di vista. Che ci fosse la micro-op cache o meno, le micro-op devono essere generate per poi essere eseguite dal backend.

Se di ottimizzazioni possiamo parlare è che questa micro-op cache funge sostanzialmente da cache L0, e quindi i decoder non sono sempre attivi. Anzi, mi pare che vengano spenti l'80% del tempo, se non ricordo male le dichiarazioni di Intel di diversi anni fa (probabilmente la situazione è ancora migliorata adesso).
Guardando sul documento che ho linkato sopra, x86-64 sembra più compatto del codice per ARMv8 ma poi se si analizzano le tipologie di istruzioni si vede che le istruzioni ampie meno di 4 byte sono il 42.4% (di cui il 23.1% ampie 3 byte) , quelle ampie 4 byte sono il 15.9%, quelle da 5 a 7 byte sono il 34.4% e quelle da 8 a 12 byte sono 6.3%.
Mediamente un istruzione x86-64 occupa 4 byte, inoltre lo stesso codice richiede molte più istruzioni move rispetto ad ARMv8, questo significa che i vantaggi legati alle istruzioni più "compatte" degli x86-64 vengono vanificati dalla minor espressività delle istruzioni "più corte" che possono accedere a meno registri e non hanno un move "gratis" come le istruzioni a 3 operandi di ARMv8.
Ovviamente il codice x86 (a 32bit) è più compatto di x86-64, ma seguendo lo stesso ragionamento il codice a 32bit degli ARM lo è ancora di più (istruzioni ARM "classiche" + istruzioni Thumb-2 a 16bit utilizzabili nello stesso codice applicativo).
In parte ho risposto sopra. Ma, contrariamente a quello che pensi, il numero di istruzioni (dinamicamente) eseguite da x86-64 è sempre minore a quello di x86, ARMv7, ARMv8, RISC-V a 64 bit in versione G e GC, come puoi vedere dal paper che ho postato.
Paper che però è viziato, visto che per RISC-V GC hanno "casualmente" messo soltanto il numero di micro-op "fused", e non il numero di istruzioni vere e proprie. Però per il resto i dati sono affidabili. ARMv8 fa molto bene, e persino meglio di RISC-V GC "micro-op fused", ma a livello di numero di istruzioni eseguite rimane comunque sotto a x86-64.

Ciò che sorprende di questo paper è il dato relativo al "Dynamic Instruction Bytes", ossia il numero di byte di tutte le istruzioni eseguite. A parte il fatto che, al solito, il paper è biased, avendo "stranamente" gli autori rimosso tale informazione per x86 (il che non sorprende: anche dalle mie statistiche, che ho riportato sopra, la lunghezza media delle istruzioni è nettamente migliore di x86-64, assestandosi sui 3,42 byte col mio bouquet, contro i 4,05 di x86-64), è il dato relativo a x86-64 che risulta decisamente lusinghiero (cosa che francamente non avrei mai detto, visto che fa decisamente peggio di x86), superando tutte le altre architetture riportate nella tabella (sì: persino ARMv7), fatta eccezione per RISC-V GC che offre i migliori risultati. ARMv8 si difende, ma c'è un netto distacco da x86-64 (e, soprattutto, da RISC-V GC).

C'è da dire che non è affatto chiaro se per ARMv7 sia stata utilizzata anche Thumb-2, visto che non v'è traccia né menzione alcuna nel paper. Potrebbe essere anche questo frutto del bias del paper (che non mi sorprenderebbe affatto): tagliare fuori Thumb-2, che è rinomata per fare molto bene a livello di densità di codice. Preciso, però, che non puoi eseguire contemporaneamente istruzioni Thumb-2 assieme a quelle ARM normali: o esegui le une o le altre, e non puoi mischiarle. Puoi soltanto passare dalla modalità ARM a Thumb-2 (che non è soltanto a 16-bit. Anzi, la maggior parte delle istruzioni sono a 32-bit) e viceversa facendo uso di apposite istruzioni, questo sì.

In sintesi: nonostante x86-64 sia una brutta architettura per quanto riguarda la struttura degli opcode e il forzato usato di prefissi (specialmente rispetto a x86), non ne esce affatto male confrontata con architetture nuove di pacca, che non hanno dovuto portarsi dietro alcun legacy.
Lo puoi fare se rinunci al "vantaggio" di usare gli operandi in memoria e caricando i valori da utilizzare su registri interni MOLTO PRIMA di quando poi li utilizzerai (in modo da effettuare il load out-of-order insieme ad altre istruzioni che non dipendono dal valore che stai caricando), solo che questo diventa meno vantaggioso quando si hanno meno registri.
E' un vantaggio del tutto trascurabile proprio quando hai una micro-architettura OoO.

Per il resto quello che prospetti è uno scenario ideale, dove avresti tante istruzioni da eseguire linearmente/sequenzialmente, e quindi potresti permetterti il lusso di piazzarle distanziando le load da quelle che poi ne useranno i valori.

Poi vai a prendere il codice reale, e vedi che queste gigantesche liste di istruzioni sequenziali sono alquanto rare, perché i casi comuni sono di piccoli gruppi di istruzioni intervallate/farcite di salti e da tante chiamate a subroutine. Per cui spesso capita che, invece, le load siano vicinissime o addirittura attaccate alle istruzioni che ne useranno il risultato, come puoi vedere anche negli spezzoni di codice che sono stati riportati nel paper che ho fornito.
Inoltre lo stesso giochino di caricamento dei valori in memoria lo possono fare anche i RISC facendo molto più semplicemente ed efficientemente il renaming dei registri interni rispetto ad un CISC.
Solo che i CISC non hanno bisogno di register renaming quando usano valori immediati, come puoi vedere dalla parte di discussione che ho riportato sopra. ;)
Le istruzioni di prefetch "esplicito" servono per ottimizzare gli accessi alla cache, mentre le "load con molto anticipo" in architetture load-store fanno semplicemente il prefetch di valori "ottimizzato dal programmatore/compilatore".
Ma resta il fatto che se vuoi ottimizzare l'uso di istruzioni x86-64 con operandi in memoria, a livello di compilatore ti servono le istruzioni di prefetch per limitare i problemi causati dal minor numero di registri visibili al programmatore/compilatore.

Mentre questo problema non è così impattante sui RISC per la possibilità di schedulare le load con maggior anticipo tenendo tutto su registri interni.
Vedi sopra: no, servono soltanto per manipolare grosse quantità di dati.
Questo nel caso in cui si riescano a sfruttare le istruzioni più complesse ed i modi di indirizzamento più complessi, mentre a quanto vedo, gli attuali compilatori per x86-64 quando ottimizzano ai settaggi più estremi usano le istruzioni "semplici" che hanno anche i RISC ma con molte più move tra registri.
Purtroppo è il comportamento di GCC, che non ottimizza tanto bene per x86/x64-64: altri compilatori fanno di meglio.

Ciò nonostante riesce a generare istruzioni facenti uso delle famigerate modalità d'indirizzamento indicizzate/scalate, come puoi vedere anche dal paper che ho riportato, e che fanno la differenza, specialmente rispetto a RISC-V.
E qui si ricade nel caso di CISC in cui si privilegiano le istruzioni Risc, ma con limiti nel numero massimo di istruzioni eseguibili in parallelo.
Ma non sono i CISC che privilegiano le istruzioni più semplici: è il codice stesso che è fatto così. :) Poi è chiaro che ci sono anche compilatori come GCC che privilegino questo modello, ma per la loro intrinseca implementazione.
Altrimenti quelli di ARM avrebbero implementato Aarch64 come un CISC "riscritto da zero e moderno" mentre invece hanno considerata molto più vantaggiosa un architettura "simil-RISC".
Beh, AArch64 ha molto dei CISC: un numero di istruzioni di poco inferiore rispetto a x86-64 (com'è riportato anche nel tuo paper), con modalità d'indirizzamento anche più complicate (pre-post incr/decremento), diverse istruzioni complicate (ha persino istruzioni load/store con due registri alla volta), come pure diverse istruzioni condizionali.

AArch64 è l'antitesi di RISC-V. E se consideri che ARM abbia progettato da zero quest'architettura, lascia pensare molto su quale macrofamiglia, fra RISC e CISC, abbia avuto la meglio nelle loro decisioni. :cool:
Io aggiungerei anche che i compilatori per x86-64 tengono conto delle limitazioni di tale architettura e quindi generano sequenze di codice in cui si hanno meno pre-caricamenti di valori nei registri interni, privilegiano l'uso dei primi 8 registri, ecc. ecc.
Dipende dal compilatore, come già detto.

Ma riguardo all'uso dei registri non ci sono privilegi: vengono usati tutti e 16. Te ne accorgi subito disassemblando un qualunque binario x86-64.
Il problema è che per arrivare al backend Risc serve una "digestione" più lunga e complessa delle istruzioni CISC, cosa che a parità di tecnologia ha il suo peso. ;)
Senz'altro, ma bisogna vedere quanto sia questo peso. :p Come ho già detto altre volte, la parte legacy di x86/x86-64 ha subito poche modifiche dai tempi del PentiumPro (mi riferisco a livello micro-architetturale), e già da tempo non pesa molto, visto che ormai abbiamo chip con decine di miliardi di transistor.

Se l'obiettivo è quello di chip ridotti all'osso, allora c'è da alzare le mani: RISC-V vince a mani basse. Perfino AArch64 non potrebbe assolutamente competere, visto che si tratta di un'ISA enorme e complessa, seconda soltanto a x86-64, per l'appunto.
Con la differenza che un Risc HA più registri disponibili per precaricare valori e che i valori immediati nella maggior parte dei casi sono piccoli oppure è vantaggioso caricarli su un registro e utilizzare più volte il registro. ;)
SE il valore lo devi usare diverse volte. :p

Sul precaricamento vedi sopra.
Alpha è morta perchè Compaq ed HP avevano deciso di puntare tutto su Itanium.
A spingere MIPS sui server era SGI, che pure essa è passata ad Itanium e poi ha fatto la fine che ha fatto. MIPS è sopravvissuto nel settore embedded ma ormai è usato principalmente in roba legacy visto che ARM ha confinato MIPS e PowerPC a nicchie ridotte di mercato.
I produttori di cpu/microcontroller embedded per roba nuova a 32bit e 64bit propongono principalmente ARM.
PowerPC resiste come architettura legacy specialmente nell'automotive ma al massimo si vedono degli shrink dei core, niente roba davvero nuova.
Infatti è un'architettura morta. Soltanto i "neo-amighisti" continuano a starci attaccati col cordone ombelicale, anziché riconoscere che i PowerPC siano morti e sepolti, per passare ad altro.
Solo che IBM i POWER li propone solo per supercomputer e server di fascia alta, una nicchia molto remunerativa ma nicchia rimane.
Sì, ma ad alte prestazioni e con parecchi registri (l'ultima estensione SIMD ne conta ben 64). Solo che da tempo prende mazzate da x86-64. :D
Forse ho capito male, ma non mi sembra che sia un vero problema (almeno per ora) visto che al momento il grosso degli utilizzi pratici sono incentrati su core con estensioni IMAC (senza floating point) oppure roba embedded compilata ad hoc, quindi sarebbe una perdita di retrocompatibilità accettabile.
Non ci sarà una vera perdita di retrocompatibilità, per quanto già detto.
I processori che hanno già implementato le estensioni attualmente standardizzate continueranno a funzionare regolarmente, ma non potranno usare le future estensioni che rimapperanno alcuni opcode.
Viceversa, quelli che useranno le future estensioni non potranno far girare i binari attuali, perché dovranno usarne di compilati appositamente per le nuove estensioni.
In fin dei conti Risc-V non è UN unico set di istruzioni ma una famiglia di set di istruzioni.
Ed era una famiglia unita dalle estensioni già definite. Poi sono arrivate le sotto-estensioni...

C'è e ci sarà frammentazione, insomma: l'esatto opposto di quello che avevano sbandierato anni fa vantandosi del loro modello con le estensioni definite, e che adesso cercano malamente di nascondere sotto il tappeto ridefinendo a loro consumo il concetto di estensione, e creando una miriade di sotto-estensioni.

cdimauro
26-12-2020, 07:38
Da da arm-none-eabi-gdb.exe (x86):
0x0072652f (7) c7042458059200 MOV DWORD [ESP], 0x920558
0x00726536 (5) e8b5fbffff CALL 0x7260f0
0x0072653b (1) 90 NOP
0x0072653c (1) 90 NOP
0x0072653d (1) 90 NOP
0x0072653e (1) 90 NOP
0x0072653f (1) 90 NOP
Da da ffmpeg_64.exe (x86-64):
0x0000000140d554cb (8) 48c745b000000000 MOV QWORD [RBP-0x50], 0x0
0x0000000140d554d3 (5) e898faffff CALL 0x140d54f70
0x0000000140d554d8 (1) 90 NOP
0x0000000140d554d9 (1) 90 NOP
0x0000000140d554da (1) 90 NOP
0x0000000140d554db (1) 90 NOP
0x0000000140d554dc (1) 90 NOP
0x0000000140d554dd (1) 90 NOP
0x0000000140d554de (1) 90 NOP
0x0000000140d554df (1) 90 NOP
Vedi perché dico che GCC ottimizza (ancora!) male per x86/x64? Non sa nemmeno ottimizzare il padding delle istruzioni!!! :muro:

Questa schifezza fa aumentare in maniera consistente (perché il codice è PIENO di padding come quello, visto che i salti vengono allineati ai 16 byte) il numero di istruzioni/uop sia totali sia dinamicamente eseguite: ovvio che RISC-V guadagni su questo fronte... :rolleyes:

LMCH
29-12-2020, 00:52
wall of text versus wall of text

lol

In realtà stiamo facendo una gara tra algoritmi di generazione di wall of text. :sofico:

raxas
29-12-2020, 01:22
ma si potrebbe avere un riassuntino degli ultimi 9 o 10 post?
tipo due righe, strette strette

LMCH
29-12-2020, 02:15
Scusa, che c'entra il fatto che abbiano usato un P4? E' stato fatto soltanto per estrarre i dati delle ricerche, ma l'ABI usata è quella di x86-64, e non quella di x86, quindi register-based anziché stack-based, anche quando sono stati ridotti i registri a 12.

Ciò che era importante evidenziare è che il passaggio da 12 a 16 registri sostanzialmente non abbia inciso a livello prestazionale. :read:

Ti credo che sul P4 non incideva, rispetto ad esempio ad uno Skylake aveva meno parallelismo interno, quindi non poteva trarre vantaggio da codice pre-parallelizzato dal compilatore sfruttando i registri disponibili.


Se le istruzioni complesse "da rischizzare" sono tutte dello stesso tipo (con Mod/RM nel caso di x86/x86-64), il costo è irrisorio: si tratta di emettere uop di load/store oltre a quella di calcolo vero e proprio, e si applica sistematicamente a tutte le istruzioni di questo tipo (basta soltanto sapere che lo siano).
Certo che si può fare ... complicando il decoder istruzioni e delegando completamente al processore delle ottimizzazioni che possono essere migliorate dal compilatore. ;)


Opinabile. Anche coi primi processori a 32 bit ARM ha commesso degli errori, alcuni madornali: vedi il registro PC a soli 26 bit (quindi max 64MB di memoria indirizzabili), perché gli aveva aggiunto anche i bit del registro di flag/stato. Infatti è stata poi costretta a separarli con la v2 (se non erro), con una modifica all'ISA assolutamente non retro-compatibile. E' stata una visione davvero molto, molto miope.

ARM ha commesso degli errori anche con le estensioni (Thumb-EE e Jazilla che sono sostanzialmente morte, per citarne due abbastanza note).

In particolare Thumb e Thumb-2 sono l'esempio del pastrocchio che ARM ha realizzato quando ha definito la prima, mentre avrebbe potuto semplicemente prendere gli allora opcode ARM, rimuovere i 4 bit per l'esecuzione condizionale, lasciare la sola "condizione" (sempre vera) per l'esecuzione tout-court delle istruzioni, e riutilizzare le altre 15 configurazioni per definire in maniera pulita e semplice le istruzioni compatte a 16-bit. Invece è partita abbozzando malamente la prima, per poi metterci una pezza dopo con la seconda.

Ma anche qui ARM ha peccato, non avendo definito un'ISA compatta. Vedrai meglio dopo il perché, nel paper dei progettisti di RISC-V che riporterò.

Mica ho scritto che ARM non ha mai sbagliato :mbe:
Semplicemente potendo ripartire quasi da zero con il set d'istruzioni a 64bit ha potuto fare scelte che Intel ed AMD non si possono manco sognare ed ha potuto basare molte decisioni sui risultati concreti ottenuti dalle diverse implementazioni RISC e CISC realizzate fino a quel punto.


Non è così, e ripeto: è perché non hai seguito l'evoluzione di quest'architettura. Infatti diverse estensioni importanti sono già state ratificate, e pure da tempo.

La grossa mancanza riguarda le estensioni vettoriali, perché sono anni che gli accademici sbattono le corna alla ricerca di qualcosa di utilizzabile concretamente nella realtà, e che non li faccia soffrire troppo nello scardinare i loro ideali di "bellezza" dell'ISA che s'erano costruiti (i famigerati soli 3 formati di opcode sono un lontano ricordo, infatti: rimangono un proclama di pura propaganda).
E meno male che a questo comitato si sono uniti diversi ingegneri provenienti da aziende, che hanno i piedi ben piantati per terra, altrimenti sarebbero state ratificate delle colossali stupidaggini, come la definizione dinamica, a runtime, del tipo di dati utilizzato dai registri vettoriali (come da originale proposta, di diversi anni fa), che avrebbe fatto piangere lacrime amare a chi avrebbe dovuto implementarle...

Ci sono anche altre estensioni già ratificate da tempo. Se non vengono usate è proprio perché al momento le aziende più interessate sono quelle che operano in ambito embedded, a cui bastano quelle istruzioni.

Anzi, quella M e A erano e sono anche di troppo (su quella C mi sono già espresso), ed è proprio il motivo per cui sono poi nate delle loro versioni castrate, aumentando di fatto la frammentazione (visto che M ed A erano già state ratificate, e non si poteva più tornare indietro).

Non lo faranno mai perché per loro l'architettura base è stata definita ed è intoccabile, incluse le istruzioni di load/store. Ti posto già qui il paper di cui ti ho parlato prima, così puoi cominciare a prendere visione di cosa ne pensano e perché sono irremovibili nel difendere le loro scelte: The Renewed Case for the Reduced Instruction Set Computer: Avoiding ISA Bloat with Macro-Op Fusion for RISC-V (https://people.eecs.berkeley.edu/~krste/papers/EECS-2016-130.pdf)
Come puoi vedere già il titolo è tutto un programma, e il contenuto non si smentisce.

No. Vedi sopra. Istruzioni di load/store più avanzate sono state proposte da progetti esterni, come il PULP dell'università di Zurigo (l'estensione / progetto più diffuso, e che praticamente è diventato uno standard parallelo), ma rimarranno non standardizzate / ratificate dal comitato RISC-V.
Sarà che appartengo al lato oscuro dell'informatica :Perfido: (quello embedded :stordita: ) ma non vedo un gran problema riguardo la "frammentazione" lato embedded visto che quello che hai descritto crea meno problemi che con gli ARM, MIPS, x86, x86-64, PowerPC ed altre architetture con evoluzioni più "contorte".

Inoltre proprio per la natura aperta di Risc V alla fine ci sarà una selezione naturale sul campo come è avvenuto con i S.O. open source dove quello attualmente più diffuso (Linux) decisamente non è il più "accademicamente puro".



Francamente è una ricerca che lascia il tempo che trova per le modalità utilizzate per estrarre l'elenco delle istruzioni, visto che fanno uso del comando objdump, che per limiti intrinseci disassembla anche blocchi dati, falsando le statistiche.
E' il motivo per cui, ad esempio, trovi un così elevato numero di istruzioni ADD, come puoi vedere anche dal loro sito (http://x86instructionpop.com) che consente di consultare il database con le informazioni raccolte. Infatti la ADD è così inflazionata perché si tratta dell'istruzione avente 0x00 come uno dei suoi opcode: dato estremamente comune negli eseguibili, come certamente sai.

Se ci fai caso, non ho parlato delle ADD, ma delle MOV e delle modalità di indirizzamento.
E guardacaso ....


Altri paper mostrano risultati abbastanza diversi:
https://www.strchr.com/x86_machine_code_statistics
http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=23D681327E0B647562223062ED5E0833?doi=10.1.1.407.5071&rep=rep1&type=pdf
http://people.umass.edu/cmutigwe/research/ICETCIT-2013/Instruction%20Set%20Usage%20Analysis%20for%20Application-Specific%20Systems%20Design.pdf
e soprattutto il paper degli autori di RISC-V (https://people.eecs.berkeley.edu/~krste/papers/EECS-2016-130.pdf) che ti ho già passato che, sebbene sia ovviamente (fortemente) "biased", mostra dei dati grezzi che sono molti utili di per sé, oltre al fatto che riporta esclusivamente istruzioni reali, e soprattutto le statistiche sono di quelle dinamiche (quindi tutte e soltanto quelle eseguite realmente in quelle applicazioni) e non statiche (quelle del paper che hai postato).

... mi sembra che i paper che hai citato a tua volta contengano sostanzialmente dati concordanti riguardo l'uso delle MOV e delle modalità di indirizzamento.


Tra l'altro anche il bouquet di applicazioni che ho usato per le mie statistiche (anche statiche, sia chiaro) mostra un quadro diverso da quello del tuo paper, e più in linea con gli altri paper. Inoltre non ho disassemblato roba a caso, ma sono partito dall'entry point dell'eseguibile, e ho disassemblato tutto ciò che era possibile, tracciando le istruzioni di salto. Quindi niente spazzatura/dati grezzi disassemblati come istruzioni. Le statistiche le trovi nella mia ultima serie di articoli su Appunti Digitali, dove puoi vedere i dati della beta pubblica di Photoshop CS6, sia a 32 sia a 64-bit.

Pure nelle tue analisi risulta che x86-64 ha una lunghezza di istruzioni media di 4,3 (maggiore di 4 byte) e che le percentuali di utilizzo delle modalità di indirizzamento più complesse sono estremamente basse rispetto a quelle più comuni implementate anche da Risc V. :vicini:


Ciò precisato, t'invito a leggere il paper che ho postato, e così vedrai che, sebbene la modalità d'indirizzamento indicizzata non sia così diffusa, è molto usata (dinamicamente) in alcune applicazioni ed è il motivo per cui RISC-V ha un crollo a livello prestazionale, di cui gli autori propongo una soluzione (macro-op fusion) per alleviare il problema.

Ed il problema sarebbe ? :mbe:
Leggendo quella paper sostanzialmente parlano di soluzioni implementative per architetture "ad alte prestazioni" che permettono di far girare lo stesso codice anche su architetture più semplici/spartane.



Come vedi usare immediati porta dei vantaggi, perché NON si usano registri, e quindi non si applica il limite del register renamer. ;)
Questo sugli x86-64 perchè sono maggiormente limitati quanto a registri disponibili, quindi le implementazioni architetturali cercano di ovviare a questo in altri modi.


In parte ho risposto sopra. Ma, contrariamente a quello che pensi, il numero di istruzioni (dinamicamente) eseguite da x86-64 è sempre minore a quello di x86, ARMv7, ARMv8, RISC-V a 64 bit in versione G e GC, come puoi vedere dal paper che ho postato.
Paper che però è viziato, visto che per RISC-V GC hanno "casualmente" messo soltanto il numero di micro-op "fused", e non il numero di istruzioni vere e proprie. Però per il resto i dati sono affidabili. ARMv8 fa molto bene, e persino meglio di RISC-V GC "micro-op fused", ma a livello di numero di istruzioni eseguite rimane comunque sotto a x86-64.

Non era per niente "casuale", visto che, nelle attuali implementazioni di Risc V, se non erro che le istruzioni "vere e proprie" (non fused) hanno una corrispondenza 1:1 con le micro-op.


In sintesi: nonostante x86-64 sia una brutta architettura per quanto riguarda la struttura degli opcode e il forzato usato di prefissi (specialmente rispetto a x86), non ne esce affatto male confrontata con architetture nuove di pacca, che non hanno dovuto portarsi dietro alcun legacy.
Non ne esce affatto male, ma non è la soluzione per tutti i problemi, non è un caso se pure i militari statunitensi sono molto interessati a Risc V.
Risc V di suo è ben lontano dall'essere perfetto, anzi, basta che sia "abbastanza buono" in settori dove gli x86 e gli x86-64 sono improponibili e dove l'ARM comporta costi aggiuntivi a livello di IP o limitazioni su cosa si può fare senza che ti saltino addosso gli avvocati di ARM Ltd.

LMCH
29-12-2020, 02:26
Da da arm-none-eabi-gdb.exe (x86):
0x0072652f (7) c7042458059200 MOV DWORD [ESP], 0x920558
0x00726536 (5) e8b5fbffff CALL 0x7260f0
0x0072653b (1) 90 NOP
0x0072653c (1) 90 NOP
0x0072653d (1) 90 NOP
0x0072653e (1) 90 NOP
0x0072653f (1) 90 NOP
Da da ffmpeg_64.exe (x86-64):
0x0000000140d554cb (8) 48c745b000000000 MOV QWORD [RBP-0x50], 0x0
0x0000000140d554d3 (5) e898faffff CALL 0x140d54f70
0x0000000140d554d8 (1) 90 NOP
0x0000000140d554d9 (1) 90 NOP
0x0000000140d554da (1) 90 NOP
0x0000000140d554db (1) 90 NOP
0x0000000140d554dc (1) 90 NOP
0x0000000140d554dd (1) 90 NOP
0x0000000140d554de (1) 90 NOP
0x0000000140d554df (1) 90 NOP
Vedi perché dico che GCC ottimizza (ancora!) male per x86/x64? Non sa nemmeno ottimizzare il padding delle istruzioni!!! :muro:

Questa schifezza fa aumentare in maniera consistente (perché il codice è PIENO di padding come quello, visto che i salti vengono allineati ai 16 byte) il numero di istruzioni/uop sia totali sia dinamicamente eseguite: ovvio che RISC-V guadagni su questo fronte... :rolleyes:

Scusa ma, quale versione di GCC è stata usata e con quali switch di compilazione ? :mbe:
Chiedo questo perchè mi sembra che versioni relativamente recenti di GCC ottimizzino in modo decisamente migliore di quel che si vede sopra, usando anche solo -O2 o -O3 (a meno che non vengano forzati alignment balordi con le -falign-XXXX).

cdimauro
29-12-2020, 09:23
ma si potrebbe avere un riassuntino degli ultimi 9 o 10 post?
tipo due righe, strette strette
Anche una soltanto: è una disquisizione su RISC vs CISC, con particolare focus su RISC-V/ARM da un lato e x86/x86-64 dall'altro. :fagiano:
Ti credo che sul P4 non incideva, rispetto ad esempio ad uno Skylake aveva meno parallelismo interno, quindi non poteva trarre vantaggio da codice pre-parallelizzato dal compilatore sfruttando i registri disponibili.
Rispetto a Skylake fa peggio, ma non era messo affatto male in termini di istruzioni eseguite, e quindi di parallelismo:
https://www.anandtech.com/show/1611/6

Ben 5 porte dedicate alle sole istruzioni intere/scalari, di cui due porte/ALU con throughput doppio (praticamente è come se fossero due porte ciascuna).
Certo che si può fare ... complicando il decoder istruzioni
Poca roba, come già detto. E' di gran lunga più complicato il fatto di decodificare le istruzioni di per sé, che quello di generare un'uop anziché un'altra, o al massimo 2 uop per gestire le modalità d'indirizzamento più complesse.
e delegando completamente al processore delle ottimizzazioni che possono essere migliorate dal compilatore. ;)
Ne ho già parlato: nei fatti l'ottimizzazione del compilatore non serve a nulla, codice reale alla mano. Vedi i frammenti che sono stati riportati nel paper.

Lo scheduling di load & op è certamente utile, e anzi necessario, per i RISC con micro-architettura in-order.
Mica ho scritto che ARM non ha mai sbagliato :mbe:
Semplicemente potendo ripartire quasi da zero con il set d'istruzioni a 64bit ha potuto fare scelte che Intel ed AMD non si possono manco sognare ed ha potuto basare molte decisioni sui risultati concreti ottenuti dalle diverse implementazioni RISC e CISC realizzate fino a quel punto.
Ehm, no, decisamente e lo posso dire con assoluta certezza: AMD (perché è stata la prima a farlo) avrebbe potuto tirare fuori un'ISA a 64-bit togliendo di mezzo quasi tutto il legacy di IA-32/x86, e semplificando enormemente frontend/decoder e backend, pur mantenendo una vasta compatibilità a livello di codice sorgente (anche il 100%, per la verità, mentre con x86-64 la retro-compatibilità è ridotta).
Il tutto con innegabili benefici su tutti i fronti: dal minor numero di transistor utilizzati, ai consumi più ridotti, e infine alle prestazioni nettamente migliori.

In buon sostanza (!) con x86-64 avrebbe potuto fare sostanzialmente quello che ARM ha fatto con AArch64/ARMv8 (ma con risultati nettamente migliori). Solo che AMD ha preferito mettere una semplice e veloce pezza su x86, per non perdere tempo a riprogettare una soluzione migliore.
Se ci fai caso, non ho parlato delle ADD, ma delle MOV e delle modalità di indirizzamento.
E guardacaso ....

... mi sembra che i paper che hai citato a tua volta contengano sostanzialmente dati concordanti riguardo l'uso delle MOV e delle modalità di indirizzamento.

Pure nelle tue analisi risulta che x86-64 ha una lunghezza di istruzioni media di 4,3 (maggiore di 4 byte) e che le percentuali di utilizzo delle modalità di indirizzamento più complesse sono estremamente basse rispetto a quelle più comuni implementate anche da Risc V. :vicini:
Sì, sono basse a livello di numero di istruzioni statiche che le usano, ma sono molte di più in quelle dinamicamente eseguite, che poi sono quelle che fanno i numeri nei benchmark.

Il punto è proprio questo.
Ed il problema sarebbe ? :mbe:
Leggendo quella paper sostanzialmente parlano di soluzioni implementative per architetture "ad alte prestazioni" che permettono di far girare lo stesso codice anche su architetture più semplici/spartane.
Sono workaround/pezze, peraltro limitate, che complicano ulteriormente sia il frontend sia il backend.
Questo sugli x86-64 perchè sono maggiormente limitati quanto a registri disponibili, quindi le implementazioni architetturali cercano di ovviare a questo in altri modi.
Non è questione di registri limitati: è che diverse istruzioni CISC consentono di specificare un immediato, che viene memorizzato direttamente nella uop e usato immediatamente anziché andare a pesare sul register file & sul register renamer.

Questa è un'intrinseca caratteristica dei CISC, che prescinde dal numero di registri. Infatti la mia architettura ne ha ben 32 GP, e consente ugualmente di specificare valori immediati (estendendone anche di molto l'utilizzo rispetto a x86/x86-64).
Non era per niente "casuale",
Lo era, lo era, ma forse non ci siamo capiti.

Nel paper hanno messo soltanto le uop fused, perché sono di numero minore rispetto al numero di istruzioni, proprio perché sono fused: ossia derivano da due istruzioni che sono state fuse. Ed è, appunto, il motivo per cui hanno messo soltanto il dato delle uop fused, anziché il numero di istruzioni, come hanno fatto con tutte le altre architetture. E' un'omissione volontaria, insomma, per nascondere un dato scomodo.
visto che, nelle attuali implementazioni di Risc V, se non erro che le istruzioni "vere e proprie" (non fused) hanno una corrispondenza 1:1 con le micro-op.
Sì. Non ce l'hanno perché sono tutte istruzioni semplici, per cui non serve dividerle in uop più semplici.
Non ne esce affatto male, ma non è la soluzione per tutti i problemi,
No, certamente. Inoltre c'è e si può fare molto meglio, persino rimanendo in ambito CISC.
non è un caso se pure i militari statunitensi sono molto interessati a Risc V.
Risc V di suo è ben lontano dall'essere perfetto, anzi, basta che sia "abbastanza buono" in settori dove gli x86 e gli x86-64 sono improponibili e dove l'ARM comporta costi aggiuntivi a livello di IP o limitazioni su cosa si può fare senza che ti saltino addosso gli avvocati di ARM Ltd.
Ma infatti è proprio questo il vantaggio nonché il motivo per cui molti abbracceranno RISC-V: niente licenze da pagare.
Scusa ma, quale versione di GCC è stata usata e con quali switch di compilazione ? :mbe:
Chiedo questo perchè mi sembra che versioni relativamente recenti di GCC ottimizzino in modo decisamente migliore di quel che si vede sopra,
I GCC usati per quelle due sono vecchi (GCC 5.3.1 20151207 e gcc 7.1.0), ma la situazione non cambia con un recente GCC (gcc 9.3.1 (GCC) 20200328):
0x0000000140e7ce18 (7) 488d0de1a08802 LEA RCX, [RIP+0x288a0e1]
0x0000000140e7ce1f (5) e89cfaffff CALL 0x140e7c8c0
0x0000000140e7ce24 (1) 90 NOP
0x0000000140e7ce25 (1) 90 NOP
0x0000000140e7ce26 (1) 90 NOP
0x0000000140e7ce27 (1) 90 NOP
0x0000000140e7ce28 (1) 90 NOP
0x0000000140e7ce29 (1) 90 NOP
0x0000000140e7ce2a (1) 90 NOP
0x0000000140e7ce2b (1) 90 NOP
0x0000000140e7ce2c (1) 90 NOP
0x0000000140e7ce2d (1) 90 NOP
0x0000000140e7ce2e (1) 90 NOP
0x0000000140e7ce2f (1) 90 NOP
usando anche solo -O2 o -O3 (a meno che non vengano forzati alignment balordi con le -falign-XXXX).
Per quest'ultimo GCC ho trovato questo nell'eseguibile:
configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libsrt --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-ffnvcodec --enable-cuda-llvm --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt --enable-amf

Trattandosi di FFMPEG mi aspetto che sia compilato almeno con -O2.

amd-novello
29-12-2020, 12:16
ma si potrebbe avere un riassuntino degli ultimi 9 o 10 post?
tipo due righe, strette strette

mission impossible

LMCH
06-01-2021, 05:39
Innanzitutto chiedo scusa per non aver risposto prima, avevo perso di vista questa discussione.


Rispetto a Skylake fa peggio, ma non era messo affatto male in termini di istruzioni eseguite, e quindi di parallelismo:
https://www.anandtech.com/show/1611/6

Ben 5 porte dedicate alle sole istruzioni intere/scalari, di cui due porte/ALU con throughput doppio (praticamente è come se fossero due porte ciascuna).

Le due ALU con throughput doppio avevano ampiezza dimezzata rispetto alla dimensione massima di un registro intero
(16bit nelle prime versioni dei Pentium 4 che supportavano solo le istruzioni x86, 32bit nelle versioni con supporto delle x86-64) e non è che potessero processare due istruzioni per ciclo.


Poca roba, come già detto. E' di gran lunga più complicato il fatto di decodificare le istruzioni di per sé, che quello di generare un'uop anziché un'altra, o al massimo 2 uop per gestire le modalità d'indirizzamento più complesse.

Rimane il fatto che la decodifica è più complessa rispetto ad un formato più semplice e poi le eventuali due uOP sono in sequenza stretta, con minori opportunità di esecuzione senza attese dovute alla dipendenza della seconda dalla prima.


Ne ho già parlato: nei fatti l'ottimizzazione del compilatore non serve a nulla, codice reale alla mano. Vedi i frammenti che sono stati riportati nel paper.

Se ci sono pochi registri visibili al programmatore/compilatore è ovvio che è più difficile schedulare in modo ottimale.


Lo scheduling di load & op è certamente utile, e anzi necessario, per i RISC con micro-architettura in-order.

Torna dannatamente utile con qualsiasi cpu in cui ci sono pipeline e cache più lente del core.


Ehm, no, decisamente e lo posso dire con assoluta certezza: AMD (perché è stata la prima a farlo) avrebbe potuto tirare fuori un'ISA a 64-bit togliendo di mezzo quasi tutto il legacy di IA-32/x86, e semplificando enormemente frontend/decoder e backend, pur mantenendo una vasta compatibilità a livello di codice sorgente (anche il 100%, per la verità, mentre con x86-64 la retro-compatibilità è ridotta).
Il tutto con innegabili benefici su tutti i fronti: dal minor numero di transistor utilizzati, ai consumi più ridotti, e infine alle prestazioni nettamente migliori.

In buon sostanza (!) con x86-64 avrebbe potuto fare sostanzialmente quello che ARM ha fatto con AArch64/ARMv8 (ma con risultati nettamente migliori). Solo che AMD ha preferito mettere una semplice e veloce pezza su x86, per non perdere tempo a riprogettare una soluzione migliore.

C'e' una differenza fondamentale: AMD doveva uscire con una cpu a 64bit che doveva per forza essere retrocompatibile con i set di istruzioni x86 a 32bit ed a 16bit, con tutto il bagaglio delle varie estensioni x87, MMX, ed SSE2 ed al tempo stesso avere prestazioni più elevate o uguali alle cpu x86 a 32bit sue e della concorrenza.
Il compromesso migliore è quello che ha scelto (anche cosiderando cosa si poteva implementare con i processi produttivi disponibili in quel periodo).

ARM invece fino a quel momento con AArch32 da almeno più di un decennio aveva privilegiato i bassi consumi rispetto alle prestazioni e quindi era decisamente molto meno problematico avere un set di istruzioni a 64bit "tutto nuovo" e con buone prestazioni nella modalità a 32bit (ma anche li si è rivelato necessario mantenere alcune similitudini a livello di modalità di indirizzamento e "mappatura" sulle unità di esecuzione)


Sì, sono basse a livello di numero di istruzioni statiche che le usano, ma sono molte di più in quelle dinamicamente eseguite, che poi sono quelle che fanno i numeri nei benchmark.


In pratica non è che sia così frequente indirizzare un elemento di un array (di interi, float o puntatori) contenuto dentro una struttura/record referenziata da un puntatore, usando indici che cambiano in modo non predicibile.

Di solito se c'e' di mezzo un loop, a parte l'indicizzazione iniziale all'inizializzazione del ciclo, le indicizzazioni ripetute si possono rifattorizzare in incrementi/decrementi di puntatori ottenendo codice che gira più efficientemente anche sugli x86 ed x86-64.

Inoltre se l'indicizzazione non è per elementi che sono potenze di due, si finisce con l'usare l'indirizzamento indiretto o base+offset dopo aver fatto i calcoli di indicizzazione con somme/shift/moltiplicazioni.

Se ne può fare a meno se si vuole un set d'istruzioni "base" che sia il più spartano possibile in termini di rapporto costo/prestazioni.
Infatti sebbene ARM implementi modalità di indirizzamento "complesse" per le load/store, nelle estensioni thumb queste si riducono a base+offset (dove offset può essere una costante oppure un registro) e push/pop per lo stack pointer.


Sono workaround/pezze, peraltro limitate, che complicano ulteriormente sia il frontend sia il backend.

La cosa da non dimenticare è che sono OPZIONALI, uno può scegliere di implementare un decoder ridotto all'osso oppure uno che "comprime" le istruzioni in macroOP per avere maggiori prestazioni.
Inoltre per come sono codificate le istruzioni Risc V la cosa rimane meno complicata della decodifica delle istruzioni x86-64 ... e questo considerando pure che le attuali istruzioni Risc V sono a 16bit oppure 32bit "senza fusione" ma che le specifiche prevedono già istruzioni lunghe 48, 64, .. 176 bit (più un prefisso per ulteriori istruzioni a 192bit o superiori). :sofico:


Ma infatti è proprio questo il vantaggio nonché il motivo per cui molti abbracceranno RISC-V: niente licenze da pagare.

Il vantaggio principale di Risc V non sta nel non pagare licenze, ma nel poter cambiare il fornitore del core liberamente; ci sono già adesso core Risc V utilizzabili solo con regolare licenza, senza contare le IP legate a circuiti specifici se si vogliono realizzarne implementazioni particolarmente performanti) e nell'avere un ecosistema di tool software ed hardware che non sia sotto il controllo di un singolo produttore o rivenditore di IP.


I GCC usati per quelle due sono vecchi (GCC 5.3.1 20151207 e gcc 7.1.0), ma la situazione non cambia con un recente GCC (gcc 9.3.1 (GCC) 20200328):
0x0000000140e7ce18 (7) 488d0de1a08802 LEA RCX, [RIP+0x288a0e1]
0x0000000140e7ce1f (5) e89cfaffff CALL 0x140e7c8c0
0x0000000140e7ce24 (1) 90 NOP
0x0000000140e7ce25 (1) 90 NOP
0x0000000140e7ce26 (1) 90 NOP
0x0000000140e7ce27 (1) 90 NOP
0x0000000140e7ce28 (1) 90 NOP
0x0000000140e7ce29 (1) 90 NOP
0x0000000140e7ce2a (1) 90 NOP
0x0000000140e7ce2b (1) 90 NOP
0x0000000140e7ce2c (1) 90 NOP
0x0000000140e7ce2d (1) 90 NOP
0x0000000140e7ce2e (1) 90 NOP
0x0000000140e7ce2f (1) 90 NOP

Per quest'ultimo GCC ho trovato questo nell'eseguibile:
configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libsrt --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-ffnvcodec --enable-cuda-llvm --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt --enable-amf

Trattandosi di FFMPEG mi aspetto che sia compilato almeno con -O2.

Ah! Capito, la cosa è legata alle ottimizzazioni -falign-functions, -falign-labels, -falign-loops e -falign-jumps

possono essere attivate con i valori di default oppure si può optare per un tuning ad hoc per ridurre la generazione di un numero eccessivo di NOP di allineamento.

Ad esempio:

-falign-labels
-falign-labels=n
-falign-labels=n:m
-falign-labels=n:m:n2
-falign-labels=n:m:n2:m2

n "allineamento primario" è il numero di byte a cui allineare le destinazioni dei branch.

m è il "limite di sfrido primario", ovverosia si generano NOP di allineamento ad n byte solo se si generano meno di m NOP.

n2 "allineamento secondario" è il numero di byte a cui allineare le destinazioni dei branch se l'allineamento primario fallisce a causa di sfrido superiore ad m.

m2 è il "limite di sfrido secondario", ovverosia si generano NOP di allineamento ad n2 byte solo se si generano meno di m2 NOP.

Es:
-falign-labels=32:5:16:3

Significa allinea i target dei branch a 32byte se questo richiede al massimo 4 NOP
oppure allineali a 16 byte se questo richiede al massimo 2 NOP
oppure non tentare di allineare in tutti gli altri casi

cdimauro
06-01-2021, 09:10
Innanzitutto chiedo scusa per non aver risposto prima, avevo perso di vista questa discussione.
Tranquillo: pure io rispondo quando posso. :p
Le due ALU con throughput doppio avevano ampiezza dimezzata rispetto alla dimensione massima di un registro intero
(16bit nelle prime versioni dei Pentium 4 che supportavano solo le istruzioni x86, 32bit nelle versioni con supporto delle x86-64) e non è che potessero processare due istruzioni per ciclo.
Perché no?
Rimane il fatto che la decodifica è più complessa rispetto ad un formato più semplice
Certamente, ma il costo è fisso: la decodifica per le modalità dell'indirizzamento si fa allo stesso modo, che tu debba farlo per una o centinaia di istruzioni. Il punto è questo.
e poi le eventuali due uOP sono in sequenza stretta, con minori opportunità di esecuzione senza attese dovute alla dipendenza della seconda dalla prima.
Lasciamo che sia la logica OoO a prendersene carico, che è proprio per queste cose che è nata.
Se ci sono pochi registri visibili al programmatore/compilatore è ovvio che è più difficile schedulare in modo ottimale.
Non è così. Se guardassi il codice reale, come ti avevo già suggerito, vedresti che è raro incontrare situazioni in cui ti puoi permettere di schedulare le istruzioni di load a debita distanza da quando verranno poi utilizzati quei dati.
Torna dannatamente utile con qualsiasi cpu in cui ci sono pipeline e cache più lente del core.
Vero, ma è anche il motivo per cui siamo arrivati alle microarchitetture OoO, che risolvono in maniera semplice ed elegante il problema.

Il problema grosso ce l'avevano quelle in-order, come avevo già datto. E lì effettivamente con pochi registri hai difficoltà.
Ma è anche vero che, in questo caso, un'ISA CISC consente di evitare l'uso di registri addizionali (con annesse dipendenze), e inoltre avendo calcolo dell'indirizzo già integrato in uno (o più, per quelli più complicati) stage della pipeline il processore può immediatamente procedere con la lettura (e meglio ancora per la scrittura) del dato mentre in parallelo procede con la lettura degli altri registri, e quando il dato è pronto (in genere la cache L1 dati nei vecchi processori in-order è di 2-3 cicli, essendo di dimensioni ridotte) può calcolare il tutto. Non è certo un caso che i CISC in-order abbiano avuto prestazioni migliori rispetto a equivalenti RISC, come abbiamo già visto. ;)
C'e' una differenza fondamentale: AMD doveva uscire con una cpu a 64bit che doveva per forza essere retrocompatibile con i set di istruzioni x86 a 32bit ed a 16bit, con tutto il bagaglio delle varie estensioni x87, MMX, ed SSE2 ed al tempo stesso avere prestazioni più elevate o uguali alle cpu x86 a 32bit sue e della concorrenza.
Il compromesso migliore è quello che ha scelto (anche cosiderando cosa si poteva implementare con i processi produttivi disponibili in quel periodo).

ARM invece fino a quel momento con AArch32 da almeno più di un decennio aveva privilegiato i bassi consumi rispetto alle prestazioni e quindi era decisamente molto meno problematico avere un set di istruzioni a 64bit "tutto nuovo" e con buone prestazioni nella modalità a 32bit (ma anche li si è rivelato necessario mantenere alcune similitudini a livello di modalità di indirizzamento e "mappatura" sulle unità di esecuzione)
Con Aarch64 ARM ha conservato piena compatibilità con l'ISA a 32 bit, tant'è che possono girare applicazioni a 64 e 32 bit assieme (ovviamente per i processori che mettono a disposizione entrambe le ISA).
Idem con x86-64 che consente di far girare le vecchie applicazioni x86 assieme a quelle native.

Ovviamente entrambe le ISA a 64 bit sono incompatibili con le precedenti a 32-bit della stessa famiglia, e richiedono ricompilazioni delle applicazioni, nonché adattamenti nel caso di integrazione di assembly nel codice.

Come vedi non c'è proprio alcuna differenza. E' soltanto AMD che ha avuto fretta di tirare fuori un'ISA a 64 bit, mettendo una mala pezza su x86.
In pratica non è che sia così frequente indirizzare un elemento di un array (di interi, float o puntatori) contenuto dentro una struttura/record referenziata da un puntatore, usando indici che cambiano in modo non predicibile.

Di solito se c'e' di mezzo un loop, a parte l'indicizzazione iniziale all'inizializzazione del ciclo, le indicizzazioni ripetute si possono rifattorizzare in incrementi/decrementi di puntatori ottenendo codice che gira più efficientemente anche sugli x86 ed x86-64.

Inoltre se l'indicizzazione non è per elementi che sono potenze di due, si finisce con l'usare l'indirizzamento indiretto o base+offset dopo aver fatto i calcoli di indicizzazione con somme/shift/moltiplicazioni.
Tutte cose che richiedono più istruzioni, e quindi inficiano sulle prestazioni nonché la densità di codice (che inficia anch'essa sulle prestazioni).

Infatti è proprio il motivo per cui, non a caso, RISC-V perde molto in quel benchmark. ;)
Se ne può fare a meno se si vuole un set d'istruzioni "base" che sia il più spartano possibile in termini di rapporto costo/prestazioni.
Infatti sebbene ARM implementi modalità di indirizzamento "complesse" per le load/store, nelle estensioni thumb queste si riducono a base+offset (dove offset può essere una costante oppure un registro) e push/pop per lo stack pointer.
Ma infatti il motivo è esattamente quello: hanno voluto un'ISA più spartana. E quindi ne pagano le conseguenze.

There's no free lunch... ;)
La cosa da non dimenticare è che sono OPZIONALI, uno può scegliere di implementare un decoder ridotto all'osso oppure uno che "comprime" le istruzioni in macroOP per avere maggiori prestazioni.
Assolutamente sì, concordo.
Inoltre per come sono codificate le istruzioni Risc V la cosa rimane meno complicata della decodifica delle istruzioni x86-64 ... e questo considerando pure che le attuali istruzioni Risc V sono a 16bit oppure 32bit "senza fusione" ma che le specifiche prevedono già istruzioni lunghe 48, 64, .. 176 bit (più un prefisso per ulteriori istruzioni a 192bit o superiori). :sofico:
Ah, non dirlo a me, che lo so bene. :D

Come lo sanno molto bene anche i progettisti di RISC-V, che però nei loro talk di pura propaganda che fanno alle conferenze mettono nelle slide che x86/x64 sia un'ISA a lunghezza variabile (sacrilegio!) e la cui lunghezza delle istruzioni arrivi a ben 15 byte (quasi un'intera linea di fetch!!). Squallidi ipocriti... :rolleyes:
Il vantaggio principale di Risc V non sta nel non pagare licenze, ma nel poter cambiare il fornitore del core liberamente; ci sono già adesso core Risc V utilizzabili solo con regolare licenza, senza contare le IP legate a circuiti specifici se si vogliono realizzarne implementazioni particolarmente performanti) e nell'avere un ecosistema di tool software ed hardware che non sia sotto il controllo di un singolo produttore o rivenditore di IP.
Beh, sì, la mancanza di licenze porta pure a questo come conseguenza.
Ah! Capito, la cosa è legata alle ottimizzazioni -falign-functions, -falign-labels, -falign-loops e -falign-jumps

possono essere attivate con i valori di default oppure si può optare per un tuning ad hoc per ridurre la generazione di un numero eccessivo di NOP di allineamento.

Ad esempio:

-falign-labels
-falign-labels=n
-falign-labels=n:m
-falign-labels=n:m:n2
-falign-labels=n:m:n2:m2

n "allineamento primario" è il numero di byte a cui allineare le destinazioni dei branch.

m è il "limite di sfrido primario", ovverosia si generano NOP di allineamento ad n byte solo se si generano meno di m NOP.

n2 "allineamento secondario" è il numero di byte a cui allineare le destinazioni dei branch se l'allineamento primario fallisce a causa di sfrido superiore ad m.

m2 è il "limite di sfrido secondario", ovverosia si generano NOP di allineamento ad n2 byte solo se si generano meno di m2 NOP.

Es:
-falign-labels=32:5:16:3

Significa allinea i target dei branch a 32byte se questo richiede al massimo 4 NOP
oppure allineali a 16 byte se questo richiede al massimo 2 NOP
oppure non tentare di allineare in tutti gli altri casi
Sì, ma così è anche peggio: è un inferno!

Il codice che ho riportato prima dimostra che il compilatore ha ottimizzato per l'allineamento dopo i salti, aggiungendo le necessarie istruzioni di padding. Ed è una cosa giustissima, che ci aspetta proprio per questo.

Il problema è che il padding che emette è a dir poco orribile e, ammazza le prestazioni visto che c'è una valanga di NOP, che anche se non fanno niente... devono essere eseguite (nonché conteggiate)!

La soluzione a questo problema esiste da eoni, ed è molto semplice: in base al numero di byte di padding (che va da 1 a 15), è sufficiente utilizzare UNA apposita istruzione di NOP della lunghezza richiesta. Come fanno gli altri compilatori. Sì, perché x86/x64 hanno NOP di dimensione diversa. In questo modo il padding viene aggiunto correttamente, e a livello di esecuzione il processore esegue UNA sola istruzione NOP. E vissero tutti felici e contenti...

E il tutto senza richiedere strane e oscure ulteriori opzioni di compilazione.

LMCH
08-01-2021, 01:31
Perché no?

Perchè anche se le ALU dei Pentium 4 giravano al doppio del clock, ricevevano una singola microistruzione per ciclo di clock che agiva su un singolo registro.
Se ricordo bene, il vantaggio che davano era in termini di area e di riduzione del clock skew nell'ALU.


Certamente, ma il costo è fisso: la decodifica per le modalità dell'indirizzamento si fa allo stesso modo, che tu debba farlo per una o centinaia di istruzioni. Il punto è questo.

E' un costo che si fa sentire a livello di complessità di implementazione e del maggior numero di interdipendenze per microistruzione (a meno che non la si scomponga in due microistruzioni, vanificando l'effettivo vantaggio in termini di prestazioni finali).


Lasciamo che sia la logica OoO a prendersene carico, che è proprio per queste cose che è nata.


L'esecuzione out-of-order non è magica, aiuta tantissimo ma più di tanto non può fare.
Basta pensare che ad esempio è possibile implementare delle stack machine con esecuzione out-of-order in teoria fantastiche come compattezza del codice, ma che poi stressano parecchio le unità di load/store.


Non è così. Se guardassi il codice reale, come ti avevo già suggerito, vedresti che è raro incontrare situazioni in cui ti puoi permettere di schedulare le istruzioni di load a debita distanza da quando verranno poi utilizzati quei dati.

Ma è più frequente schedularle "più distanti", guadagnando cicli di clock utili.


Vero, ma è anche il motivo per cui siamo arrivati alle microarchitetture OoO, che risolvono in maniera semplice ed elegante il problema.

Il problema grosso ce l'avevano quelle in-order, come avevo già datto. E lì effettivamente con pochi registri hai difficoltà.


Difatti in un sacco di applicazioni si usano ancora architetture in-order in cui ha più senso un Risc che un x86 proprio perchè si possono ottenere buone prestazioni con un implementazione relativamente semplice.


Ma è anche vero che, in questo caso, un'ISA CISC consente di evitare l'uso di registri addizionali (con annesse dipendenze), e inoltre avendo calcolo dell'indirizzo già integrato in uno (o più, per quelli più complicati) stage della pipeline il processore può immediatamente procedere con la lettura (e meglio ancora per la scrittura) del dato mentre in parallelo procede con la lettura degli altri registri, e quando il dato è pronto (in genere la cache L1 dati nei vecchi processori in-order è di 2-3 cicli, essendo di dimensioni ridotte) può calcolare il tutto. Non è certo un caso che i CISC in-order abbiano avuto prestazioni migliori rispetto a equivalenti RISC, come abbiamo già visto. ;)

Dipende da cosa si intende per "equivalenti", stesso processo produttivo e stesso numero di gate ? E quanto potevano rispettivamente salire di clock ?


Con Aarch64 ARM ha conservato piena compatibilità con l'ISA a 32 bit, tant'è che possono girare applicazioni a 64 e 32 bit assieme (ovviamente per i processori che mettono a disposizione entrambe le ISA).
Idem con x86-64 che consente di far girare le vecchie applicazioni x86 assieme a quelle native.

Quello che cambia è il costo di tale retrocompatibilità. ;)
ARM A32 non aveva vincoli di retrocompatibilità quando è nato e come formato delle istruzioni era semplice e regolare, mentre l' 80386 doveva essere retrocompatibile con l' 80286 che a sua volta doveva essere retrocompatibile con l'8086 che a sua volta fu pensato per facilitare il porting di applicazioni scritte in assembly per l'8080 se ricordo bene.


Come vedi non c'è proprio alcuna differenza. E' soltanto AMD che ha avuto fretta di tirare fuori un'ISA a 64 bit, mettendo una mala pezza su x86.


Ricorda che Intel aveva già provato a sganciarsi da x86 proprio per i limiti di tale architettura per poi ritornare sui suoi passi ed aggiungere un ennesima pezza ad x86.
Aveva provato a farlo con gli iAPX 432 per poi abbandonarlo e concentrarsi sull'80386.
Poi ci ha riprovato con i "suoi" RISC i80960 (principalmente per roba embedded) ed i80860 (che tentò di piazzare come RISC per workstation e server).
Ed infine c'e' stato l'Itanium che questa volta "per retrocompatibilità" nella prima versione aveva in hardware l'equivalente in prestazioni ad un i80486.
Ma prima che Intel ritornasse sui suoi passi e mettesse la sua pezza, quella volta fu AMD a farlo e non è che abbia fatto un lavoro peggiore di Intel a riguardo.


Tutte cose che richiedono più istruzioni, e quindi inficiano sulle prestazioni nonché la densità di codice (che inficia anch'essa sulle prestazioni).

Infatti è proprio il motivo per cui, non a caso, RISC-V perde molto in quel benchmark. ;)

Dagli tempo, al momento Risc V è ancora in evoluzione e non è che ci siano implementazioni OoO effettivamente disponibili sul mercato. ;)


Ma infatti il motivo è esattamente quello: hanno voluto un'ISA più spartana. E quindi ne pagano le conseguenze.

There's no free lunch... ;)

Risc V è nato come "architettura didattica e spartana" ma sono anni che sta diventando una specie di famiglia di set di istruzioni estendibili in cui l'estendibilità è nel DNA stesso del set di istruzioni.
RV32I o RV64I sono la "versione spartana" per quando ti serve una cpu senza tante pretese, poi a colpi di estensioni diventa qualcosa che si adatta a casi d'uso di ogni tipo.
Non è "perfetta", basta che sia sufficientemente versatile e con meno vincoli di quelli che si avrebbero utilizzando ARM o x86.


Ah, non dirlo a me, che lo so bene. :D

Come lo sanno molto bene anche i progettisti di RISC-V, che però nei loro talk di pura propaganda che fanno alle conferenze mettono nelle slide che x86/x64 sia un'ISA a lunghezza variabile (sacrilegio!) e la cui lunghezza delle istruzioni arrivi a ben 15 byte (quasi un'intera linea di fetch!!). Squallidi ipocriti... :rolleyes:

Mi sembra che da qualche annetto si parli più della semplicità del decoder Risc V rispetto ad x86, del fatto che la lunghezza delle istruzioni la sai già con i primi bit invece di caricare prefisso dopo prefisso, ecc. ecc.
Stai ancora guardando alle origini di Risc V mentre ora di fatto è diventato altro.


Beh, sì, la mancanza di licenze porta pure a questo come conseguenza.


Spiegalo ad OpenRISC, al J-core o ad altre architetture open source, non hanno avuto lo stesso successo di Risc V. ;)

Non è solo questione di avere un core open source, tutto l'ecosistema che si sta costruendo attorno nasce da esigenze reali a livello accademico e di R&D che stanno piano piano aprendosi la strada in altri ambiti.

Poi se avrà successo così oppure se ci sarà un Risc VI o se la cosa finirà in un ecosistema frammentato è ancora tutto da vedere, ma a livello di microcontroller e core "di servizio" mi sembra che stia facendosi strada cominciando dalla fascia bassa.


Sì, ma così è anche peggio: è un inferno!

Il codice che ho riportato prima dimostra che il compilatore ha ottimizzato per l'allineamento dopo i salti, aggiungendo le necessarie istruzioni di padding. Ed è una cosa giustissima, che ci aspetta proprio per questo.

Il problema è che il padding che emette è a dir poco orribile e, ammazza le prestazioni visto che c'è una valanga di NOP, che anche se non fanno niente... devono essere eseguite (nonché conteggiate)!

La soluzione a questo problema esiste da eoni, ed è molto semplice: in base al numero di byte di padding (che va da 1 a 15), è sufficiente utilizzare UNA apposita istruzione di NOP della lunghezza richiesta. Come fanno gli altri compilatori. Sì, perché x86/x64 hanno NOP di dimensione diversa. In questo modo il padding viene aggiunto correttamente, e a livello di esecuzione il processore esegue UNA sola istruzione NOP. E vissero tutti felici e contenti...

E il tutto senza richiedere strane e oscure ulteriori opzioni di compilazione.

E' almeno dalla versione 4.6.4 (del 2013) che GCC usa NOP "lunghe" (https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(fontScale:14,j:1,lang:c%2B%2B,selection:(endColumn:22,endLineNumber:4,positionColumn:22,positionLineNumber:4,selectionStartColumn:22,selectionStartLineNumber:4,startColumn:22,startLineNumber:4),source:'//+Type+your+code+here,+or+load+an+example.%0Aint+square(int+num)+%7B%0A++++if+(num+%3E0)+goto+aaa%3B%0A++++num+%3D+square(num+%2B+17)%3B%0A++++%2B%2Bnum%3B%0Aaaa:%0A++++if+(num+%3C+0)+goto+bbb%3B%0A++++num+%3D+square(num%2B7)%3B%0A++++num+%3D+num*num%3B%0Abbb:%0A++++if+(num+%3E4096)+goto+ccc%3B%0A++++num+%3D+num+-16%3B%0A++++num+%3D+square(num%2B1)%3B%0Accc:%0A++++return+num%3B%0A%7D'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:33.52480417754569,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:g464,filters:(b:'0',binary:'0',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1'),fontScale:14,j:1,lang:c%2B%2B,libs:!(),options:'-O3+-falign-labels%3D32',selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'x86-64+gcc+4.6.4+(Editor+%231,+Compiler+%231)+C%2B%2B',t:'0')),k:66.47519582245431,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4).
Nell'esempio su godbolt.org che ho linkato sopra, ho forzato "-falign-labels=32" in modo da rendere evidente l'inserimento di NOP "lunghi"; ma in generale a partire dal livello generico -O1 vengono attivate tutte le -falign-XXXX su valori di default che fanno scattare la generazione dei NOP (lunghi e corti a seconda delle esigenze) solo se non si genera troppo sfrido.

cdimauro
09-01-2021, 08:39
Perchè anche se le ALU dei Pentium 4 giravano al doppio del clock, ricevevano una singola microistruzione per ciclo di clock che agiva su un singolo registro.
Se ricordo bene, il vantaggio che davano era in termini di area e di riduzione del clock skew nell'ALU.
OK. Purtroppo non ricordo più questi dettagli.
E' un costo che si fa sentire a livello di complessità di implementazione
Sì, ma bisogna vedere anche quanto.

Posto che il costo per decodificare un'istruzione di load/store con quelle modalità di istruzioni sia fisso, non andresti certo a duplicarlo per ogni istruzione facente accesso alla memoria.
e del maggior numero di interdipendenze per microistruzione
Ma il vantaggio è proprio che non ci sono interdipendenze fra microistruzioni.
(a meno che non la si scomponga in due microistruzioni, vanificando l'effettivo vantaggio in termini di prestazioni finali).

L'esecuzione out-of-order non è magica, aiuta tantissimo ma più di tanto non può fare.
Però è proprio in questi casi che fa tantissimo.
Basta pensare che ad esempio è possibile implementare delle stack machine con esecuzione out-of-order in teoria fantastiche come compattezza del codice, ma che poi stressano parecchio le unità di load/store.
Vero, ma proprio perché fanno continuo riferimento alla memoria. Non è certo il caso di cui stiamo parlando adesso.

Infatti nel nostro caso le unità di load/store vengono stressate soltanto quando non si hanno abbastanza registri a disposizione, e il compilatore è costretto a salvare e ripristinare i registri su/dallo stack.
Ma è più frequente schedularle "più distanti", guadagnando cicli di clock utili.
Guardati quei frammenti di codice, e poi ne riparliamo. ;)
Difatti in un sacco di applicazioni si usano ancora architetture in-order in cui ha più senso un Risc che un x86 proprio perchè si possono ottenere buone prestazioni con un implementazione relativamente semplice.

Dipende da cosa si intende per "equivalenti", stesso processo produttivo e stesso numero di gate ? E quanto potevano rispettivamente salire di clock ?
Ne abbiamo parlato nell'altro thread in cui c'erano a confronto l'Atom in-order e i Cortex in-order e out-of-order.

Numeri alla mano, non c'è proprio storia a livello prestazionale: le soluzioni CISC in-order obliterano quelle RISC in-order, e sono persino competitive con quelle OoO "low/mid-end".
Quello che cambia è il costo di tale retrocompatibilità. ;)
ARM A32 non aveva vincoli di retrocompatibilità quando è nato e come formato delle istruzioni era semplice e regolare, mentre l' 80386 doveva essere retrocompatibile con l' 80286 che a sua volta doveva essere retrocompatibile con l'8086
Ma non cambia di una virgola la questione.

Il punto è x86-64 e AArch64 sono modalità di esecuzione a 64 bit AGGIUNTIVE a quelle a 32-bit delle rispettive famiglie, che funzionano diversamente e richiedono anche decoder diversi.

Questo è esplicitato proprio con x86-64, che chiama Long Mode la modalità nativa a 64 bit, e "Compatibility / legacy" mode tutto il resto (che da tanti anni a questa parte vuol dire soltanto modalità protetta a 32-bit).

Qualunque sia il legacy che si portano dietro (e anche ARM a 32-bit ne ha tanto), il concetto è che per entrambe le famiglie c'è un nuovo set d'istruzioni (incompatibile col precedente) e un nuovo ambiente di esecuzione (molti più registri, e anche modalità d'indirizzamento diverse). Poi possono far girare ANCHE il legacy, qualunque esso sia.

Per cui ribadisco il concetto: la modalità a 64-bit di AMD sarebbe potuta benissimo essere molto diversa da x86-64 (ben più semplice da decodificare, più efficiente, e con buona parte del legacy rimosso in QUESTA modalità d'esecuzione). Senza intaccare tutto il resto (come fa anche AArch64, appunto).
che a sua volta fu pensato per facilitare il porting di applicazioni scritte in assembly per l'8080 se ricordo bene.
8085; comunque ricordi bene. Intel aveva un tool per tradurre i sorgenti 8085 in equivalenti 8086, che funzionava nella quasi totalità dei casi.

Il vantaggio di 8086 fu, infatti, proprio questo: convertire molto velocemente l'esistente libreria di 8085, ma offrendo un'architettura migliore.
Ricorda che Intel aveva già provato a sganciarsi da x86 proprio per i limiti di tale architettura per poi ritornare sui suoi passi ed aggiungere un ennesima pezza ad x86.
Aveva provato a farlo con gli iAPX 432 per poi abbandonarlo e concentrarsi sull'80386.
Poi ci ha riprovato con i "suoi" RISC i80960 (principalmente per roba embedded) ed i80860 (che tentò di piazzare come RISC per workstation e server).
Ed infine c'e' stato l'Itanium che questa volta "per retrocompatibilità" nella prima versione aveva in hardware l'equivalente in prestazioni ad un i80486.
Ma prima che Intel ritornasse sui suoi passi e mettesse la sua pezza, quella volta fu AMD a farlo e non è che abbia fatto un lavoro peggiore di Intel a riguardo.
Direi di sì, invece, perché i precedenti tentativi di Intel non erano delle male pezze su x86, ma architetture completamente nuove che nulla avevano a che fare con x86 e successori.

L'unico di tali tentativi che offrì retrocompatibilità x86 fu proprio Itanium, ma consisteva in una soluzione in parte hardware che cercava di aiutare nell'esecuzione di codice x86. Nulla a che vedere col Compatibility mode di x86-64.

Quindi, ancora una volta sì: AMD ha fatto un lavoro nettamente peggiore di Intel, visto che ha preferito creare una veloce e brutta pezza su x86, anziché cercare di togliere di mezzo una volta per tutte il legacy di x86. Anzi: ci ha costruito sopra il nuovo legacy x86-64...
Dagli tempo, al momento Risc V è ancora in evoluzione e non è che ci siano implementazioni OoO effettivamente disponibili sul mercato. ;)
Ce ne sono diverse, invece, ma tanto il problema rimane lo stesso: anche se in evoluzione, molti elementi chiave di RISC-V rimarranno gli stessi, e quindi rimarranno le problematiche di cui abbiamo discusso.

Peraltro questa è proprio l'n-esima dimostrazione che, checché se ne dica, le architetture CONTINO, eccome! :fagiano:
Risc V è nato come "architettura didattica e spartana" ma sono anni che sta diventando una specie di famiglia di set di istruzioni estendibili in cui l'estendibilità è nel DNA stesso del set di istruzioni.
RV32I o RV64I sono la "versione spartana" per quando ti serve una cpu senza tante pretese, poi a colpi di estensioni diventa qualcosa che si adatta a casi d'uso di ogni tipo.
Non è "perfetta", basta che sia sufficientemente versatile e con meno vincoli di quelli che si avrebbero utilizzando ARM o x86.
Vedi sopra: per quanto versatile, rimarrà quel che è con le diverse scelte che sono state fatte.

L'unico modo per aggirarle è facendo uso di estensioni custom (non proprietarie: ce ne sono di pubbliche, come PULP per l'appunto), ma qui andiamo fuori dallo standard e della sue estensioni ufficiali. Altra frammentazione, insomma.
Mi sembra che da qualche annetto si parli più della semplicità del decoder Risc V rispetto ad x86, del fatto che la lunghezza delle istruzioni la sai già con i primi bit invece di caricare prefisso dopo prefisso, ecc. ecc.
Stai ancora guardando alle origini di Risc V mentre ora di fatto è diventato altro.
Vero: ricordo tante cose vecchie, perché è da tempo che seguo quest'ISA.

Ma in realtà ormai da tempo non si parla più di semplicità del decoder, ma del fatto che l'architettura sia libera da vincoli e licenze da pagare. E' su questo punto che battono continuamente i creatori di RISC-V, e chi ha abbracciato questo progetto.
Spiegalo ad OpenRISC, al J-core o ad altre architetture open source, non hanno avuto lo stesso successo di Risc V. ;)

Non è solo questione di avere un core open source, tutto l'ecosistema che si sta costruendo attorno nasce da esigenze reali a livello accademico e di R&D che stanno piano piano aprendosi la strada in altri ambiti.

Poi se avrà successo così oppure se ci sarà un Risc VI o se la cosa finirà in un ecosistema frammentato è ancora tutto da vedere, ma a livello di microcontroller e core "di servizio" mi sembra che stia facendosi strada cominciando dalla fascia bassa.
La differenza è che OpenRISC e J-core sono troppo specializzati, mentre con RISC-V si è posto fin dall'inizio l'obiettivo di essere un'architettura scalabile e utilizzabile dai microcontrolli ai supercomputer.

Che ovviamente è un modello vincente rispetto a tutti gli altri progetti open source.
E' almeno dalla versione 4.6.4 (del 2013) che GCC usa NOP "lunghe" (https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(fontScale:14,j:1,lang:c%2B%2B,selection:(endColumn:22,endLineNumber:4,positionColumn:22,positionLineNumber:4,selectionStartColumn:22,selectionStartLineNumber:4,startColumn:22,startLineNumber:4),source:'//+Type+your+code+here,+or+load+an+example.%0Aint+square(int+num)+%7B%0A++++if+(num+%3E0)+goto+aaa%3B%0A++++num+%3D+square(num+%2B+17)%3B%0A++++%2B%2Bnum%3B%0Aaaa:%0A++++if+(num+%3C+0)+goto+bbb%3B%0A++++num+%3D+square(num%2B7)%3B%0A++++num+%3D+num*num%3B%0Abbb:%0A++++if+(num+%3E4096)+goto+ccc%3B%0A++++num+%3D+num+-16%3B%0A++++num+%3D+square(num%2B1)%3B%0Accc:%0A++++return+num%3B%0A%7D'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:33.52480417754569,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:g464,filters:(b:'0',binary:'0',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1'),fontScale:14,j:1,lang:c%2B%2B,libs:!(),options:'-O3+-falign-labels%3D32',selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1),l:'5',n:'0',o:'x86-64+gcc+4.6.4+(Editor+%231,+Compiler+%231)+C%2B%2B',t:'0')),k:66.47519582245431,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4).
Nell'esempio su godbolt.org che ho linkato sopra, ho forzato "-falign-labels=32" in modo da rendere evidente l'inserimento di NOP "lunghi"; ma in generale a partire dal livello generico -O1 vengono attivate tutte le -falign-XXXX su valori di default che fanno scattare la generazione dei NOP (lunghi e corti a seconda delle esigenze) solo se non si genera troppo sfrido.
Purtroppo non è così, e lo puoi vedere tu stesso col tool di cui hai passato il link: è soltanto da GCC 10.1 che vengono finalmente generate le NOP correttamente DOPO le istruzioni di call. Prima di tale versione le NOP spesso non venivano inserite dopo le call.

Inoltre in diversi casi continuano a venire generate più NOP di quelle necessarie per coprire il padding.

Infine, sarebbe bastato abilitare di default -falign-labels=16 per imitare ciò che fanno gli altri compilatori, senza costringere i programmatori a dover usare questo parametro addizionale.

LMCH
10-01-2021, 02:05
Ne abbiamo parlato nell'altro thread in cui c'erano a confronto l'Atom in-order e i Cortex in-order e out-of-order.
Appunto, ed avevi citato una paper in cui veniva confrontato un Atom con un TDP molto più alto con dei SoC ARM completi che eppure avevano un TDP più basso.
Decisamente c'erano troppe differenze a livello di tecnologia e risorse per considerarlo un confronto ad armi pari.


Il punto è x86-64 e AArch64 sono modalità di esecuzione a 64 bit AGGIUNTIVE a quelle a 32-bit delle rispettive famiglie, che funzionano diversamente e richiedono anche decoder diversi.

Questo è esplicitato proprio con x86-64, che chiama Long Mode la modalità nativa a 64 bit, e "Compatibility / legacy" mode tutto il resto (che da tanti anni a questa parte vuol dire soltanto modalità protetta a 32-bit).

Qualunque sia il legacy che si portano dietro (e anche ARM a 32-bit ne ha tanto), il concetto è che per entrambe le famiglie c'è un nuovo set d'istruzioni (incompatibile col precedente) e un nuovo ambiente di esecuzione (molti più registri, e anche modalità d'indirizzamento diverse). Poi possono far girare ANCHE il legacy, qualunque esso sia.

Per cui ribadisco il concetto: la modalità a 64-bit di AMD sarebbe potuta benissimo essere molto diversa da x86-64 (ben più semplice da decodificare, più efficiente, e con buona parte del legacy rimosso in QUESTA modalità d'esecuzione). Senza intaccare tutto il resto (come fa anche AArch64, appunto).


Prima implementazionedi 8086 (16bit) 1978: circa 29000 gate.
Prima implementazionedi 80186 (16bit) 1982: circa 55000 gate.
Prima implementazione di 80286 (16bit) 1982: circa 134000 gate.
Prima implementazione di ARM2 (32bit) aprile 1985: circa 30000 gate.
Prima implementazione di 80386 (32bit) ottobre 1985: circa 275000 gate.

ARM2 letteralmente DISINTEGRAVA a livello di prestazioni gli 80286 e gli 8086 ancor di più.
Un ARM2 ad 8MHz aveva pure prestazioni maggiori di un 80386 a 16Mhz, non so se rendo l'idea.

Uno dei punti di forza di ARM2 era il decoder istruzioni estremamente semplice.

Quando poi fu introdotta la modalità Thumb il "decoder Thumb" faceva giusto una rimappatura 1:1 delle istruzioni ampie 16bit su un sottoinsieme di quelle ampie 32bit
(tutto il resto del chip bastava fosse ottimizzato per eseguire il set d'istruzioni A32, come se Thumb quasi non esistesse).

Con gli x86 questo avrebbe richiesto due decoder istruzioni distinti se si voleva sganciarsi dal formato delle istruzioni x86 della generazione precedente, fu scelto di mantenere un formato simile proprio per non perdere troppe prestazioni eseguendo codice "vecchio".


8085; comunque ricordi bene. Intel aveva un tool per tradurre i sorgenti 8085 in equivalenti 8086, che funzionava nella quasi totalità dei casi.

Il vantaggio di 8086 fu, infatti, proprio questo: convertire molto velocemente l'esistente libreria di 8085, ma offrendo un'architettura migliore.

Solo che aveva poco senso farlo, poichè per sfruttare le cose in più che rendeva disponibili l'8086 di fatto bisognava riscrivere da zero il codice assembly.


Direi di sì, invece, perché i precedenti tentativi di Intel non erano delle male pezze su x86, ma architetture completamente nuove che nulla avevano a che fare con x86 e successori.

L'unico di tali tentativi che offrì retrocompatibilità x86 fu proprio Itanium, ma consisteva in una soluzione in parte hardware che cercava di aiutare nell'esecuzione di codice x86. Nulla a che vedere col Compatibility mode di x86-64.


Le cose stanno peggio di come ricordi: di fatto 8086 nacque anche per mettere una pezza ai ritardi accumulati da Intel nello sviluppare iAPX 432. :fiufiu:

Intel iniziò nel 1975 lo sviluppo della cpu a 32bit 8800 (poi rinominata iAPX 432), mentre lo sviluppo di 8086 (come ulteriore evoluzione della famiglia di cpu iniziata con l'8080, il cui ultimo esponente era l'8085) iniziò nel 1976.
In quel periodo Motorola stava lavorando allo sviluppo di MC68000 e Zilog allo sviluppo dello Z8000 (la cpu usata poi sugli Olivetti M20) ed Intel aveva bisogno di qualcosa da piazzare sul mercato perchè lo sviluppo di iAPX 432 era troppo lento.
In teoria POI doveva arrivare iAPX 432 e sarebbe stato quello la cpu del futuro.

Se ci pensi è grottesco, il piano originale di Intel è stato sempre sin dal principio quello di sganciarsi da x86 ... :stordita:

iAPX 432 fu lanciato ufficialmente nel 1981 ma di fatto fu un flop, dopo 3 release alla fine fu abbandonato nel 1985, con l'uscita dell' 80386.

80386 fu il primo x86 a 32bit, ma pur avendo la possibilità di implementare un set d'istruzioni "nuovo" fu scelto di realizzarlo come estensione degli x86 a 16bit, perchè per molti anni fu usato come "8086 molto veloce" più che come "processore a 32bit" e quindi le prestazioni in modalità retrocompatibile erano quelle che interessavano di più.

In pratica 80386 fu una pezza al fallimento completo di iAPX 432 ed alle limitazioni degli x86 a 16bit ed Intel si limitò ad allargare i registri interi ed aggiungere nuove modalità di indirizzamento invece di fare un vero restyling del set di istruzioni.

Non mi sembra abbia fatto un lavoro migliore di quello fatto in seguito da AMD con i 64bit, specialmente se si considera che anche con x86-64 all'inizio la cosa più importante erano le prestazioni in modalità retrocompatibile (a 32bit).


Ce ne sono diverse, invece, ma tanto il problema rimane lo stesso: anche se in evoluzione, molti elementi chiave di RISC-V rimarranno gli stessi, e quindi rimarranno le problematiche di cui abbiamo discusso.


Ma almeno per ora le problematiche attuali non è che siano così devastanti, si fanno sempre dei compromessi e per ora non viene chiesto l'impossibile.
Ripeto. Nulla vieta in futuro di "ripartire da capo" con un Risc VI ecc.


L'unico modo per aggirarle è facendo uso di estensioni custom (non proprietarie: ce ne sono di pubbliche, come PULP per l'appunto), ma qui andiamo fuori dallo standard e della sue estensioni ufficiali. Altra frammentazione, insomma.

E' una frammentazione "controllata", inoltre le estensioni custom servono anche per collaudare sul campo estensioni che poi possono essere rimappate in istruzioni standard aggiunte successivamente.


Ma in realtà ormai da tempo non si parla più di semplicità del decoder, ma del fatto che l'architettura sia libera da vincoli e licenze da pagare. E' su questo punto che battono continuamente i creatori di RISC-V, e chi ha abbracciato questo progetto.

Per forza che battono su tali aspetti, con gli USA che vietano l'export di certe IP e la Cina che "fa campagna acquisti" (vedere MIPS e la filiale cinese di ARM), diventa vitale non avere vincoli export e licenze di IP.


La differenza è che OpenRISC e J-core sono troppo specializzati, mentre con RISC-V si è posto fin dall'inizio l'obiettivo di essere un'architettura scalabile e utilizzabile dai microcontrolli ai supercomputer.


Troppo specializzati ?!?!? :mbe:

OpenRISC grossomodo è un simili-MIPS e MIPS come architettura mi sembra abbastanza versatile (usata a suo tempo dagli embedded ai server).

J-core nasce some "versione libera da vincoli" di SH-2 ed ora che i brevetti su SH-4 sono scaduti in teoria potrebbe esssere spinta oltre, aveva già un ecosistema di supporto ben rodato e non è che mi sembrasse così "specializzata" come dici.

Allo stato attuale Risc V non è un architettura, ma una famiglia di set d'istruzioni "accessibile a tutti" e supportata da un ecosistema software che facilita l'implementazione di nuove architetture, è quello il punto di forza che ha.

raxas
10-01-2021, 08:40
ma si potrebbe avere un riassuntino degli ultimi 9 o 10 post?
tipo due righe, strette strette
mission impossible

Anche una soltanto: è una disquisizione su RISC vs CISC, con particolare focus su RISC-V/ARM da un lato e x86/x86-64 dall'altro. :fagiano:
...

mi erano sfuggiti i replay (alla mia "richiesta" :D)
visti solo ieri sera, rispondo di domenica con un pò di calma :D

":" mi chiedo se sia possibile fare una cpu che faccia le istruzioni in maniera che non si debba definire questo e quello e l'altro e cioè che facciano tutto elle cpu tipo come quando si paga un professionista e non si sa cosa faccia, mettendo lui in campo le sue conoscenze... ma sempre in maniera standard e fissa

non so se sono stato chiaro :D

cioè si "istruiscono" in maniera tale "sbrigatela tu cpu" senza che il progettista sappia nulla :D

tipo come il "temuto" avvento dei robòt, come che prendano loro potere e si sia in mano loro, con gli specialisti che vanno alla "loro presenza" e cerchino di capire cosa arr"o"battino :D

cdimauro
10-01-2021, 09:56
Appunto, ed avevi citato una paper in cui veniva confrontato un Atom con un TDP molto più alto con dei SoC ARM completi che eppure avevano un TDP più basso.
Decisamente c'erano troppe differenze a livello di tecnologia e risorse per considerarlo un confronto ad armi pari.
I confronti erano esclusivamente sul lato prestazionale della CPU, e anche dal punto di vista dei consumi l'Atom era messo bene a livello complessivo (ossia considerando il tempo per portare a termine i benchmark e il consumo impiegato in quell'arco di tempo).

Comunque ne abbiamo già ampiamente parlato nell'altro thread, dove ci sono tutte le informazioni e i paper.
Prima implementazionedi 8086 (16bit) 1978: circa 29000 gate.
Prima implementazionedi 80186 (16bit) 1982: circa 55000 gate.
Prima implementazione di 80286 (16bit) 1982: circa 134000 gate.
Prima implementazione di ARM2 (32bit) aprile 1985: circa 30000 gate.
Prima implementazione di 80386 (32bit) ottobre 1985: circa 275000 gate.

ARM2 letteralmente DISINTEGRAVA a livello di prestazioni gli 80286 e gli 8086 ancor di più.
Un ARM2 ad 8MHz aveva pure prestazioni maggiori di un 80386 a 16Mhz, non so se rendo l'idea.

Uno dei punti di forza di ARM2 era il decoder istruzioni estremamente semplice.
Ma su tutto questo hai riportato non ho assolutamente nulla da dire. :)

Però parlavo d'altro. Mi spiego meglio dopo.
Quando poi fu introdotta la modalità Thumb il "decoder Thumb" faceva giusto una rimappatura 1:1 delle istruzioni ampie 16bit su un sottoinsieme di quelle ampie 32bit
(tutto il resto del chip bastava fosse ottimizzato per eseguire il set d'istruzioni A32, come se Thumb quasi non esistesse).
Quasi proprio no, perché Thumb richiedeva un decoder ad hoc (completamente diverso da quello di ARM2) per le sue istruzioni, nonché un'apposita modalità d'esecuzione.

Il fatto che poi le istruzioni Thumb venissero convertite in istruzioni ARM2 è una mera questione micro-architetturale.

Infatti ci sono processori ARM Cortex che hanno esclusivamente l'ISA Thumb-2, avendo abbandonato del tutto l'originale set ARM2+.
ARM avrebbe potuto benissimo lasciare sia l'ISA ARM2+ sia quella Thumb-2 se il costo di tenerle entrambe fosse stato quasi inesistente. Cosa che evidentemente non è affatto.

Idem per ThumbEE e Jazilla: altre due ISA & modalità d'esecuzione che integrano soltanto pochi core ARM, e che ormai sono state del tutto abbandonate da ARM (ma ovviamente sempre disponibili per chi ne avesse ancora bisogno).

C'è una ragione per tutto ciò, ed è proprio nei costi di implementazione, che non sono così ridotti.
Con gli x86 questo avrebbe richiesto due decoder istruzioni distinti se si voleva sganciarsi dal formato delle istruzioni x86 della generazione precedente,
Infatti ci sono effettivamente due decoder di istruzioni per x86 e x86-64, visto che il set d'istruzioni è diverso: in modalità x86 le istruzioni vengono decodificate in un certo modo, mentre in quella x86-64 in maniera diversa.

Molto dei due decoder è condiviso ovviamente, perché la maggior parte della struttura base degli opcode è comune, ma ci sono diverse differenze che sono anche molto rilevanti, e di cui il rispettivo decoder si deve far carico di considerare.
fu scelto di mantenere un formato simile proprio per non perdere troppe prestazioni eseguendo codice "vecchio".
Non è una questione prestazionale, ma di mera convenienza implementativa: la modalità a 64-bit richiedeva soltanto il 5% in più di transistor rispetto allo stesso core Athlon utilizzato per "espanderlo" a 64-bit.

Le prestazioni, al contrario, sarebbero pure aumentate nettamente riprogettando il tutto.
Solo che aveva poco senso farlo, poichè per sfruttare le cose in più che rendeva disponibili l'8086 di fatto bisognava riscrivere da zero il codice assembly.
Non è così. Già con la sola conversione meccanica dal codice 8085 si guadagnavano 64KB di spazio per il codice, altrettanti per i dati, e altrettanti per lo stack. A costo zero, insomma, semplicemente usando il binario generato per 8086.

Con cambiamenti veramente minimi si guadagnavano altri 64KB per dati extra.

Inoltre c'era un guadagno prestazionale per il fatto di avere un bus dati a 16 bit, e ALU a 16 bit.

Ovviamente per sfruttare meglio l'8086 serviva codice ad hoc, ed è quello che poi è stato fatto. Non è un caso che ancora oggi ci ritroviamo a usare eredi di quest'architettura.
Le cose stanno peggio di come ricordi: di fatto 8086 nacque anche per mettere una pezza ai ritardi accumulati da Intel nello sviluppare iAPX 432. :fiufiu:

Intel iniziò nel 1975 lo sviluppo della cpu a 32bit 8800 (poi rinominata iAPX 432), mentre lo sviluppo di 8086 (come ulteriore evoluzione della famiglia di cpu iniziata con l'8080, il cui ultimo esponente era l'8085) iniziò nel 1976.
In quel periodo Motorola stava lavorando allo sviluppo di MC68000 e Zilog allo sviluppo dello Z8000 (la cpu usata poi sugli Olivetti M20) ed Intel aveva bisogno di qualcosa da piazzare sul mercato perchè lo sviluppo di iAPX 432 era troppo lento.
In teoria POI doveva arrivare iAPX 432 e sarebbe stato quello la cpu del futuro.

Se ci pensi è grottesco, il piano originale di Intel è stato sempre sin dal principio quello di sganciarsi da x86 ... :stordita:

iAPX 432 fu lanciato ufficialmente nel 1981 ma di fatto fu un flop, dopo 3 release alla fine fu abbandonato nel 1985, con l'uscita dell' 80386.

80386 fu il primo x86 a 32bit, ma pur avendo la possibilità di implementare un set d'istruzioni "nuovo" fu scelto di realizzarlo come estensione degli x86 a 16bit, perchè per molti anni fu usato come "8086 molto veloce" più che come "processore a 32bit" e quindi le prestazioni in modalità retrocompatibile erano quelle che interessavano di più.
Quasi nulla da dire anche su questo, a parte farti notare che qui è l'esatto opposto di quello che avevi scritto: iAPX 432 NON nasce per far fuori x86, visto che quando il progetto è partito non se ne parlava ancora di 8086 (e derivati).

Semmai è 8086 che ha fatto fuori iAPX 432. ;)
In pratica 80386 fu una pezza al fallimento completo di iAPX 432 ed alle limitazioni degli x86 a 16bit ed Intel si limitò ad allargare i registri interi ed aggiungere nuove modalità di indirizzamento invece di fare un vero restyling del set di istruzioni.
Cosa che mi ricorda esattamente quello che ha fatto AMD con x86-64 nei confronti di x86. :D
Non mi sembra abbia fatto un lavoro migliore di quello fatto in seguito da AMD con i 64bit, specialmente se si considera che anche con x86-64 all'inizio la cosa più importante erano le prestazioni in modalità retrocompatibile (a 32bit).
Intanto vedi sopra: x86-64 sta a x86 come 80386 sta a 8086/80286, e iAPX 432 non c'entra nulla con la discussione. :fagiano:

E aggiungo che con gli altri tentativi di rimpiazzare x86 (80860, 80960, Itanium) Intel ha, esattamente al contrario di AMD con x86-64, progettato architetture totalmente nuove. Dei "clean design", insomma. Che non hanno nulla a che vedere con la mala pezza di AMD su x86. :read:
Ma almeno per ora le problematiche attuali non è che siano così devastanti, si fanno sempre dei compromessi e per ora non viene chiesto l'impossibile.
Ripeto. Nulla vieta in futuro di "ripartire da capo" con un Risc VI ecc.
Considerato l'ecosistema che s'è creato e si sta continuando a creare su RISC-V, dubito che vedremo un nuovo "clean design" da Berkeley...
E' una frammentazione "controllata", inoltre le estensioni custom servono anche per collaudare sul campo estensioni che poi possono essere rimappate in istruzioni standard aggiunte successivamente.
Non funziona così. Come ho già detto prima, le istruzioni standard sono quelle e sono destinate a rimanere "set in the stone". Stanno sistemando alcune cose con le famigerate sottoestensioni, ma non toccheranno le fondamenta dell'ISA, che sono ben piantate per terra. Lo puoi vedere tu stesso nel documento / paper che ho già fornito. Ci sono cose (e sono tante) su cui non scenderanno mai a compromessi, perché sono dei fanatici.

Per cui l'unica sarà ricorrere a estensioni personalizzate.

"Il dado è tratto..."
Per forza che battono su tali aspetti, con gli USA che vietano l'export di certe IP e la Cina che "fa campagna acquisti" (vedere MIPS e la filiale cinese di ARM), diventa vitale non avere vincoli export e licenze di IP.
Fanno benissimo. Se c'è una cosa buona che ha fatto Trump è dimostrare di quanto siamo dominati dall'imperialismo americano nonché legati mani e piedi agli USA, che allargano prepotentemente il loro raggio d'azione all'intero globo.

Servono soluzioni nuove che ci consentano di divenire completamente autonomi da questi padri-padroni.
Troppo specializzati ?!?!? :mbe:

OpenRISC grossomodo è un simili-MIPS e MIPS come architettura mi sembra abbastanza versatile (usata a suo tempo dagli embedded ai server).
OpenRISC è arrivata quando di RISC-V avevano già definito l'architettura base e alcune importanti estensioni. Infatti la versione 1.0 di OpenRISC risale al 2012, come puoi leggere nel loro sito (http://openrisc.io/architecture), mentre il precedente draft risale al 2006 ed era rimasto a prendere la polvere.

A parte questo, OpenRISC mette a disposizione diverse istruzioni MAC sin dall'inizio, mostrando che l'ambito di utilizzo per cui nasce è l'embedded, ma sono soprattutto le scelte fatte per le istruzioni FP e vettoriali (SIMD) che lo dimostrano indubitabilmente: utilizzano tutte e soltanto i 32 registri general purpose!
In particolare l'estensione vettoriale sembra essere realizzata apposta per implementare classiche istruzioni da DSP.
La cosa peggiore in assoluto, che purtroppo è derivata dalla scelta di usare i registri GP, è che le istruzioni FP a doppia precisione sono a disposizione soltanto nell'ISA a 64 bit e non in quella a 32 bit. Idem per diverse istruzioni vettoriali che richiedono i 64 bit.

Infine, gli opcode sono fissi a 32 bit, e dalla loro struttura immagino già che la densità di codice non sarà delle migliori. Non c'è e non può nemmeno essere prevista un'ISA o delle estensioni compatte (tipo a 16-bit) a causa delle scelte fatte con la struttura degli opcode, e questa è una grande penalizzazione.

Quindi, direi proprio di no. Sebbene sia effettivamente un'ISA RISC (togliendo da parte un attimo la presenza di numerose istruzioni), a mio avviso OpenRISC non è affatto adeguata per coprire tutti gli ambiti di utilizzo & segmenti di mercati.
J-core nasce some "versione libera da vincoli" di SH-2 ed ora che i brevetti su SH-4 sono scaduti in teoria potrebbe esssere spinta oltre, aveva già un ecosistema di supporto ben rodato e non è che mi sembrasse così "specializzata" come dici.
A parte il fatto che, come dici, soltanto di recente sono scaduti i brevetti su SH-2 & SH-4 (e già soltanto questo sarebbe stato sufficiente a non prendere in considerazione quest'architettura), guarda che SH-2..4 è una famiglia di CISC sotto mentite spoglie.
Viene spacciata come RISC soltanto perché, come ormai dovrebbe essere chiaro a tutti, è a causa della propaganda "RISC è meglio / fico / bello, CISC fa schifo / è brutto / cattivo").
Quest'ISA ha tonnellate di diverse (anche complicate) modalità d'indirizzamento verso la memoria, nonché istruzioni aritmetiche per accedere direttamente alla memoria con la famigerata modalità read-execute-write che hai pure criticato quando l'ho citata come punto di forza dei CISC (e di x86/x86-64 in particolare).
Inoltre è chiaramente specializzata in ambito embedded, con tutte le (numerose) istruzioni di manipolazione di bit, nonché istruzioni di MAC e relativi registri addizionali. Le mancano pure le istruzioni ternarie (due registri sorgenti e uno di destinazione. Tipico dei RISC), e deve ripiegare sul riutilizzo del registro destinazione anche come sorgente (tipico dei CISC).
Infine ha soltanto 16 registri general purpose (e tu sostieni che è meglio averne tanti), di cui alcuni persino specializzati.
E' anche importante sottolineare che è soltanto a 32-bit. SH-5, che è a 64 bit, è arrivato dopo, ma è importante notare che ha definito anche un'ISA completamente nuova, con opcode fissi a 32 bit (SH fino alla 4 ha opcode fissi a 16-bit), e quindi due diverse modalità d'esecuzione (devi passare dall'una all'altra ogni volta). Ha ben 64 registri GP e 64 FP con la nuova modalità, che sono un'enorme esagerazione, e che quindi la portano lontana da certi ambiti (proprio l'embedded, paradossalmente).

Direi che ce n'è abbastanza per far scappare a gambe levate i cattedratici puristi di Berkeley, che è la patria dei RISC... :D
Allo stato attuale Risc V non è un architettura, ma una famiglia di set d'istruzioni "accessibile a tutti" e supportata da un ecosistema software che facilita l'implementazione di nuove architetture, è quello il punto di forza che ha.
Senz'altro.
mi erano sfuggiti i replay (alla mia "richiesta" :D)
visti solo ieri sera, rispondo di domenica con un pò di calma :D

":" mi chiedo se sia possibile fare una cpu che faccia le istruzioni in maniera che non si debba definire questo e quello e l'altro e cioè che facciano tutto elle cpu tipo come quando si paga un professionista e non si sa cosa faccia, mettendo lui in campo le sue conoscenze... ma sempre in maniera standard e fissa

non so se sono stato chiaro :D

cioè si "istruiscono" in maniera tale "sbrigatela tu cpu" senza che il progettista sappia nulla :D

tipo come il "temuto" avvento dei robòt, come che prendano loro potere e si sia in mano loro, con gli specialisti che vanno alla "loro presenza" e cerchino di capire cosa arr"o"battino :D
Scusami, ma non è chiaro cosa vorresti ottenere. :stordita:

raxas
10-01-2021, 11:26
...
Scusami, ma non è chiaro cosa vorresti ottenere. :stordita:
è molto semplice :rotfl: : fare un qualcosa che si costruisca la migliore architettura operativa possibile, cioè che la cambi al volo :fagiano: :D

cdimauro
11-01-2021, 05:50
Se hai costruito la miglior architettura possibile allora non c'è più bisogno di doverla cambiare al volo dopo. :p

Cambiare architettura "dinamicamente" (ossia ridefinendola alla bisogna) si può fare, e lo si fa già con gli FPGA. Ma il prezzo da pagare è il notevole calo prestazionale perché i processori "sintetizzati" (è il termine che si usa in genere) non sono assolutamente ottimizzati come invece avviene coi chip "tradizionali" (diciamo così per semplificare. In genere si parla di ASIC).

Spero di essere stato chiaro.

Pino90
11-01-2021, 08:40
Se hai costruito la miglior architettura possibile allora non c'è più bisogno di doverla cambiare al volo dopo. :p

Cambiare architettura "dinamicamente" (ossia ridefinendola alla bisogna) si può fare, e lo si fa già con gli FPGA. Ma il prezzo da pagare è il notevole calo prestazionale perché i processori "sintetizzati" (è il termine che si usa in genere) non sono assolutamente ottimizzati come invece avviene coi chip "tradizionali" (diciamo così per semplificare. In genere si parla di ASIC).

Spero di essere stato chiaro.

Cesare però FPGA è per calcolo parallelo, almeno secondo me non può essere messo sullo stesso piano di una CPU "tradizionale" (per quello che può valere). Cioè il vantaggio di una FPGA è che riesco a creare una architettura ad hoc che tipicamente risolve un problema specifico molto velocemente perchè lo affronta con un approccio parallelo e non sequenziale come un processore tradizionale. Ossia invece di fare un processore generico che può essere programmato faccio una architettura per risolvere un problema specifico. Ed è per questo che nonostante le frequenze siano molto più basse spesso risulta conveniente: pensa ai campi classici come l'applicazione di filtri, campionamento di segnali o reti neurali etc., tutte applicazioni in cui si trae un enorme vantaggio dal design ad hoc del calcolatore che può affrontare le sfide algoritmiche in parallelo. Per altro un FPGA ha bisogno di una CPU tradizionale e di un bus di interfaccia (AXI, PCI) per funzionare.

Un ASIC è qualcosa di ancora diverso - almeno per come usiamo noi il termine a lavoro. FPGA normalmente si usa per prototipare o per applicazioni su piccola scala o di ricerca.

Scusate la precisazione.

cdimauro
12-01-2021, 06:21
Cesare però FPGA è per calcolo parallelo,
No, nasce per essere un dispositivo (ri)programmabile (da cui la P dell'acronimo), a seconda di quello che serve implementare (in hardware).
almeno secondo me non può essere messo sullo stesso piano di una CPU "tradizionale" (per quello che può valere).
Infatti non lo è. Ci si possono fare delle CPU (e in ambito retrogaming, ad esempio, le soluzioni FPGA dilagano), ma le prestazioni saranno scarse (rispetto a un ASIC equivalente).
Cioè il vantaggio di una FPGA è che riesco a creare una architettura ad hoc che tipicamente risolve un problema specifico molto velocemente perchè lo affronta con un approccio parallelo e non sequenziale come un processore tradizionale. Ossia invece di fare un processore generico che può essere programmato faccio una architettura per risolvere un problema specifico.
Sì, ma non deve necessariamente essere un approccio parallelo: è sufficiente che si risolva il problema specifico a un costo migliore di un sistema discreto esistente (altrimenti si userebbe quello, ovviamente).

Poi è chiaro che se lo specifico problema si presta a essere parallelizzato gli elementi di logica integrati li puoi sfruttare per creare tante copie dei core, ALU, o altro, che ti servono.
Ed è per questo che nonostante le frequenze siano molto più basse spesso risulta conveniente: pensa ai campi classici come l'applicazione di filtri, campionamento di segnali o reti neurali etc., tutte applicazioni in cui si trae un enorme vantaggio dal design ad hoc del calcolatore che può affrontare le sfide algoritmiche in parallelo.
SE i risultati sono migliori di un'esistente soluzione discreta... sì. Bisogna sempre farsi i conti.
Per altro un FPGA ha bisogno di una CPU tradizionale e di un bus di interfaccia (AXI, PCI) per funzionare.
No, con l'FPGA la CPU tradizionale te la puoi costruire sfruttando gli elementi di logica integrati, e puoi fare lo stesso coi bus d'interfacciamento con l'esterno (memorie incluse).

Quindi questi elementi non servono.

Però molti FPGA includono anche delle CPU e/o dei controller di memoria e/o dei controlli PCI, ecc., perché sono componenti che vengono usati molto spesso, e quindi è inutile che i programmatori FGPA si reinventino la ruota ogni volta.
Un ASIC è qualcosa di ancora diverso - almeno per come usiamo noi il termine a lavoro.
Come lo usate?
FPGA normalmente si usa per prototipare o per applicazioni su piccola scala o di ricerca.
Esattamente. Oppure se non si hanno i soldi per realizzare un ASIC (visto che produrli è molto costoso).
Scusate la precisazione.
Non ti devi scusare: è un forum, ed è nato per discutere. Poi questo è pure un forum tecnico. :)

Pino90
12-01-2021, 07:50
No, nasce per essere un dispositivo (ri)programmabile (da cui la P dell'acronimo), a seconda di quello che serve implementare (in hardware).

Infatti non lo è. Ci si possono fare delle CPU (e in ambito retrogaming, ad esempio, le soluzioni FPGA dilagano), ma le prestazioni saranno scarse (rispetto a un ASIC equivalente).

Sì, ma non deve necessariamente essere un approccio parallelo: è sufficiente che si risolva il problema specifico a un costo migliore di un sistema discreto esistente (altrimenti si userebbe quello, ovviamente).

Poi è chiaro che se lo specifico problema si presta a essere parallelizzato gli elementi di logica integrati li puoi sfruttare per creare tante copie dei core, ALU, o altro, che ti servono.

SE i risultati sono migliori di un'esistente soluzione discreta... sì. Bisogna sempre farsi i conti.


Si certo si possono fare delle CPU e in generale ci si può fare un po' quello che si vuole nei limiti delle capacità del singolo chip. Scusa, è che in effetti le ho sempre usate per compiti ad alto parallelismo e quindi do per scontato che si usino sempre per questo genere di compiti ma come giustamente fai notare tu non è vero.

In generale do per scontato che se si usa una FPGA l'analisi dei rischi e dei costi sia già stata fatta. Nel senso, nel momento in cui si arriva ad usarla già si pensa che se ne possa beneficiare, anche perchè l'investimento di termini di ore uomo per la stesura di un codice HDL di qualità decente è piuttosto ingente.


No, con l'FPGA la CPU tradizionale te la puoi costruire sfruttando gli elementi di logica integrati, e puoi fare lo stesso coi bus d'interfacciamento con l'esterno (memorie incluse).

Quindi questi elementi non servono.

Però molti FPGA includono anche delle CPU e/o dei controller di memoria e/o dei controlli PCI, ecc., perché sono componenti che vengono usati molto spesso, e quindi è inutile che i programmatori FGPA si reinventino la ruota ogni volta.

Nella mia piccola esperienza (settore aeronautico e ferroviario) FPGA è sempre accompagnato da una CPU tradizionale. Di nuovo hai ragione tu nel dire che non è necessario anche se io non l'ho mai visto in maniera diversa.
Solo come completezza rimarco che le trame moderne già hanno dei blocchi di memoria all'interno della trama stessa (i cosiddetti bram blocks) e spesso e volentieri hanno anche dei piccoli banchi ram per memorizzare dati intermedi più consistenti senza sprecare registri né cicli per accedere ad una memoria esterna (se ne vanno svariate decine di cicli per leggere un dato da una RAM normalmente).

Come lo usate?

Nel nostro caso parliamo di ASIC quando è finito il ciclo di V&V su FPGA, le ottimizzazioni del design sono state fatte e viene fatta la sintesi in silicio. Non so se il termine sia generalmente corretto. Cioè prima di stampare vogliamo essere 150% sicuri che vada tutto bene anche perché se no volano euro che è un piacere.
Ai clienti normalmente vengono consegnati i sistemi già certificati e prodotti in silicio insieme a tutta la documentazione. Normalmente la produzione viene eseguita dopo la certificazione del design (per componenti safety) per evitare casini con il re-design e i conseguenti costi esorbitanti.

Io chiudo qui ché siamo OT. :) Sempre un piacere!

LMCH
12-01-2021, 15:40
Quasi proprio no, perché Thumb richiedeva un decoder ad hoc (completamente diverso da quello di ARM2) per le sue istruzioni, nonché un'apposita modalità d'esecuzione.

Il fatto che poi le istruzioni Thumb venissero convertite in istruzioni ARM2 è una mera questione micro-architetturale.

Infatti ci sono processori ARM Cortex che hanno esclusivamente l'ISA Thumb-2, avendo abbandonato del tutto l'originale set ARM2+.
ARM avrebbe potuto benissimo lasciare sia l'ISA ARM2+ sia quella Thumb-2 se il costo di tenerle entrambe fosse stato quasi inesistente. Cosa che evidentemente non è affatto.

Idem per ThumbEE e Jazilla: altre due ISA & modalità d'esecuzione che integrano soltanto pochi core ARM, e che ormai sono state del tutto abbandonate da ARM (ma ovviamente sempre disponibili per chi ne avesse ancora bisogno).

C'è una ragione per tutto ciò, ed è proprio nei costi di implementazione, che non sono così ridotti.

I Cortex-M implementano solo Thumb2 perchè ARM li contrappone alle vecchie cpu ad 8bit ed ai vari microcontroller in area sul chip ridotta al minimo (per avere costi di produzione più bassi), bassi consumi e compattezza del codice sono fondamentali.
Quindi hanno limato via tutto quello che potevano.

Basta pensare che i core Cortex-M0 nella loro implementazione più spartana richiedono circa 12000 gate contro i circa 6000 gate di un core 8051 ad 8bit.

Non è un caso che i Cortex-M0 stiano spazzando via le cpu ad 8bit anche in termini di costo/prestazioni :sborone:

Poi, a parte il target di fascia più bassa, i Cortex-M implementano solo Thumb2 anche nelle versioni "più potenti" (in cui conta meno la minimizzazione del numero di gate utilizzati) perchè con Thumb2 oltre alla compattezza del codice, ad un microcontroller basta avere il bus da flash a core ampio 16bit per avere buone prestazioni
(e se poi uno vuole il set completo di istruzioni a 32bit, ci sono i Cortex-R)


Infatti ci sono effettivamente due decoder di istruzioni per x86 e x86-64, visto che il set d'istruzioni è diverso: in modalità x86 le istruzioni vengono decodificate in un certo modo, mentre in quella x86-64 in maniera diversa.

Molto dei due decoder è condiviso ovviamente, perché la maggior parte della struttura base degli opcode è comune, ma ci sono diverse differenze che sono anche molto rilevanti, e di cui il rispettivo decoder si deve far carico di considerare.

Non si tratta solo di quello che c'e' sul decoder, ma anche di quello che sta a valle di esso. Il formato e la codifica delle microOP, degli scheduler di istruzioni, il dimensionamento di ALU, AGU, ecc. non viene mica deciso arbitrariamente. Se la tipologia o il formato di quello che generano i decoder è troppo diverso, si hanno effetti anche su tutto quello che sta a valle OPPURE si deve accettare che uno dei due set di istruzioni sia penalizzato.


Non è una questione prestazionale, ma di mera convenienza implementativa: la modalità a 64-bit richiedeva soltanto il 5% in più di transistor rispetto allo stesso core Athlon utilizzato per "espanderlo" a 64-bit.

Le prestazioni, al contrario, sarebbero pure aumentate nettamente riprogettando il tutto.

Ti faccio notare che con Itanium hanno letteralmente riprogettato tutto ed il suo punto debole più rilevante per il grosso degli utilizzatori era che in emulazione x86 era troppo lento (aveva circa le prestazioni di un 486 quando sul mercato c'erano Pentium III, Pentium 4 ed Athlon ).
Quindi ci sono limiti ben precisi su quel che si può ottenere implementando due decoder molto differenti. ;)


Non è così. Già con la sola conversione meccanica dal codice 8085 si guadagnavano 64KB di spazio per il codice, altrettanti per i dati, e altrettanti per lo stack. A costo zero, insomma, semplicemente usando il binario generato per 8086.

Con cambiamenti veramente minimi si guadagnavano altri 64KB per dati extra.

Inoltre c'era un guadagno prestazionale per il fatto di avere un bus dati a 16 bit, e ALU a 16 bit.

Ovviamente per sfruttare meglio l'8086 serviva codice ad hoc, ed è quello che poi è stato fatto. Non è un caso che ancora oggi ci ritroviamo a usare eredi di quest'architettura.


Il costo non era zero.
La conversione automatica andava bene solo per roba che si limitava a max 64k di dati e programmi nello stesso spazio di memoria
E che non facesse uso di codice automodificante, per tutto il resto era meglio riscrivere tutto.

Se ad esempio il programma usava puntatori, bisognava verificare che non ci fossero parti di codice che presupponevano che stack, variabili globali/heap e codice fossero nello stesso spazio di indirizzamento lineare
(tipo se allochi una struttura sullo stack e poi passi ad una funzione il puntatore alla struttura).

Infatti il grosso del software per 8080 ed 8085 col tempo o è migrato verso gli Z80 oppure è stato riscritto per la maggior parte a mano (se era codice assembly).
Non è un caso se al giorno d'oggi trovi ancora in produzione un sacco di microcontroller Z80-compatibili oppure le loro versioni evolute retrocompatibili a livello di codice binario.



Quasi nulla da dire anche su questo, a parte farti notare che qui è l'esatto opposto di quello che avevi scritto: iAPX 432 NON nasce per far fuori x86, visto che quando il progetto è partito non se ne parlava ancora di 8086 (e derivati).

Semmai è 8086 che ha fatto fuori iAPX 432. ;)


Per la precisione in precedenza avevo scritto:

Ricorda che Intel aveva già provato a sganciarsi da x86 proprio per i limiti di tale architettura per poi ritornare sui suoi passi ed aggiungere un ennesima pezza ad x86.
Aveva provato a farlo con gli iAPX 432 per poi abbandonarlo e concentrarsi sull'80386.

Infatti poi successivamente ho chiarito cosa intendevo, mi sembra. ;)


Cosa che mi ricorda esattamente quello che ha fatto AMD con x86-64 nei confronti di x86. :D

Intanto vedi sopra: x86-64 sta a x86 come 80386 sta a 8086/80286, e iAPX 432 non c'entra nulla con la discussione. :fagiano:

C'entra eccome, le uniche cpu Intel che sono tuttora in produzione sono esclusivamente quelle con retrocompatibilità con x86 e con buone prestazioni (rispetto al loro target di mercato) in tale modalità.


E aggiungo che con gli altri tentativi di rimpiazzare x86 (80860, 80960, Itanium) Intel ha, esattamente al contrario di AMD con x86-64, progettato architetture totalmente nuove. Dei "clean design", insomma. Che non hanno nulla a che vedere con la mala pezza di AMD su x86. :read:

Ed ogni volta il potenziale sostituto ... è stato sostituito da una nuova generazione di x86 con una mala pezza (di Intel oppure di AMD).


Considerato l'ecosistema che s'è creato e si sta continuando a creare su RISC-V, dubito che vedremo un nuovo "clean design" da Berkeley...

Mai dire mai, specialmente quando ci sono di mezzo gli accademici. ;)


Non funziona così. Come ho già detto prima, le istruzioni standard sono quelle e sono destinate a rimanere "set in the stone". Stanno sistemando alcune cose con le famigerate sottoestensioni, ma non toccheranno le fondamenta dell'ISA, che sono ben piantate per terra. Lo puoi vedere tu stesso nel documento / paper che ho già fornito. Ci sono cose (e sono tante) su cui non scenderanno mai a compromessi, perché sono dei fanatici.

Per cui l'unica sarà ricorrere a estensioni personalizzate.

Ci sono ancora un sacco di estensioni "standard" di Risc-V ancora da congelare e gruppi di istruzioni ancora da assegnare, vediamo che succede.


Fanno benissimo. Se c'è una cosa buona che ha fatto Trump è dimostrare di quanto siamo dominati dall'imperialismo americano nonché legati mani e piedi agli USA, che allargano prepotentemente il loro raggio d'azione all'intero globo.

Servono soluzioni nuove che ci consentano di divenire completamente autonomi da questi padri-padroni.

Inoltre la longevità/reperibilità dei componenti e del software sta diventando sempre più rilevante.
Un pericolo sempre più tangibile è ritrovarsi con prodotti dal lungo ciclo di vita il cui hardware diventa obsoleto troppo presto o non più reperibile.
E li più che la geopolitica pesa il vendor lock-in.
Avere un hardware che male che vada puoi reimplementare su FPGA o farti fare un ASIC da un produttore a tua scelta diventa molto interessante sotto questo punto di vista.


OpenRISC è arrivata quando di RISC-V avevano già definito l'architettura base e alcune importanti estensioni. Infatti la versione 1.0 di OpenRISC risale al 2012, come puoi leggere nel loro sito (http://openrisc.io/architecture), mentre il precedente draft risale al 2006 ed era rimasto a prendere la polvere.


Veramente i lavori su OpenRISC erano iniziati nel 2000, il 2012 è quando è stato fissato lo standard 1.0 (ed un computer basato su OpenRisc fu utilizzato in orbita sulla ISS), ma ad esempio già nel 2009 c'era Samsung che usava i core OpenRisc (https://opencores.org/forum/OpenRISC/0/4613) in prodotti commerciali (i suoi SoC per televisori).

I lavori su Risc V sono iniziati nel 2010, è progredito molto più rapidamente sotto tutti gli aspetti ed inizialmente sembrava essere solo una "versione accademica" di OpenRisc.

(riguardo J-core)

Direi che ce n'è abbastanza per far scappare a gambe levate i cattedratici puristi di Berkeley, che è la patria dei RISC... :D


Il mio punto non era riguardo cpu open source "sviluppate da puristi dei RISC" ma semplicemente che cpu non gravate da brevetti (ed il J-core ed OpenRisc rispondono a tali requisiti) non hanno sfondato come sta facendo Risc V.

cdimauro
16-01-2021, 09:01
Rieccomi. Finalmente ho abbastanza tempo da dedicare a questo lungo (ma fantastico) thread.
Si certo si possono fare delle CPU e in generale ci si può fare un po' quello che si vuole nei limiti delle capacità del singolo chip. Scusa, è che in effetti le ho sempre usate per compiti ad alto parallelismo e quindi do per scontato che si usino sempre per questo genere di compiti ma come giustamente fai notare tu non è vero.

In generale do per scontato che se si usa una FPGA l'analisi dei rischi e dei costi sia già stata fatta. Nel senso, nel momento in cui si arriva ad usarla già si pensa che se ne possa beneficiare, anche perchè l'investimento di termini di ore uomo per la stesura di un codice HDL di qualità decente è piuttosto ingente.

Nella mia piccola esperienza (settore aeronautico e ferroviario) FPGA è sempre accompagnato da una CPU tradizionale. Di nuovo hai ragione tu nel dire che non è necessario anche se io non l'ho mai visto in maniera diversa.
Solo come completezza rimarco che le trame moderne già hanno dei blocchi di memoria all'interno della trama stessa (i cosiddetti bram blocks) e spesso e volentieri hanno anche dei piccoli banchi ram per memorizzare dati intermedi più consistenti senza sprecare registri né cicli per accedere ad una memoria esterna (se ne vanno svariate decine di cicli per leggere un dato da una RAM normalmente).
Esattamente, ed è anche il motivo per cui gli FPGA si sono diffusi e si stanno diffondendo molto negli ultimi anni. Ormai non sono soltanto dei componenti che offrono un certo numero di elementi di logica e basta, ma integrano tanta roba già bella e pronta, che devi soltanto selezionare e usare per quello che ti serve.

Scrivere HDL richiede tempo, ma grazie a tutta questa roba integrata è diventato di gran lunga più facile. Oggi realizzare una CPU interamente in FPGA non è più un tabù, e progetti se ne vedono parecchi in giro (specialmente in ambito retrogaming, come già detto).
Nel nostro caso parliamo di ASIC quando è finito il ciclo di V&V su FPGA, le ottimizzazioni del design sono state fatte e viene fatta la sintesi in silicio. Non so se il termine sia generalmente corretto. Cioè prima di stampare vogliamo essere 150% sicuri che vada tutto bene anche perché se no volano euro che è un piacere.
Ai clienti normalmente vengono consegnati i sistemi già certificati e prodotti in silicio insieme a tutta la documentazione. Normalmente la produzione viene eseguita dopo la certificazione del design (per componenti safety) per evitare casini con il re-design e i conseguenti costi esorbitanti.
Da quel che scrivi dovete avere un bel giro d'affari con cifre importanti. :D

Già soltanto per tirare fuori una maschera per un ASIC ci vogliono parecchi soldi (centinaia di migliaia di euro, a memoria. Ma non so se i costi sono calati negli ultimi anni). E devi sperare che vada tutto bene e che non devi rifarne altre.
Poi andare in produzione per lotti di poche decine di migliaia di chip dovrebbe richiedere qualche milione di euro.
Cifre assolutamente fuori portata di hobbisti et similia.
Io chiudo qui ché siamo OT. :) Sempre un piacere!
Idem. :)
I Cortex-M implementano solo Thumb2 perchè ARM li contrappone alle vecchie cpu ad 8bit ed ai vari microcontroller in area sul chip ridotta al minimo (per avere costi di produzione più bassi), bassi consumi e compattezza del codice sono fondamentali.
Quindi hanno limato via tutto quello che potevano.

Basta pensare che i core Cortex-M0 nella loro implementazione più spartana richiedono circa 12000 gate contro i circa 6000 gate di un core 8051 ad 8bit.

Non è un caso che i Cortex-M0 stiano spazzando via le cpu ad 8bit anche in termini di costo/prestazioni :sborone:

Poi, a parte il target di fascia più bassa, i Cortex-M implementano solo Thumb2 anche nelle versioni "più potenti" (in cui conta meno la minimizzazione del numero di gate utilizzati) perchè con Thumb2 oltre alla compattezza del codice, ad un microcontroller basta avere il bus da flash a core ampio 16bit per avere buone prestazioni
(e se poi uno vuole il set completo di istruzioni a 32bit, ci sono i Cortex-R)
Assolutamente sì, infatti, ma lo vedi tu stesso che i costi implementativi sono importanti e non indifferenti. :)

Se consideri che il primo ARM (ARM1) richiedeva 25 mila gate (se non ricordo male) e che nel frattempo l'ISA è aumentata non poco (ARMv7), a conti fatti tenere Thumb-2 e ARM assieme richiedono non poche risorse. ;)
Non si tratta solo di quello che c'e' sul decoder, ma anche di quello che sta a valle di esso. Il formato e la codifica delle microOP, degli scheduler di istruzioni, il dimensionamento di ALU, AGU, ecc. non viene mica deciso arbitrariamente. Se la tipologia o il formato di quello che generano i decoder è troppo diverso, si hanno effetti anche su tutto quello che sta a valle OPPURE si deve accettare che uno dei due set di istruzioni sia penalizzato.
Certamente, ma non stiamo parlando di ISA completamente diverse. Perfino ARM64 ricicla parecchia "infrastruttura" di ARM, estendendola.

Nel caso di x86 e x64 (ormai uso le sigle più comuni nonché abbreviate) i dati li ha fornito AMD all'epoca: l'implementazione di quest'ultima ha richiesto il 5% in più di transistor rispetto allo stesso, identico, core, ma soltanto con x86. Non è molto, se consideri che dentro c'è il raddoppio dei registri sia general purpose sia SIMD (e, come sai, il register file è uno degli elementi microarchitetturali che richiede più transistor & area in un core).

Vuol dire che è stato possibile riciclare quasi tutto, praticamente, con poche modifiche sia al frontend sia al backend.
Ti faccio notare che con Itanium hanno letteralmente riprogettato tutto ed il suo punto debole più rilevante per il grosso degli utilizzatori era che in emulazione x86 era troppo lento (aveva circa le prestazioni di un 486 quando sul mercato c'erano Pentium III, Pentium 4 ed Athlon ).
Quindi ci sono limiti ben precisi su quel che si può ottenere implementando due decoder molto differenti. ;)
Vero, ma Itanium è un caso a parte, perché non aveva effettivamente due decoder separati le due diverse ISA: aveva soltanto qualche accelerazione hardware integrata per x86.

Per il resto vedi sopra, sulla questione.

E' chiaro che se hai due ISA completamente diverse ci saranno costi maggiori sia per i decoder sia per il backend, perché ci sarà un limite alla possibilità di riciclare / usare parti comuni.

Infatti persino Transmeta, che aveva un'ISA nativa completamente diversa, ha dovuto incorporare (in hardware, intendo) alcuni elementi di x86, altrimenti l'emulazione sarebbe stata mooooolto più lenta.

Infine e per ritornare alla discussione originale (mi riferisco a questa specifica parte :D): x64 rimane una brutta pezza che AMD ha messo su x86, che ha velocemente applicato e implementato per non dover perdere tempo nel progettare un'ISA ex-novo (seppure basata sui concetti di x86, e riciclando ugualmente quasi tutto il backend).
Questo lo posso affermare con assoluta certezza, perché ho dati concreti in mano che lo dimostrano senza alcun dubbio.
Il costo non era zero.
La conversione automatica andava bene solo per roba che si limitava a max 64k di dati e programmi nello stesso spazio di memoria
E che non facesse uso di codice automodificante, per tutto il resto era meglio riscrivere tutto.

Se ad esempio il programma usava puntatori, bisognava verificare che non ci fossero parti di codice che presupponevano che stack, variabili globali/heap e codice fossero nello stesso spazio di indirizzamento lineare
(tipo se allochi una struttura sullo stack e poi passi ad una funzione il puntatore alla struttura).
Corretto. Diverse cose si potevano sistemare meccanicamente e automaticamente (col traduttore) usando i famigerati prefissi di segmento, ma per le cose che hai elencato servivano modifiche al codice, effettivamente.

Comunque si poteva sempre partire da una traduzione in cui tutti i segmenti fossero uguale, in modo da avere immediatamente codice funzionante. Per poi fare modifiche migliorative col tempo.
Infatti il grosso del software per 8080 ed 8085 col tempo o è migrato verso gli Z80 oppure è stato riscritto per la maggior parte a mano (se era codice assembly).
All'epoca si usava per lo più l'assembly con questi processori.
Non è un caso se al giorno d'oggi trovi ancora in produzione un sacco di microcontroller Z80-compatibili oppure le loro versioni evolute retrocompatibili a livello di codice binario.
Già in produzione magari sì, ma danni non vedo roba Z80 o simile. Come pure 6502/65C02/65816. O, sfortunatamente, 68000+.

E' tutta roba legacy, mentre oggi sono più diffusi microcontrollori a basso costo come Microchip, Atmel, Renaissance, ecc.. Meno male che stanno prendendo piede i Thumb-2, per l'appunto, che sono di gran lunga più versatili e potenti.
C'entra eccome, le uniche cpu Intel che sono tuttora in produzione sono esclusivamente quelle con retrocompatibilità con x86 e con buone prestazioni (rispetto al loro target di mercato) in tale modalità.
Sì, ma iAPX 432 non ha mai impensierito né tanto meno sostituito 8086 e successori. ;)
Mai dire mai, specialmente quando ci sono di mezzo gli accademici. ;)
Hanno avuto una gran botta di culo perché hanno trovato un enorme appoggio dai privati, ma son treni che in genere passano una sola volta. :fagiano:

Sarà difficile pensare a un sostituito una volta che RISC-V diventerà un ecosistema solido e paragonabile a x86 e ARM a livello di diffusione e supporto.
Ci sono ancora un sacco di estensioni "standard" di Risc-V ancora da congelare e gruppi di istruzioni ancora da assegnare, vediamo che succede.
Vero ma, come dico dicevo prima, quelle più importanti sono già state ratificate. Fra le più importanti rimaste ancora da ratificare manca quella vettoriale, che sta avendo un lunghissimo travaglio.
Inoltre la longevità/reperibilità dei componenti e del software sta diventando sempre più rilevante.
Un pericolo sempre più tangibile è ritrovarsi con prodotti dal lungo ciclo di vita il cui hardware diventa obsoleto troppo presto o non più reperibile.
E li più che la geopolitica pesa il vendor lock-in.
Avere un hardware che male che vada puoi reimplementare su FPGA o farti fare un ASIC da un produttore a tua scelta diventa molto interessante sotto questo punto di vista.
A chi lo dici. Pensa al settore automobilistico, dove serve garantire assistenza e ricambi per 17 anni (se non ricordo male). Avendo FPGA o (meglio ancora, visto l'utilizzo) ASIC permetterebbe di evitare di mettere a magazzino tanta roba che poi andrà per lo più buttata. Quando, invece, alla bisogna si potrebbero produrre nuovamente i componenti necessari.
Veramente i lavori su OpenRISC erano iniziati nel 2000, il 2012 è quando è stato fissato lo standard 1.0 (ed un computer basato su OpenRisc fu utilizzato in orbita sulla ISS), ma ad esempio già nel 2009 c'era Samsung che usava i core OpenRisc (https://opencores.org/forum/OpenRISC/0/4613) in prodotti commerciali (i suoi SoC per televisori).

I lavori su Risc V sono iniziati nel 2010, è progredito molto più rapidamente sotto tutti gli aspetti ed inizialmente sembrava essere solo una "versione accademica" di OpenRisc.
Non ero a conoscenza dell'implementazione di Samsung. Comunque parliamo del draft non ancora ratificato (nemmeno la 1.0).

Per il resto rimangono le mie obiezioni tecniche su OpenRISC: purtroppo è troppo specializzato e non adatto a poter essere impiegato in qualunque ambito applicativo, che era l'obiettivo di RISC-V.
(riguardo J-core)

Il mio punto non era riguardo cpu open source "sviluppate da puristi dei RISC" ma semplicemente che cpu non gravate da brevetti (ed il J-core ed OpenRisc rispondono a tali requisiti) non hanno sfondato come sta facendo Risc V.
Per due motivi: perché, come già detto, erano e sono troppo specializzate, e poi all'epoca erano ancora gravate dai brevetti (spirati soltanto qualche anno fa). In entrambi i casi inutilizzabili per i fini di RISC-V.

LMCH
18-01-2021, 17:06
Rieccomi. Finalmente ho abbastanza tempo da dedicare a questo lungo (ma fantastico) thread.

Stiamo costruendo una vera e propria muraglia di testo. :D


Vero, ma Itanium è un caso a parte, perché non aveva effettivamente due decoder separati le due diverse ISA: aveva soltanto qualche accelerazione hardware integrata per x86.


Soltanto "accelerazione hardware integrata" ? :mbe:

Il Merced aveva nella descrizione del layout del chip un unico blocco denominato "instruction fetch and decode" e due altri blocchi denominati "IA-32 Control" ed "IA-64 Control".
intel_itanium.jpg (http://cpudb.stanford.edu/system/die_photos/photos/000/000/036/large/intel_itanium.jpg).
Quindi a valle del decoder c'erano due sottosistemi di esecuzione separate ma il decoder poteva decodificare direttamente entrambi i set di istruzioni (probabilmente l'IA-64 in modo più efficiente, per ovvi motivi, ma pur sempre di decodifica in hardware si trattava)

Il successivo McKinley aveva un "IA-32 Engine" ancora più complesso
(vedere pagina 8 di questo pdf (https://www.cse.msu.edu/~cse820/lectures/Itanium.pdf))
ma anche in quel caso il codice x86 era seguito in hardware, non con l'ausilio di software che si appoggiasse ad acceleratori hardware integrati per l'esecuzione!

Solo dopo nelle versioni che seguirono il decoder istruzioni x86 ed il resto della logica di controllo esecuzione furono eliminati (presumibilmente con ancora alcune estensioni che semplificasseo l'emulazione x86, ma di quello non sono sicuro).


Infine e per ritornare alla discussione originale (mi riferisco a questa specifica parte :D): x64 rimane una brutta pezza che AMD ha messo su x86, che ha velocemente applicato e implementato per non dover perdere tempo nel progettare un'ISA ex-novo (seppure basata sui concetti di x86, e riciclando ugualmente quasi tutto il backend).
Questo lo posso affermare con assoluta certezza, perché ho dati concreti in mano che lo dimostrano senza alcun dubbio.

Sono d'accordo con te, era una brutta pezza, ma funzionava e non penalizzava troppo le prestazioni in modalità retrocompatibile, ricordo anche che a suo tempo circolava voce che Intel avesse a sua volta preparato un evoluzione a 64bit degli x86 incompatibile con x86-64 di AMD, ma che poi non se ne fece niente perchè Microsoft si rifiutò di supportare un altro set di istruzioni dopo il bagno di sangue di Itanium.
Viene da chiedersi cosa avessero preparato, forse una modalità a 64bit molto più innovativa ? Oppure avevano deciso di estendere a 64bit gli 8 registri interi e poco altro ?


Corretto. Diverse cose si potevano sistemare meccanicamente e automaticamente (col traduttore) usando i famigerati prefissi di segmento, ma per le cose che hai elencato servivano modifiche al codice, effettivamente.


Comunque si poteva sempre partire da una traduzione in cui tutti i segmenti fossero uguale, in modo da avere immediatamente codice funzionante. Per poi fare modifiche migliorative col tempo.

Avere immediatamente codice assembly che forse-funziona-forse-no ?
Se era relativamente complesso, come minimo lo avrebbero dovuto passare al setaccio con code review multiple.
Se era relativamene semplice, sempre per gli stessi motivi conveniva riscriverlo a mano in modo da sfruttare bene i registri e le istruzioni disponibili.
Mi ricordo come erano i due set d'istruzioni e passare da una cpu all'altra
era così: https://www.youtube.com/watch?v=S9WWz95ripA&list=RDrJ2WqmKLsuY&index=9 :yeah:


All'epoca si usava per lo più l'assembly con questi processori.

Me lo ricordo, adesso persino per i PIC di Microchip esistono dei compilatori C, allora era assembly o forth per la roba embedded (a meno di usare roba "grossa").


Già in produzione magari sì, ma danni non vedo roba Z80 o simile. Come pure 6502/65C02/65816. O, sfortunatamente, 68000+.

Si nascondono, ma ci sono, di solito sono usati per sviluppare nuovo hardware da usare come retrofit di roba "vecchia" di cui si sono persi i sorgenti oppure per riciclare software già sviluppato e testato da anni (dove ora al posto di una schedina con 2..3 chip c'e' un SoC supereconomico).


Sì, ma iAPX 432 non ha mai impensierito né tanto meno sostituito 8086 e successori. ;)

Ma nei piani della stessa Intel doveva essere il loro nuovo prodotto di punta al posto degli 8086. ;)


Hanno avuto una gran botta di culo perché hanno trovato un enorme appoggio dai privati, ma son treni che in genere passano una sola volta. :fagiano:

Concordo sulla botta di culo, ma i cambiamenti che inevitabilmente ci saranno in futuro a livello di tecnologie e di mercato, finiranno con il creare nuove finestre di opportunità.


Vero ma, come dico dicevo prima, quelle più importanti sono già state ratificate. Fra le più importanti rimaste ancora da ratificare manca quella vettoriale, che sta avendo un lunghissimo travaglio.


In compenso c'e' ancora spazio e tempo per aggiungere nuove istruzioni in base alle esigenze concrete che sono già emerse e che emergeranno.
C'è inoltre RV32E che non è ancora congelata e che potrebbe essere "ritoccata" in vari modi, prevedendo anche cosa fare con RV32EC.

raxas
19-01-2021, 19:57
"Homo homini papȳrus magnum."(cit.)

(traduco vah... "l'uomo è un grande papiro per l'altro uomo" :asd: )

aggiungo :D magari qualcuno non lo sa, che è una riedizione, ed adattamento :D,
della frase latina "Homo homini lupus" (trad. Ogni uomo è un lupo per l'altro uomo) espressione in campo socio-antropologico, più conosciuta di Thomas Hobbes, filosofo inglese, e prima ancora di Plauto, scrittore latino
ancora questi tizi non conoscevano i notevoli dibattiti in materia digitale-informatica, meritori comunque :D
(senza riferimento necessario ad altro genere di papiri :D )

cdimauro
23-01-2021, 08:26
Stiamo costruendo una vera e propria muraglia di testo. :D
Nahhh Ormai sta crollando, e oggi gli diamo una bella scorzatura. :fagiano:
Soltanto "accelerazione hardware integrata" ? :mbe:

Il Merced aveva nella descrizione del layout del chip un unico blocco denominato "instruction fetch and decode" e due altri blocchi denominati "IA-32 Control" ed "IA-64 Control".
intel_itanium.jpg (http://cpudb.stanford.edu/system/die_photos/photos/000/000/036/large/intel_itanium.jpg).
Quindi a valle del decoder c'erano due sottosistemi di esecuzione separate ma il decoder poteva decodificare direttamente entrambi i set di istruzioni (probabilmente l'IA-64 in modo più efficiente, per ovvi motivi, ma pur sempre di decodifica in hardware si trattava)

Il successivo McKinley aveva un "IA-32 Engine" ancora più complesso
(vedere pagina 8 di questo pdf (https://www.cse.msu.edu/~cse820/lectures/Itanium.pdf))
ma anche in quel caso il codice x86 era seguito in hardware, non con l'ausilio di software che si appoggiasse ad acceleratori hardware integrati per l'esecuzione!
In entrambi i casi x86 veniva sostanzialmente emulato, sfruttando dell'accelerazione hardware per agevolare il compito. Lo si può vedere dalle slide che hai riportato, a partire da pag. 32, di cui riporto alcune parti:
"IA-32 Support:
Done with hardware emulation

32 Bit Hardware Emulation

Less than 1% of the chip devoted to Hardware Emulation"
In particolare è da notare quest'ultima frase, che dimostra quanto poco spazio sia stato dato all'accelerazione hardware per aiutare l'emulatore x86.

Comunque se leggi quelle slide lo vedi tu stesso che era veramente poca cosa.
Solo dopo nelle versioni che seguirono il decoder istruzioni x86 ed il resto della logica di controllo esecuzione furono eliminati (presumibilmente con ancora alcune estensioni che semplificasseo l'emulazione x86, ma di quello non sono sicuro).
No, sembra che sia stata totalmente rimossa l'accelerazione hardware, e che l'emulazione fosse soltanto software. Ne parlano anche le slide, in cui riportano che l'emulatore software era addirittura più veloce, per cui non c'era proprio alcun motivo per continuare a sprecare silicio (per quanto fosse poco) per questa funzionalità.
Sono d'accordo con te, era una brutta pezza, ma funzionava e non penalizzava troppo le prestazioni in modalità retrocompatibile,
Ma infatti: assolutamente nulla dire sui risultati. E' il come sia stato fatto che non mi va a genio. :p
ricordo anche che a suo tempo circolava voce che Intel avesse a sua volta preparato un evoluzione a 64bit degli x86 incompatibile con x86-64 di AMD, ma che poi non se ne fece niente perchè Microsoft si rifiutò di supportare un altro set di istruzioni dopo il bagno di sangue di Itanium.
Viene da chiedersi cosa avessero preparato, forse una modalità a 64bit molto più innovativa ? Oppure avevano deciso di estendere a 64bit gli 8 registri interi e poco altro ?
Sì, anche Intel fu costretta a preparare la sua estensione a 64 bit di x86. Purtroppo non c'è nessuna informazione in merito, ma visti i tempi ben più stretti rispetto ad AMD, e al fatto che di x86-64 ormai si conosceva tutto, probabilmente avrà realizzato una pezza estremamente simile.
Avere immediatamente codice assembly che forse-funziona-forse-no ?
Se era relativamente complesso, come minimo lo avrebbero dovuto passare al setaccio con code review multiple.
Se era relativamene semplice, sempre per gli stessi motivi conveniva riscriverlo a mano in modo da sfruttare bene i registri e le istruzioni disponibili.
Non servivano code review, nemmeno multiple. Come già detto, il codice prodotto dalla traduzione era già funzionante (ovviamente tolta roba come codice automodificante, o inserimento inline di codice binario in mezzo all'assembly): non serviva nulla. E girava pure più veloce.

L'8086 ebbe successo proprio per quello, e rimane uno use-case studiato. Come lo è stato anche il 68HC12 di Motorola, che ha seguito una strada molto simile.
Mi ricordo come erano i due set d'istruzioni e passare da una cpu all'altra
era così: https://www.youtube.com/watch?v=S9WWz95ripA&list=RDrJ2WqmKLsuY&index=9 :yeah:
LOL :D Mi sarei fermato alla sola parte iniziale... :oink: Bella anche la canzone: non conoscevo il gruppo. Grazie. :P

Per il resto, beh, sì, le istruzioni erano diverse, ma molte erano in comune. Ma l'8086 risultava pure più semplice da programmare, IMO, e anche questo potrebbe aver invogliato al passaggio.
Concordo sulla botta di culo, ma i cambiamenti che inevitabilmente ci saranno in futuro a livello di tecnologie e di mercato, finiranno con il creare nuove finestre di opportunità.
Per eventuali concorrenti. Spero... :fagiano:
In compenso c'e' ancora spazio e tempo per aggiungere nuove istruzioni in base alle esigenze concrete che sono già emerse e che emergeranno.
Per lo più sarà appannaggio di estensioni custom, come peraltro avviene già da tempo.
C'è inoltre RV32E che non è ancora congelata e che potrebbe essere "ritoccata" in vari modi, prevedendo anche cosa fare con RV32EC.
Sì, non è stata ancora ratificata (dopo anni di discussioni), ma dovrebbe essere a buon punto.

Ma non è vista molto bene, ed è ritenuta sostanzialmente inutile, perché a fronte di una riduzione dell'area del chip provoca anche una riduzione della densità del codice e prestazioni inferiori. Lo ha dimostrato Patterson in un talk di giusto qualche anno fa.