Pamięć nie jest płaska! Wręcz przeciwnie – dostęp do pamięci operacyjnej jest nierównomierny, a tworzenie wydajnego oprogramowania polega na umiejętnym wykorzystaniu podsystemu pamięci wraz z całą jego wielopoziomową hierarchią.
Prezentacja miała miejsce 29 kwietnia 2015, w ramach odbywających się barcampów organizowanych przez Semihalf.
2. Kto mówi?
● Inżynier systemów wbudowanych
● Linux, ARMv7, ARMv8
● ...które mają 16GB RAM
3. Kto mówi?
● Inżynier systemów wbudowanych
● Linux, ARMv7, ARMv8
● ...które mają 16GB RAM
● ...40 Gb/s przepustowość sieci
4. Kto mówi?
● Inżynier systemów wbudowanych
● Linux, ARMv7, ARMv8
● ...które mają 16GB RAM
● ...40 Gb/s przepustowość sieci
● ...i są wbudowane w rack
5. Quiz
#define N (1024 * 1024)
long a[N];
void quiz(unsigned step) {
unsigned i;
for (i = 0; i < N; i += step)
a[i] *= 3;
}
6. Relatywny koszt quiz(1), quiz(2)...?
#define N (1024 * 1024)
long a[N];
void quiz(unsigned step) {
unsigned i;
for (i = 0; i < N; i += step)
a[i] *= 3;
}
Przemnóż co n-ty
element tablicy.
19. Czas dostępu do pamięci - ARM
* 4x Cortex A15 1.60 GHz
L1
16KB
L2
4MB
20. Wnioski
● 1ns - średnio 2 cykle CPU (2GHz)
● 1 cykl ~ 1 operacja dodawania (mnożenia)
● Większy cache - dłuższy dostęp
● Dostęp do DDR prawie nie zależy od CPU
● Zasada lokalności
33. Kod pomiarowy
void benchmark(long id)
{
struct list *l = list;
unsigned iters = iterations;
while (iters--)
{
l->pad[id] += 1; // synchronizacja cache
l = l->next;
}
}
34. Hyper-threading
● Dwa (więcej) “logiczne” wątki dzielą jeden
rdzeń
● Wspólny cache L1
● Tania synchronizacja (przez L1, nie L3)
● Większe zużycie cache (nawet 50% na
wątek)
● SPARC T5 (2012) - 8 wątków, 16 rdzeni
35. Plan
1. Cache i RAM
2. Dostęp nie taki znowu swobodny
3. Dostęp lepiej niż sekwencyjny
4. Współbieżność a pamięć
5. Optymalizacja kodu
36. Techniki poprawy lokalności danych
● Tablice jako główny “kontener” danych
● Rozkładanie pól w strukturach / klasach
● Podział danych na lokalne i wspólne
● Alternatywne metody alokacji pamięci
○ Pule pamięci
○ inne implementacje malloc()
○ HugeTLB
39. Lokalna optymalizacja struktur / klas
struct Bad {
int flags;
long a[7];
int counter;
};
$ pahole -C Bad test_prog
struct Bad {
int flags; /* 0 4 */
/* XXX 4 bytes hole, try to pack */
long int a[7]; /* 8 56 */
/* --- cacheline 1 boundary (64 bytes) --- */
int counter; /* 64 4 */
/* size: 72, cachelines: 2, members: 3 */
/* sum members: 64, holes: 1, sum holes: 4 */
/* padding: 4 */
/* last cacheline: 8 bytes */
};
40. Pakiet dwarves - program “pahole”
● Rozmieszczenie pól w pamięci
● “przerwy” w strukturach
● wypełnienie na końcu struktury
● sugeruje reorganizację (opcja -R)
● diagnozuje problemy z niezgodnością
struktur (łatwo porównać wydruki)
41. Lokalna optymalizacja struktur c.d
struct Good {
int flags;
int counter;
long a[7];
};
$ pahole -C Good test_prog
struct Good {
int flags; /* 0 4 */
int counter; /* 4 4 */
long int array[7]; /* 8 56 */
/* --- cacheline 1 boundary (64 bytes) --- */
/* size: 64, cachelines: 1, members: 3 */
};
42. Poprawiamy struktury c.d.
struct Pretty {
int flags; /* 0 4 */
int counter; /* 4 4 */
long int array[7]; /* 8 56 */
/* -- cacheline 1 boundary (64 bytes) -- */
long int not_used; /* 64 8 */
/* size: 72, cachelines: 2, members: 4 */
/* last cacheline: 8 bytes */
};
struct Ugly {
long int not_used; /* 0 8 */
long int array[7]; /* 8 56 */
/* -- cacheline 1 boundary (64 bytes) -- */
int flags; /* 64 4 */
int counter; /* 68 4 */
/* size: 72, cachelines: 2, members: 4 */
/* last cacheline: 8 bytes */
};
44. Unikanie false sharing - inne CC
● Wyrównanie = rozmiar zmiennej
struct Shared {
struct producer prod;
/* -- nowa linijka cache -- */
struct {
...
char pad[64 - SIZE];
} cons; /* cons ma rozmiar 64B i wyrównanie 64B */
};
45. Alternatywy dla malloc() - pula
● Stały rozmiar obiektów
● Minimalny czas alokacji/zwalniania
● Bezpieczne dla wielu wątków
● Oparte na tablicach! (cyklicznych)
◌
wolne
zajęte
46. Alternatywy dla malloc() c.d.
● jemalloc()
○ Firefox od wersji 3
● libhugetlb
○ Przyspiesza użycie pamięci wirtualnej
○ 2MB strony zamiast 4KB
○ Dobre dla dużych zbiorów danych
49. Podsumowanie
● Jeśli nie wiadomo o co chodzi….
○ to chodzi o cache
● Pomiar, pomiar, pomiar…
○ perf top -e cache-misses
● Drobne zmiany mają znaczenie
○ Rozkład pól w strukturze
■ 2X mniej pamięci!
● Może zmieścimy się w cache L1?
50. Do poduchy
● Urlich Depper: “What every programmer
should know about memory”
● “Learn more about CUDA” http://www.nvidia.
com/object/cudau_ucdavis