profiling prima di ottimizzare
ottimizzare senza misurare crea regressioni. identifica il collo di bottiglia con dati reali e un carico rappresentativo, poi intervieni in modo mirato.
regola: misura, cambia una cosa, misura di nuovo.
flag di compilazione
# debug + simboli
clang++ -std=c++20 -O0 -g main.cpp -o app
# release
clang++ -std=c++20 -O2 -march=native main.cpp -o app
usa -O2 per release, -O3 solo se hai benchmark che mostrano benefici reali.
benchmark stabili
tieni il codice fuori da I/O e usa std::chrono con loop ripetuti.
#include <chrono>
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 100000; ++i) {
compute();
}
auto end = std::chrono::high_resolution_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
ripeti 5-10 volte e scarta i valori estremi per una media pulita.
allocazioni e move
- usa
reservesu vector per evitare riallocazioni. - preferisci passaggio per riferimento costante.
- sfrutta move semantics per evitare copie pesanti.
std::vector<int> values;
values.reserve(1024);
std::string payload = build();
std::string moved = std::move(payload);
località dati
strutture compatte e accessi sequenziali sono più veloci della logica complessa.
| scelta | impatto |
|---|---|
| array of struct | migliore per accesso lineare ai record |
| struct of arrays | migliore per vettorizzazione e cache |
strumenti
- perf o Instruments per il profilo cpu.
- valgrind o heaptrack per memoria.
- sanitizers (
-fsanitize=address) per bug nascosti.
checklist finale
- benchmark replicabili con input reale.
- ottimizza solo le funzioni nel top 5% di costo.
- riduci allocazioni e copia dati il meno possibile.
- verifica sempre con sanitizers dopo i cambiamenti.
panoramica
In questo capitolo su performance e profiling, misura, ottimizza e scala: workflow completo per codice veloce. L'obiettivo è trasformare i concetti in micro-pattern riutilizzabili con esempi piccoli e verificabili.
Lavora in sequenza: leggi, prova, modifica gli snippet e annota i trade-off principali (performance, leggibilità, manutenzione).
badge: performance
obiettivi
- capire e applicare profiling prima in uno scenario reale
- capire e applicare flag di compilazione in uno scenario reale
- capire e applicare benchmark stabili in uno scenario reale
- capire e applicare allocazioni e move in uno scenario reale
scheda rapida
#include <iostream>
#include <vector>
int main() {
std::vector<int> dati{1, 2, 3};
for (auto &v : dati) {
v *= 2;
}
for (const auto &v : dati) {
std::cout << v << " ";
}
std::cout << "\n";
return 0;
}
Adatta questo scheletro agli esempi della lezione e sostituisci i dati con il tuo dominio.
tips
- compila con warning elevati
- preferisci RAII
- usa const ovunque possibile
- misura prima di ottimizzare
- usa -O2/-O3
- riduci allocazioni in loop
tip: Ottimizzare senza misure è solo ipotesi.
mini progetto
Confronta due approcci di calcolo.
- implementa due varianti
- misura il tempo
- ripeti più volte
- annota differenze
output atteso: uno script o query ripetibile con risultati verificabili.