Lezione 7 di 7 · 25 min di lettura

Sfida finale

Un ripasso di tutto il modulo e una sfida da risolvere da solo, collegata al motivo per cui Mojo esiste - quanta energia costa addestrare un modello, e quanta se ne risparmia con un kernel più veloce.

Guarda quanta strada

In sei lezioni hai installato Mojo, capito come passa dal sorgente al codice macchina e imparato la grammatica di base del linguaggio. Prima della sfida, un ripasso compatto: se una riga non ti torna, torna alla lezione indicata.

La pagina da tenere accanto

CosaCome si scriveLezione
Laboratoriouv init --bare learn-mojo, uv add mojo, source .venv/bin/activatePerché Mojo
Eseguire / compilaremojo file.mojo, mojo build file.mojo -o nomeHello, World!
Formattaremojo format .Il laboratorio
Punto d’ingressodef main(): (o def main() raises:)Hello, World!
Stampaprint(a, b, sep=", ", end="")Hello, World!
Variabilevar x = 1, var y: Float32 = 2.5, var z: IntVariabili e tipi
Costantecomptime NAME = 42 (anche fuori da main)Variabili e tipi
ConversioniFloat64(n), Int(x), String(n), Int("42")Variabili e tipi
Divisioni tra Intcon a = -7 e b = 2: a / b fa -3, a // b fa -4, a % b fa 1Operatori
Letterali7 / 2 fa 3.5, 0.1 + 0.2 fa 0.3 (calcolati esatti in compilazione)Operatori
Logicaand, or, not, a if cond else b, 1 < x < 9Operatori
Aggiornarex += 1, x //= 2, x **= 2Operatori
Testot"{x} + 1 = {x + 1}", String("a", 1)Stampare e formattare
Arrotondareround(x, 2)Stampare e formattare
Allineares.ascii_ljust(10, "."), s.ascii_rjust(2, "0")Stampare e formattare
Lunghezzes.byte_length(), s.count_codepoints(), s.count_graphemes()Stampare e formattare

E tre regole che ti eviteranno la maggior parte degli errori di compilazione:

  1. Il codice sta dentro le funzioni; fuori, solo comptime, import e dichiarazioni.
  2. Una variabile nasce con var e non cambia mai tipo.
  3. I tipi non si mescolano da soli: Int con Int, Float64 con Float64, e le conversioni si scrivono.

Quiz di controllo

Quiz

Con var a = 10 e var b = 4, cosa stampa print(Float64(a / b))?

Quiz

Quale di queste righe, dentro main, compila?

Quiz

Con var word = "città", cosa succede con print(len(word))?

La sfida: l’impronta di un addestramento

Nella prima lezione abbiamo detto che la velocità è anche energia. Mettiamolo in numeri. Un gruppo di ricerca addestra un modello su 64 GPU, ognuna delle quali assorbe 700 W, per 240 ore. Il data center ha un PUE di 1,2 e l’elettricità che usa emette 300 g di CO₂ per kWh. Poi qualcuno riscrive in Mojo il kernel che domina il calcolo, e l’addestramento diventa 1,6 volte più veloce.

I numeri sono plausibili (700 W è il consumo massimo di una GPU da data center di fascia alta) ma inventati: non descrivono un modello reale.

Dettagli nerd Cos'è il PUE di un data center?

Il PUE (Power Usage Effectiveness) è il rapporto tra l’energia consumata dall’intero data center e quella consumata dai soli computer. Un PUE di 1,2 significa che per ogni kWh assorbito dai server se ne spendono altri 0,2 in raffreddamento, conversione della corrente, illuminazione e rete. Il valore ideale è 1,0; i data center più efficienti si avvicinano a 1,1, quelli più vecchi superano 1,5. Moltiplicare il consumo dei server per il PUE dà il consumo reale.

Allo stesso modo, i grammi di CO₂ per kWh (l’intensità carbonica della rete elettrica) dipendono da come è prodotta l’elettricità: pochi grammi con idroelettrico e nucleare, centinaia con il gas, quasi mille con il carbone. Lo stesso calcolo, in un paese diverso, può avere un’impronta dieci volte diversa.

Esercizio · sul tuo computer

L'impronta di un addestramento

Crea footprint.mojo che stampi esattamente:

output
TRAINING RUN
GPUs ............... 64
Hours .............. 240
Energy (kWh) ....... 12902.4
CO2 (t) ............ 3.87
---------------------------
WITH A 1.6x FASTER KERNEL
Hours .............. 150
Energy saved (kWh) . 4838.4
CO2 saved (kg) ..... 1451.5
Saved .............. 37.5%

Requisiti:

  • tutti i dati di partenza (64, 700, 240, 1.2, 300, 1.6) sono costanti comptime in cima al file;
  • tutto il resto è calcolato: energia in kWh = GPU × watt × ore ÷ 1000 × PUE; CO₂ in kg = kWh × grammi per kWh ÷ 1000;
  • con il kernel più veloce le ore e l’energia si dividono per 1,6; “saved” è la differenza rispetto al caso originale, e la percentuale è l’energia risparmiata sul totale;
  • le etichette, con uno spazio finale, sono allineate a 20 caratteri con ascii_ljust(20, "."), seguite dal valore (lascia che sia print a mettere lo spazio in mezzo);
  • energia e CO₂ in kg arrotondate a 1 decimale, le tonnellate a 2, la percentuale a 1; le ore stampate come interi;
  • la riga di separazione è fatta di 27 trattini, e si scrive senza contarli a mano: "-" * 27 ripete una stringa;
  • il titolo della seconda sezione usa una t-string con la costante del fattore di velocità.

Suggerimenti: le costanti intere e quelle decimali non si mescolano da sole, quindi converti con Float64(...) dove serve; Int(...) trasforma le ore in intero per la stampa.

Mostra una soluzione (prima prova da solo!)
footprint.mojo
comptime GPUS = 64
comptime WATTS_PER_GPU = 700
comptime HOURS = 240
comptime PUE = 1.2  # data centre overhead: cooling, power supplies, network
comptime GRAMS_CO2_PER_KWH = 300
comptime SPEEDUP = 1.6


def main():
    var hours = Float64(HOURS)
    var kwh = Float64(GPUS * WATTS_PER_GPU) * hours / 1000.0 * PUE
    var co2_kg = kwh * Float64(GRAMS_CO2_PER_KWH) / 1000.0

    var fast_hours = hours / SPEEDUP
    var fast_kwh = kwh / SPEEDUP
    var saved_kwh = kwh - fast_kwh
    var saved_co2_kg = saved_kwh * Float64(GRAMS_CO2_PER_KWH) / 1000.0
    var saved_percent = saved_kwh / kwh * 100.0

    print("TRAINING RUN")
    print("GPUs ".ascii_ljust(20, "."), GPUS)
    print("Hours ".ascii_ljust(20, "."), Int(hours))
    print("Energy (kWh) ".ascii_ljust(20, "."), round(kwh, 1))
    print("CO2 (t) ".ascii_ljust(20, "."), round(co2_kg / 1000.0, 2))
    print("-" * 27)
    print(t"WITH A {SPEEDUP}x FASTER KERNEL")
    print("Hours ".ascii_ljust(20, "."), Int(fast_hours))
    print("Energy saved (kWh) ".ascii_ljust(20, "."), round(saved_kwh, 1))
    print("CO2 saved (kg) ".ascii_ljust(20, "."), round(saved_co2_kg, 1))
    print("Saved ".ascii_ljust(20, "."), t"{round(saved_percent, 1)}%")

Nota l’ultima riga: print accetta anche una t-string come argomento, accanto a una stringa normale.

Cosa succede nel Modulo 2

Il tuo scontrino e la tua impronta di CO₂ ripetevano lo stesso codice più volte, e non potevano prendere decisioni. Nel prossimo modulo arrivano gli strumenti per farlo:

  • funzioni con argomenti e tipi di ritorno, return, argomenti con nome e valori di default;
  • decisioni con if, elif, else;
  • cicli con for e while, range, break e continue;
  • le prime regole su come Mojo passa i valori alle funzioni, che sono il cuore della sua velocità.