Cos'è un sistema di calcolo?
Martedì 22 febbraio 2022 09:00
Prima Parte Pagina 1
Prima Parte Pagina 2
Prima Parte Pagina 3
Mercoledì 23 febbraio 2022 09:00
Miniaturizzazione e VLSI
Le CPU reali utilizzano un procedimento di miniaturizzazione, chiamato Very Large Scale Integration (VLSI), che consente di realizzare circuiti visibili esclusivamente al microscopio. Le CPU di ultima generazione contengono milioni di transistor.
È possibile combinare le porte logiche per costruire circuiti più complessi, noti come circuiti combinatori, che realizzano funzioni booleane arbitrarie. In un'espressione, gli operatori hanno priorità, dalla maggiore alla minore: NOT, AND, OR.
Hanno una nozione di stato, ovvero una memoria di eventi accaduti nel passato. La realizzazione tipica usata nei calcolatori elettronici è sincrona e prevede un temporizzatore (clock) che invia impulsi in cui un segnale elettrico oscilla tra acceso e spento con una determinata frequenza.
Il segnale si propaga in un circuito elettronico a velocità variabili, che dipendono da vari fattori inclusa la temperatura. Per questo e altri motivi, come la dissipazione di calore, la frequenza di clock di una CPU non può superare una certa soglia salvo generare instabilità e inaffidabilità nel sistema.
Prima Parte Pagina 4
Un segnale inviato all'ingresso S (set) imposta a 1 l'uscita Q, mentre uno inviato su R (reset) la imposta a 0. Si ha Q' = NOT Q. Se nessun segnale viene inviato su S e su R, il flip-flop mantiene l'ultimo stato in cui è stato posto. Se viene inviato un segnale simultaneamente su S e su R, lo stato del flip-flop diviene indefinito. Di per sé un flip-flop SR è asincrono, ma se sollecitato da un oscillatore si comporta in modo sincrono e può cambiare stato solo durante una pulsazione.
Prima Parte Pagina 5
Sistemi operativi
I sistemi di calcolo più complessi si basano su sistemi operativi, ovvero software sviluppati per consentire l'esecuzione di applicazioni (programmi) sull'hardware disponibile.
- Gestione dei processi, ovvero dei programmi in esecuzione.
- Allocazione delle risorse ai processi, come memoria principale (RAM), secondaria (dischi), e connessioni di rete.
- Misurazione e gestione del tempo.
- Gestione delle utenze per consentire a più utenti di usare il sistema mediante l'assegnazione di privilegi di accesso alle risorse disponibili.
- Comunicazione tra processi che girano in locale sulla stessa macchina o su sistemi di calcolo distinti connessi da una rete.
- Gestione degli errori che possono emergere durante l'esecuzione dei processi o del sistema stesso.
- Protezione e sicurezza, isolando i processi affinché non possano interferire con altri processi, con il sistema operativo o con l'hardware, ad esempio esfiltrando dati o manomettendone il funzionamento in modo malevolo o per via di errori di programmazione (bug).
Obiettivi di progettazione
- Multitasking, ovvero la possibilità di avere varie applicazioni simultaneamente in esecuzione.
- Preemption, ovvero la possibilità di togliere il controllo della CPU a un processo per darlo a un altro processo.
- Progresso e assenza di starvation, ovvero l'assegnazione periodica della CPU ai processi per consentirne il progresso della computazione.
- Alto throughput, ovvero massimizzazione del numero di istruzioni eseguite dal sistema nell'unità di tempo.
- Bassa latenza, ovvero minimizzazione del tempo richiesto dalle singole operazioni svolte dal sistema operativo. Importante in ambienti real-time, dove il sistema deve rispondere rapidamente alle sollecitazioni esterne.
Hanno la possibilità di richiamare funzionalità offerte da librerie software oppure chiedere servizi direttamente al sistema operativo invocando funzioni wrapper che passano il controllo al sistema operativo effettuando chiamate a sistema (system call).
Programmi e librerie aderiscono a un insieme di convenzioni definite da una particolare Application Binary Interface (ABI), che definisce ad esempio il modo in cui i parametri vengono passati a una funzione e come questa restituisce un valore al chiamante. Un programma eseguibile per la piattaforma usata si basa inoltre su una specifica Instruction Set Architecture (ISA), che definisce lo stato della CPU, le sue istruzioni, e l'effetto delle istruzioni sullo stato.
I programmi girano normalmente in una modalità a privilegi ridotti, detta modalità utente, che impedisce loro di effettuare operazioni potenzialmente pericolose per il sistema. Quando un processo esegue codice del sistema operativo a seguito di una system call, passa in modalità supervisore (o sistema, o kernel), acquisendo privilegi completi nell'esecuzione della system call per poter avere il pieno controllo della macchina.
Il passaggio del controllo di un programma al sistema operativo (ovvero al suo kernel, o nucleo) per effettuare chiamate a sistema avviene normalmente mediante il meccanismo degli interrupt. Un interrupt è un evento che interrompe il flusso di esecuzione del programma e passa il controllo a codice del sistema operativo, cambiando modalità di esecuzione in modo che il programma abbia privilegi più alti. Un interrupt può essere generato dalla CPU stessa oppure da eventi esterni come la pressione di un tasto sulla tastiera.
I moduli principali del kernel del sistema operativo, attivati mediante interrupt, sono adibiti alla gestione dei processi, della memoria, di file e I/O in genere, e del tempo.
- Il modulo di esecuzione dei processi è adibito al caricamento di un programma eseguibile (loading), alla sua schedulazione (assegnazione della CPU), alla gestione degli interrupt, al mantenimento delle informazioni sull'esecuzione in una struttura chiamata Process Control Block (PCB) e alla gestione dei segnali, un meccanismo di notifica di eventi tra processi e tra sistema operativo e processi.
- Il modulo di gestione della memoria fornisce nei sistemi operativi moderni un meccanismo di virtualizzazione della memoria in modo che ogni processo veda una porzione tutta sua e non sia possibile per un processo accedere alla memoria di un altro processo senza che quest'ultimo ne sia a conoscenza. Questo meccanismo di protezione impedisce ad esempio a un programma malevolo o difettoso di accedere allo spazio di memoria di un altro programma alternandone il contenuto. La virtualizzazione è basata su una separazione tra memoria fisica e memoria logica accessibile ai programmi. Un altro aspetto della gestione della memoria riguarda l'allocazione dello spazio logico disponibile ai programmi stessi.
- Il modulo di gestione dei file e dell'I/O in generale si occupa di soddisfare le richieste di uso dei dischi e di dispositivi da parte dei programmi. Importanti sono i driver, componenti software che forniscono un'interfaccia standard verso il kernel astraendo le caratteristiche specifiche dei dispositivi esterni.
- Il modulo di gestione del tempo fornisce al kernel e alle applicazioni funzionalità per la misurazione del tempo reale e del tempo speso attivamente sulla CPU su base singolo processo.
L'uso dell'hardware da parte di un programma avviene come segue:
- La CPU può essere usata dal programma in modalità utente senza il tramite del sistema operativo. Questo avviene quando il programma gira in modalità utente.
- Ogni altra interazione con l'hardware è mediata dal sistema operativo.
Prima Parte Pagina 6
Come viene programmato un sistema di calcolo?
Martedì 1 marzo 2022 09:00
Prima Parte Pagina 7
Prima Parte Pagina 8
Sintassi AT&T
Mercoledì 2 marzo 2022 09:00
Tipi di dato
| Tipo di dato | Suffisso | Dimensione | Corrispondenza macchina | Assembly | Tipi C |
|---|---|---|---|---|---|
| Byte | b | 1 byte (8 bit) | (unsigned) char | ||
| Word | w | 2 byte (16 bit) | (unsigned) short | ||
| Double word | l | 4 byte (32 bit) | (unsigned) int | indirizzo di memoria | (unsigned) long |
| Quad word | q | 8 byte (64 bit) | Indirizzo di memoria per x86_64 |
Prima Parte Pagina 9
Prima Parte Pagina 10
Prima Parte Pagina 11
Prima Parte Pagina 12
If/if-else in Assembly
Martedì 8 marzo 2022 09:00
Prima Parte Pagina 13
Prima Parte Pagina 14
While/for in Assembly
Mercoledì 9 marzo 2022 09:00
Prima Parte Pagina 15
Prima Parte Pagina 16
Prima Parte Pagina 17
Aritmetica dei puntatori
Martedì 15 marzo 2022 09:00
Prima Parte Pagina 18
Prima Parte Pagina 19
Mercoledì 16 marzo 2022 09:00
c=a char c short c int c c=a unsigned char c unsigned short c unsigned int cchar a Spostamento Down-cast Down-cast unsigned Spostamento Down-cast Down-castmovb %cl, %al movb %cl, %al movb %cl, %al char a movb %cl, %al movb %cl, %al movb %cl, %alshort a Up-cast Spostamento Down-cast unsigned Up-cast Spostamento Down-castmovsbw %cl, %ax movw %cx, %ax movw %cx, %ax short a movzbw %cl, %ax movw %cx, %ax movw %cx, %axint a Up-cast Up-cast Spostamento unisgned Up-cast Up-cast Spostamentomovsbl %cl, %eax movswl %cx, %eax movl %ecx, %eax int a movzbl %cl, %eax movzwl %cx, %eax movl %ecx, %eax
Prima Parte Pagina 20
Prima Parte Pagina 21
Prima Parte Pagina 22
Approfondimenti sull'ABI
Martedì 22 marzo 2022 09:00
Prima Parte Pagina 23
Prima Parte Pagina 24
Mercoledì 23 marzo 2022 09:00
Prima Parte Pagina 25
Prima Parte Pagina 26
Prima Parte Pagina 27
Prima Parte Pagina 28
Introduzione
Martedì 29 marzo 2022 09:00
Seconda Parte Pagina 29
Tipi di errori
Mercoledì 30 marzo 2022 14:33
Seconda Parte Pagina 30
Seconda Parte Pagina 31
Funzioni di libreria per la gestione della memoria
Martedì 5 aprile 2022 09:00
Seconda Parte Pagina 32
Seconda Parte Pagina 33
Funzioni di libreria per la gestione binaria (byte a byte) di stream
Mercoledì 6 aprile 2022 09:00
Seconda Parte Pagina 34
Seconda Parte Pagina 35
Ottimizzazione dei programmi
Martedì 12 aprile 2022 09:00
Seconda Parte Pagina 36
Seconda Parte Pagina 37
Profilazione automatica
Mercoledì 20 aprile 2022 09:00
Seconda Parte Pagina 38
Seconda Parte Pagina 39
Ulteriori ottimizzazioni del compilatore
Martedì 26 aprile 2022 09:00
Seconda Parte Pagina 40
Seconda Parte Pagina 41
Seconda Parte Pagina 42
Immagine di memoria di un processo
Mercoledì 27 aprile 2022 09:00
Seconda Parte Pagina 43
Seconda Parte Pagina 44
Seconda Parte Pagina 45
Esecuzione dei programmi
Martedì 3 maggio 2022 09:00
L'esecuzione di un programma, quindi di ogni istruzione che lo compone, è suddivisa dall'hardware in diverse sotto-operazioni che coinvolgono le varie parti della CPU:
- Unità di controllo
- Registri
- Unità aritmetico-logica (o ALU)
- Interfaccia verso la memoria e l'I/O
Le CPU sono tipicamente organizzate in stadi che sono delegati a portare a termine l'esecuzione delle sottoparti di un'istruzione, quindi ogni istruzione viene eseguita dalla CPU attivando nella corretta sequenza una serie di stadi di esecuzione.
Gli stadi basati su un'architettura RISC del processore sono:
- Fetch (F): l'istruzione corrente viene prelevata dalla memoria e viene calcolato l'indirizzo dell'istruzione che segue la corrente in memoria;
- Decode (D): viene interpretata l'istruzione, eventuali operandi immediati dell'istruzione vengono letti, così come eventuali registri di input dell'istruzione;
- Execute (E): se richiesto dall'istruzione, l'unità aritmetico-logica esegue un'operazione;
- Memory (M): se richiesto dall'istruzione, la memoria di sistema viene acceduta in lettura o scrittura;
- Write-Back (W): se richiesto dall'istruzione, i registri di output vengono aggiornati.
Storicamente le CPU erano divise, in base alle istruzioni dell'ISA che potevano essere processate, in:
- RISC (Reduced Instruction Set Computer):
- Numero ridotto di istruzioni
- Hardware più semplice
- Frequenze di clock più alte
- CISC (Complex Instruction Set Computer):
- Più istruzioni disponibili
- Hardware più complesso ⇒ più transistor ⇒ più consumo energetico
- Frequenze di clock più basse
Questa divisione è molto importante nella scrittura del codice in Assembly, ma risulta nascosta al compilatore. Inoltre, oggi i processori sono una via di mezzo tra RISC e CISC, poiché possono essere processate istruzioni più complesse che vengono tradotte, automaticamente dal sistema di calcolo all'insaputa del compilatore e del programmatore, in linguaggio micro-architetturale basato sul processore RISC.
- Il calcolo di ciascuno stadio richiede tipicamente qualche centinaio di picosecondi (10-12 sec).
- La sequenza di stadi viene ripetuta per ogni istruzione eseguita.
- Per scandire il tempo e consentire l'attivazione dei circuiti combinatori viene usato un orologio (clock) che crea un segnale elettrico.
- La frequenza di clock, vale a dire il numero di oscillazioni al secondo (cicli di clock) del segnale, misura pertanto la velocità con cui vengono eseguite le istruzioni, assumendo che la frequenza sia costante nel tempo.
- Ciclo di clock := distanza tra due fronti di salita consecutivi.
- L'idea del pipelining nasce dall'osservazione che i diversi stadi impegnano porzioni diverse della circuiteria della CPU.
- In principio quindi, quando un'istruzione lascia uno stadio di fetch per entrare in quello di decode, si potrebbe immediatamente procedere a caricare una nuova istruzione, come in una catena di montaggio.
- Consente di ottenere un certo grado di parallelismo in cui più di un'istruzione è in esecuzione simultanea (Instruction-Level Parallelism, IPL).
- Il tempo per istruzione (latenza) non cambia (anzi, potrebbe leggermente crescere per via della maggiore complessità dell'hardware con pipelining).
- Si ha un impatto invece sul numero di istruzioni eseguite nell'unità di tempo (throughput), che in condizioni ideali può aumentare di un fattore pari al numero di stadi.
- La temporizzazione di una CPU con pipelining assume che ogni stadio richieda un ciclo di clock, con frequenze di clock più alte.
- L'esecuzione sequenziale delle tre istruzioni richiede 15 cicli di clock.
- L'esecuzione con pipelining delle tre istruzioni richiede 7 cicli di clock.
Seconda Parte Pagina 46
Purtroppo, vi sono varie ragioni (hazard) per cui non è sempre possibile avere una pipeline sempre a regime ("piena") con le istruzioni in esecuzione durante il ciclo designato e ottenere quindi il throughput ideale.
Ci sono vari tipi di hazard:
- Hazard strutturali: due o più istruzioni richiedono di usare simultaneamente lo stesso componente hardware durante lo stesso ciclo di clock come ad esempio la memoria;
- Si noti come al ciclo di clock 4 due istruzioni chiedono di accedere contemporaneamente alla memoria: istr1 per leggere un dato, istr4 per prelevare l'istruzione.
- Questo particolare tipo di hazard è in realtà mitigato dalla presenza di memorie tampone (cache) distinte per dati e istruzioni.
- Hazard strutturali possono coinvolgere anche altri componenti (registri, ALU) e possono essere in genere risolti duplicando l'hardware oppure mediante la tecnica dello stallo.
- Hazard sui dati: vi sono dipendenze fra i dati su cui operano istruzioni differenti come ad esempio un'istruzione che ha come input l'output di quella precedente;
- Il tipo di hazard sui dati viene normalmente risolto dall'hardware, con una penalità sul tempo di esecuzione, mettendo in stallo la pipeline tramite l'inserimento di "bolle" che prendono il posto delle istruzioni senza però impegnare nessuno stadio.
- L'inserimento di "bolle" riduce il throughput.
- Un altro modo di mitigare gli hazard sui dati, effettuato non dall'hardware ma dal compilatore o dal programmatore che scrive direttamente in assembly, si ha modificando l'ordine delle istruzioni tramite una tecnica di ottimizzazione chiamata instruction scheduling che, però, non sempre è possibile. Il riordinamento è possibile se sia l'ordine delle istruzioni sia le istruzioni stesse sono indipendenti tra loro.
- Hazard sul controllo:
- L'esecuzione di un'istruzione condizionale necessita una predizione (branch prediction) sul ramo che verrà preso per poter continuare a caricare istruzioni.
- Se la predizione è errata (branch misprediction) è necessario svuotare la pipeline e ripartire con la sequenza di istruzioni giusta.
- Tecnica dello "stallo".
- Tecnica di "branch prediction" utilizzata dalla CPU per cercare di "indovinare" quale sarà la prossima istruzione da eseguire.
- Dal punto di vista del compilatore/programmatore, una tecnica molto efficace è cercare di ridurre i salti condizionati rimpiazzandoli con istruzioni che non alterano il flusso del controllo (program counter).
- Queste istruzioni, come la CMOV, vengono dette branchless.
Seconda Parte Pagina 47
Flusso del controllo eccezionale
Mercoledì 4 maggio 2022 09:00
- Un programma normalmente segue un flusso del controllo determinato dalle istruzioni di salto o semplicemente dal susseguirsi delle istruzioni in memoria.
- Si parla di flusso del controllo eccezionale ogni volta che il program counter (registro EIP in IA32) di un core della CPU assume un valore che sposta l'esecuzione in una zona di codice non conforme con il normale flusso del controllo.
- Il flusso del controllo eccezionale viene spesso utilizzato per gestire situazioni anomale, ma non solo.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.