Torna ai corsi
AI031 Professional

Sistemi Informatici: Una Prospettiva per Programmatore (Edizione Globale)

Un'approfondita analisi su come i sistemi informatici eseguono programmi e memorizzano informazioni. Questo corso colma il divario tra la programmazione a alto livello e l'hardware sottostante, coprendo la rappresentazione a livello macchina, l'architettura del processore, la gerarchia della memoria e la programmazione concorrente.

5.0
36.0h
955 studenti
0 mi piace
Intelligenza Artificiale
Inizia ad imparare

Panoramica del corso

📚 Riepilogo del contenuto

Un'approfondita analisi su come i sistemi informatici eseguono programmi e memorizzano informazioni. Questo corso colma il divario tra la programmazione ad alto livello e l'hardware sottostante, coprendo la rappresentazione a livello macchina, l'architettura del processore, la gerarchia della memoria e la programmazione concorrente.

Padroneggia l'arte della programmazione di sistema comprendendo l'interfaccia hardware-software.

Autore: Randal E. Bryant, David R. O'Hallaron

Ringraziamenti: Supportato dagli studenti e dai docenti del corso 15-213 presso la Carnegie Mellon University. I ringraziamenti includono contributi di Manasa S. e Mohit Tahiliani.

🎯 Obiettivi di apprendimento

  1. Identificare come le informazioni sono rappresentate tramite bit e contesto all'interno di un sistema.
  2. Tracciare le quattro fasi del sistema di compilazione dal codice sorgente all'eseguibile.
  3. Descrivere la struttura organizzativa dell'hardware e la natura gerarchica dei dispositivi di archiviazione.
  4. Convertire tra notazioni decimale, binaria e esadecimale e spiegare l'indirizzamento a livello macchina (Endianness).
  5. Eseguire operazioni a livello di bit e logiche in C e prevedere i risultati degli shift aritmetici.
  6. Analizzare gli encoding degli interi per identificare vulnerabilità potenziali legate al sovrapposizione e errori di casting.
  7. Analizzare la mappatura tra costrutti C (cicli, ramificazioni, procedure) e istruzioni assembly x86-64.
  8. Scomporre lo stack di runtime per spiegare come vengano passati i parametri, memorizzate le variabili locali e gestiti i richiami ricorsivi.
  9. Valutare i layout di memoria per strutture dati eterogenee e applicare le regole di allineamento per calcolare i requisiti totali di archiviazione.
  10. Definire lo stato visibile al programmatore Y86-64 e codificare/decodificare istruzioni in sequenze di byte.

🔹 Lezione 1: Un tour dei sistemi informatici

Panoramica: Questa lezione fornisce una panoramica completa su come i sistemi informatici rappresentano le informazioni, traducono i programmi ed eseguono istruzioni attraverso complesse interazioni hardware-software. Esplora il viaggio di un programma dal codice sorgente fino all'esecuzione, il ruolo cruciale della gerarchia della memoria nel superare il divario tra processore e memoria, le astrazioni fornite dal sistema operativo e le leggi matematiche che governano le prestazioni e la parallelizzazione del sistema.

Risultati dell'apprendimento:

  • Identificare come le informazioni sono rappresentate tramite bit e contesto all'interno di un sistema.
  • Tracciare le quattro fasi del sistema di compilazione dal codice sorgente all'eseguibile.
  • Descrivere la struttura organizzativa dell'hardware e la natura gerarchica dei dispositivi di archiviazione.

🔹 Lezione 2: Rappresentazione e manipolazione delle informazioni

Panoramica: Questa lezione esplora come i computer digitali rappresentano e manipolano le informazioni a livello di bit. Copre la transizione dalle notazioni esadecimali e dalle dimensioni delle parole a livello macchina agli encodings complessi degli interi (senza segno e complemento a due) e dei numeri in virgola mobile (IEEE 754). Gli studenti analizzeranno le proprietà matematiche dell'aritmetica informatica, inclusi gli impatti sulla sicurezza derivanti dal sovrapposizione e le sfumature dell'arrotondamento nei sistemi con precisione finita.

Risultati dell'apprendimento:

  • Convertire tra notazioni decimale, binaria ed esadecimale e spiegare l'indirizzamento a livello macchina (Endianness).
  • Eseguire operazioni a livello di bit e logiche in C e prevedere i risultati degli shift aritmetici.
  • Analizzare gli encoding degli interi per identificare vulnerabilità potenziali legate al sovrapposizione e errori di casting.

🔹 Lezione 3: Rappresentazione a livello macchina dei programmi

Panoramica: Questa lezione offre un'analisi approfondita su come i programmi C ad alto livello vengano trasformati in codice macchina x86-64. Copre l'architettura fondamentale del processore, inclusi registri e stack, l'implementazione del flusso di controllo (condizioni, cicli e switch), il funzionamento delle chiamate di procedura e della ricorsione, e la rappresentazione a livello macchina di strutture dati complesse come array, struct e unioni. Inoltre affronta la sicurezza del sistema tramite analisi di buffer overflow e le istruzioni specializzate utilizzate per l'aritmetica in virgola mobile.

Risultati dell'apprendimento:

  • Analizzare la mappatura tra costrutti C (cicli, ramificazioni, procedure) e istruzioni assembly x86-64.
  • Scomporre lo stack di runtime per spiegare come vengano passati i parametri, memorizzate le variabili locali e gestiti i richiami ricorsivi.
  • Valutare i layout di memoria per strutture dati eterogenee e applicare le regole di allineamento per calcolare i requisiti totali di archiviazione.

🔹 Lezione 4: Architettura del processore

Panoramica: Questa lezione esplora l'architettura fondamentale di un processore, concentrandosi sulla transizione da un'implementazione sequenziale (SEQ) a un'implementazione ad alte prestazioni in pipeline (PIPE) utilizzando l'Architettura dell'Instruzione Y86-64 (ISA). Gli studenti analizzeranno come le istruzioni siano codificate, elaborate attraverso fasi discrete (Prelevamento, Decodifica, Esecuzione, Memoria, Scrittura-Ritorno), e come gli hazard hardware siano gestiti tramite logica di controllo, attese e forwarding per massimizzare il throughput.

Risultati dell'apprendimento:

  • Definire lo stato visibile al programmatore Y86-64 e codificare/decodificare istruzioni in sequenze di byte.
  • Implementare la logica di controllo hardware usando HCL (Hardware Control Language) per circuiti combinatori e sequenziali.
  • Tracciare il flusso delle istruzioni attraverso le sei fasi di un processore sequenziale e identificare l'impatto del clocking.

🔹 Lezione 5: Ottimizzazione delle prestazioni del programma

Panoramica: Questa lezione esplora l'approccio sistematico per migliorare le prestazioni del programma comprendendo l'interazione tra codice ad alto livello, compilatori ottimizzanti e architetture dei microprocessori moderni. Gli studenti impareranno a identificare "blocchi di ottimizzazione" come l'aliasing della memoria, applicare trasformazioni a basso livello come il loop unrolling e la riassociazione, e utilizzare strumenti di profiling come GPROF per individuare efficacemente i colli di bottiglia delle prestazioni.

Risultati dell'apprendimento:

  • Identificare e mitigare blocchi di ottimizzazione, inclusi aliasing della memoria e overhead delle chiamate di procedura.
  • Quantificare le prestazioni del programma utilizzando il metrica Cicli Per Elemento (CPE).
  • Applicare trasformazioni come loop unrolling, accumulatore multiplo e riassociazione per sfruttare il parallelismo a livello di istruzione.

🔹 Lezione 6: Gerarchia della memoria

Panoramica: Questa lezione esplora la progettazione strutturale e funzionale della gerarchia della memoria, concentrandosi sui compromessi tra velocità, costo e capacità di archiviazione. Dettaglia le tecnologie che alimentano i sistemi moderni — dalla SRAM e DRAM ai dischi e SSD — e spiega come il Principio di Località (temporale e spaziale) permetta a piccole memorie cache veloci di migliorare significativamente le prestazioni del programma. Gli studenti impareranno ad analizzare la mappatura della cache (Direct-Mapped, Set Associative, Fully Associative) e ad applicare tecniche di ottimizzazione come il riordino dei cicli e il blocco per scrivere codice amico della cache.

Risultati dell'apprendimento:

  • Distinguere tra tecnologie di memoria SRAM, DRAM, ROM e Flash e il loro ruolo nella gerarchia.
  • Calcolare la capacità di archiviazione del disco e il tempo totale di accesso basandosi sulla geometria e sui componenti operativi.
  • Analizzare gli indirizzi di memoria per determinare gli indici di set della cache, i tag e gli offset del blocco in diverse strategie di mappatura.

🔹 Lezione 7: Collegamento

Panoramica: Questa lezione esplora il processo fondamentale a livello di sistema del collegamento, che aggrega codice e dati in un singolo file caricabile in memoria ed eseguibile. Gli studenti passeranno dal codice sorgente all'eseguibile finale, comprendendo come i linkers risolvano i riferimenti simbolici, uniscano sezioni tramite ridirezionamento e gestiscano librerie statiche e dinamiche. La lezione si conclude con tecniche avanzate come l'interposizione di librerie e il codice indipendente dal posizionamento (PIC) utilizzato nelle moderne librerie condivise.

Risultati dell'apprendimento:

  • Tracciare la trasformazione dei file sorgente attraverso il driver del compilatore fino all'eseguibile finale.
  • Analizzare i file oggetto ELF per identificare tipi di simboli e organizzazione delle sezioni.
  • Applicare le regole di risoluzione dei simboli per gestire nomi duplicati e dipendenze al momento del collegamento.

🔹 Lezione 8: Flusso di controllo eccezionale

Panoramica: Questa lezione esplora il Flusso di Controllo Eccezionale (ECF), il meccanismo con cui un sistema informatico reagisce ai cambiamenti nello stato del sistema. Esaminiamo come l'ECF sia implementato a tutti i livelli del sistema, dal software hardware-triggered Eccezioni e Switching di contesto e Controllo di processo a livello di sistema operativo (fork, wait, execve) alle Segnali software e ai Salti non locali. Gli studenti impareranno a gestire la concorrenza, trattare gli errori di sistema e scrivere codice robusto e sicuro per i segnali.

Risultati dell'apprendimento:

  • Distinguere tra le quattro categorie di eccezioni a livello hardware (Interruzioni, Interruzioni trap, Faults, Aborts) e i loro meccanismi di gestione.
  • Gestire i cicli di vita dei processi tramite chiamate di sistema per creazione (fork), raccolta (waitpid) ed esecuzione (execve).
  • Implementare gestori di segnali sicuri che tengano conto della concorrenza, dei segnali non in coda e della sicurezza asincrona.

🔹 Lezione 9: Memoria virtuale

Panoramica: Questa lezione esplora la Memoria Virtuale (VM) come astrazione fondamentale che fornisce a ogni processo uno spazio di indirizzamento grande, continuo e privato. Copre i suoi tre ruoli principali: strumento per una caching efficiente nella DRAM, meccanismo per la gestione e la protezione della memoria, e fondamento per la mappatura della memoria. Inoltre, la lezione approfondisce i meccanismi di traduzione degli indirizzi (TLB), l'allocazione dinamica della memoria (gestione dell'heap) e i principi della raccolta automatica dei rifiuti, concludendo con critiche fallacie relative alla memoria nel linguaggio C.

Risultati dell'apprendimento:

  • Distinguere tra indirizzamento fisico e virtuale e descrivere il ruolo dell'Unità di Gestione della Memoria (MMU).
  • Eseguire la traduzione da indirizzo virtuale a fisico utilizzando Tabelle delle Pagine e Buffer di Traduzione (TLB).
  • Analizzare e implementare strategie di allocazione dinamica della memoria, incluse liste esplicite/implicithe e coalescenza.

🔹 Lezione 10: I/O a livello di sistema

Panoramica: Questa lezione esplora l'interfaccia fondamentale tra il sistema operativo Linux e i programmi applicativi per eseguire input e output. Copre le chiamate di sistema Unix di base, i diversi tipi di file incontrati nel filesystem Linux e le strutture di dati a livello kernel usate per gestirli. Introduce inoltre il pacchetto Robust I/O (RIO) per gestire i "short counts" e fornisce linee guida per scegliere tra I/O standard e I/O a livello di sistema in diversi contesti di programmazione, come la programmazione di rete.

Risultati dell'apprendimento:

  • Implementare operazioni di file di base utilizzando l'interfaccia Unix I/O (open, close, read, write).
  • Differenziare tra file regolari, directory e collegamenti mentre si interrogano i metadati dei file tramite stat.
  • Utilizzare il pacchetto RIO per eseguire operazioni di I/O robuste, bufferizzate e non bufferizzate.

🔹 Lezione 11: Programmazione di rete

Panoramica: Questa lezione esplora l'architettura fondamentale delle applicazioni basate su rete, centrata sul modello Client-Server e Internet Globale IP. Gli studenti impareranno a navigare nell'interfaccia Socket — l'API principale per comunicazioni di rete a livello di sistema — e progrediranno verso l'implementazione di un server web funzionale (TINY) in grado di fornire sia file statici che contenuti dinamici tramite l'Interfaccia Comune Gateway (CGI).

Risultati dell'apprendimento:

  • Comprendere il ciclo richiesta-risposta del modello client-server e l'architettura hardware/software dell'Internet Globale IP.
  • Manipolare e convertire indirizzi IP, nomi di dominio e strutture socket utilizzando funzioni indipendenti dal protocollo come getaddrinfo.
  • Implementare un server web iterativo robusto e programmi CGI che utilizzino il controllo dei processi e la redirezione I/O per servire contenuti dinamici.

🔹 Lezione 12: Programmazione concorrente

Panoramica: Questa lezione esplora i modelli fondamentali di concorrenza: processi, multiplexing I/O e thread. Fornisce un'analisi approfondita della sincronizzazione tramite semafori per risolvere le condizioni di competizione, modelli architettonici comuni come produttore-consumatore e server prethreaded, e le metriche utilizzate per valutare le prestazioni parallele. Infine affronta questioni critiche di affidabilità come la sicurezza dei thread, la rientranza e la prevenzione dei deadlock.

Risultati dell'apprendimento:

  • Distinguere tra modelli di concorrenza basati su processi, I/O multiplexed e thread.
  • Applicare operazioni di semaforo (P e V) per garantire l'esclusione mutua e risolvere schemi di sincronizzazione.
  • Calcolare metriche di prestazioni parallele come il guadagno e l'efficienza sotto diverse leggi di scalabilità.