Două thread-uri pot modifica variabile complet diferite și totuși să își reducă drastic performanța reciproc. Motivul: variabilele se află în aceeași cache line, iar protocolul de coerență trebuie să transfere ownership-ul liniei între nuclee de fiecare dată când unul dintre thread-uri scrie.
Acesta este false sharing. Nu există neapărat lock contention și nici aceeași adresă accesată simultan. Problema apare deoarece hardware-ul gestionează coerența la granularitatea cache line-ului, frecvent 64 bytes, nu la nivelul variabilelor C/C++. Kernelul Linux recomandă perf c2c împreună cu pahole tocmai pentru localizarea acestor situații.
Confirmă că perf c2c este suportat
Verifică mai întâi instrumentul:
perf --version
perf c2c --help
Vezi evenimentele disponibile:
sudo perf c2c record -e list
perf c2c folosește mecanisme hardware diferite în funcție de arhitectură: precise load/store events pe Intel, IBS pe anumite procesoare AMD și SPE pe Arm64. Suportul nu este identic pe toate procesoarele; documentația actuală menționează explicit că Zen 3 nu este suportat de perf c2c.
Nu presupune că lipsa rezultatelor înseamnă lipsa false sharing-ului dacă PMU-ul procesorului nu poate furniza evenimentele necesare.
Înregistrează workload-ul problematic
Pentru o aplicație pe care o poți porni direct:
sudo perf c2c record -- \
./myapp --benchmark
Pentru profiling system-wide timp de 20 de secunde:
sudo perf c2c record -- -a -g sleep 20
În acest interval reprodu exact problema: aceleași thread-uri, număr de worker-e, request rate și CPU affinity.
perf c2c înregistrează adresa accesată, tipul accesului, latența și CPU-ul implicat, apoi grupează informațiile după cache line pentru a evidenția zonele cu contention ridicat.
Deschide raportul și caută HITM
Rulează:
sudo perf c2c report
Sau pentru output text:
sudo perf c2c report --stdio
În primul rând urmărește cache line-urile cu valori mari pentru:
LclHitm
RmtHitm
Total HITM
HITM înseamnă Hit Modified: un load găsește linia modificată în cache-ul altui CPU și trebuie rezolvată coerența înainte ca accesul să continue.
RmtHitm este în special important pe sisteme NUMA, deoarece ownership-ul poate trece între nuclee aflate pe noduri diferite. Raportul afișează separat cache line-urile scumpe și apoi distribuția acceselor pe offset-uri în interiorul fiecărei linii.
Identifică exact cele două thread-uri
Pentru mai multe detalii per thread:
sudo perf c2c report \
--coalesce=tid,iaddr
Raportul poate afișa:
Cacheline: 0x7f...c800
Offset PID TID Symbol
0x00 4812 4813 worker_a
0x08 4812 4814 worker_b
Dacă două TID-uri accesează offset-uri diferite ale aceleiași cache line, iar cel puțin unul efectuează scrieri, ai un candidat foarte puternic pentru false sharing.
Dacă ambele thread-uri modifică aceeași variabilă, problema este mai degrabă true sharing sau contention legitim. perf c2c identifică cache-line contention; interpretarea offset-urilor îți spune ce tip de sharing ai. Documentația kernelului definește false sharing prin acces concurent la date aflate în aceeași linie, cu cel puțin un writer.
Mapează offset-ul la structura din cod
Pentru un program C/C++ compilat cu debug information:
pahole ./myapp | less
Pentru o structură cunoscută:
pahole -C worker_stats ./myapp
Poți descoperi:
struct worker_stats {
uint64_t requests; /* offset 0 */
uint64_t errors; /* offset 8 */
};
Dacă thread-ul A actualizează requests, iar thread-ul B actualizează errors, ambele câmpuri pot locui în aceeași linie.
Kernelul recomandă corelarea offset-urilor perf c2c cu layout-ul produs de pahole pentru identificarea membrilor exacți ai structurii.
Repară și măsoară din nou
O soluție posibilă este separarea datelor frecvent modificate:
struct worker_stats {
alignas(64) uint64_t requests;
alignas(64) uint64_t errors;
};
Alternativ, folosește structuri per-thread/per-CPU și agregă valorile mai rar.
Nu adăuga padding peste tot. Alinierea agresivă crește memoria consumată și presiunea asupra cache/TLB. Kernelul recomandă separarea datelor hot doar când măsurătorile justifică modificarea.
Recompilează și repetă exact același test:
sudo perf c2c record -- ./myapp --benchmark
sudo perf c2c report --stdio
Compară HITM, throughput și latența aplicației înainte și după. Dacă linia problematică dispare din top, dar performanța nu se schimbă, ai eliminat false sharing-ul fără ca acesta să fi fost principalul bottleneck — situație perfect posibilă într-un sistem complex.
Surse folosite
Linux Kernel Documentation — False Sharing, cauze, detectare cu perf c2c, pahole și strategii de reducere.
Linux perf documentation — perf c2c, HITM, cache line contention, PID/TID, offset-uri și Source.
Red Hat Enterprise Linux Documentation — interpretarea rapoartelor perf c2c și identificarea shared cache lines

















































