Skip to main content

Cyber AI România

Marți, 29 septembrie 2026

False Sharing cu perf c2c: cum găsești două thread-uri care se luptă pentru aceeași cache line

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

Facebook
X
WhatsApp

Te-ar putea interesa si: