Pobierz prezentację z tego wydarzenia.

Transkrypt

Pobierz prezentację z tego wydarzenia.
Kto mówi?
● Inżynier systemów wbudowanych
● Linux, ARMv7, ARMv8
Kto mówi?
● Inżynier systemów wbudowanych
● Linux, ARMv7, ARMv8
● ...które mają 16GB RAM
Kto mówi?
●
●
●
●
Inżynier systemów wbudowanych
Linux, ARMv7, ARMv8
...które mają 16GB RAM
...40 Gb/s przepustowość sieci
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
Quiz
#define N (1024 * 1024)
long a[N];
void quiz(unsigned step) {
unsigned i;
for (i = 0; i < N; i += step)
a[i] *= 3;
}
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.
czas (ms)
Koszt quiz(n) dla 1 <= n < 16
step
czas (ms)
Koszt quiz(n) dla 1 <= n < 16
quiz(1) ~ quiz(8) !
step
$ Perf stat ./quiz <N>
●
●
●
●
●
0,997 CPUs utilized
3,141 GHz
13,33% frontend cycles idle
3,02 instructions per cycle
Wysokie IPC -> procesor
zajęty
●
●
●
●
●
0,997 CPUs utilized
3,114 GHz
84,84% frontend cycles idle
0,52 instructions per cycle
Niskie IPC -> procesor
bezczynny
Hierarchia pamięci
Dlaczego pamięć nie jest płaska
Maciej Czekaj
Plan
1.
2.
3.
4.
5.
Cache i RAM
Dostęp nie taki znowu swobodny
Dostęp lepiej niż sekwencyjny
Współbieżność a pamięć
Optymalizacja kodu
Architektura pamięci - Intel Core i7
●
●
●
●
DDR - osobno
L2 - kod i dane
L3 - wspólny
RAM <-> CPU przez
L1, L2, L3
● CPU <-> CPU?
Cache to znaczna część krzemu i
ciągle rośnie!
*http://www.hardwarezone.com.sg/tech-news-intel-launches-its-4th-generation-haswell-processors
Prawo Moore’a działa wybiórczo
*http://www.techdesignforums.com/practice/files/2013/02/tdf-snps-ARMcc-feb13-fig1lg.jpg
Plan
1.
2.
3.
4.
5.
Cache i RAM
Dostęp nie taki znowu swobodny
Dostęp lepiej niż sekwencyjny
Współbieżność a pamięć
Optymalizacja kodu
Czas dostępu do pamięci - Intel
* 3 gen Corei-7 2.20GHz
Czas dostępu do pamięci - Intel
L3
8MB
L2
256KB
L1
32KB
* 3 gen Corei-7 2.20GHz
Czas dostępu do pamięci - ARM
* 4x Cortex A15 1.60 GHz
Czas dostępu do pamięci - ARM
L2
4MB
L1
16KB
* 4x Cortex A15 1.60 GHz
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
Program pomiarowy
struct list {
struct list *next;
/* Zmienne wypełnienie */
long pad[0];
};
Program pomiarowy
void benchmark(void)
{
struct list *l = list;
unsigned iters = iterations;
while (iters--)
{
l = l->next;
}
}
// “Skacz” do kolejnej linijki
Plan
1.
2.
3.
4.
5.
Cache i RAM
Dostęp nie taki znowu swobodny
Dostęp lepiej niż sekwencyjny
Współbieżność a pamięć
Optymalizacja kodu
Czas odczytu (ns)
Dostęp sekwencyjny
Ilość bajtów
* 3 gen Corei-7 2.20GHz
Czas odczytu (ns)
Dostęp sekwencyjny
Częściowo
L3
L2
L1
Ilość bajtów
* 3 gen Corei-7 2.20GHz
Wracamy do quizu
$ perf stat -e L1-dcache-loads,L1-dcache-load-misses ./quiz 7
7 115.0
Performance counter stats for './quiz 7':
155435733 L1-dcache-loads
134733981 L1-dcache-load-misses
#
86,68% of all L1-dcache hits
$ perf stat -e L1-dcache-loads,L1-dcache-load-misses ./quiz 1
1 125.4
Performance counter stats for './quiz 1':
1075973403 L1-dcache-loads
134758255 L1-dcache-load-misses
#
12,52% of all L1-dcache hits
Prefetch
● Wczytywanie z wyprzedzeniem
● Działa dobrze w pętlach
● Iteracja po tablicy gwarantuje prefetch
Load 0x00
...
Load 0x40
0x0
...
Load 0x80
Load 0xC0
0x40
0x80
...
0xC0
Lmbench - par_mem
Ilość równoległych
operacji
Ilość bajtów
* 3 gen Corei-7 2.20GHz
Plan
1.
2.
3.
4.
5.
Cache i RAM
Dostęp nie taki znowu swobodny
Dostęp lepiej niż sekwencyjny
Współbieżność a pamięć
Optymalizacja kodu
Czas odczytu (ns)
Wiele wątków na raz - false sharing
Ilość bajtów
* 3 gen Corei-7 2.20GHz
Czas odczytu (ns)
Wiele wątków na raz - false sharing
Cache L3 - punkt
wymiany danych
Ilość bajtów
* 3 gen Corei-7 2.20GHz
Kod pomiarowy
struct list
{
struct list *next;
long pad[15];
};
Kod pomiarowy
void benchmark(long id)
{
struct list *l = list;
unsigned iters = iterations;
while (iters--)
{
l->pad[id] += 1; // synchronizacja cache
l = l->next;
}
}
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
Plan
1.
2.
3.
4.
5.
Cache i RAM
Dostęp nie taki znowu swobodny
Dostęp lepiej niż sekwencyjny
Współbieżność a pamięć
Optymalizacja kodu
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
Problemy z obiektami
● Sktruktury wskaźnikowe a zasada lokalności
Obiekty przyjazne dla cache
● Grupowe zarządzanie obiektami
● Alokacja w tablicach
Lokalna optymalizacja struktur / klas
struct Bad {
int flags;
long a[7];
int counter;
};
$ pahole -C Bad test_prog
struct Bad {
int flags;
/* XXX 4 bytes hole, try to
long int a[7];
/* --- cacheline 1 boundary
int counter;
/*
/*
/*
/*
};
/*
0
4 */
pack */
/*
8
56 */
(64 bytes) --- */
/*
64
4 */
size: 72, cachelines: 2, members: 3 */
sum members: 64, holes: 1, sum holes: 4 */
padding: 4 */
last cacheline: 8 bytes */
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)
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 */
};
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 */
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 */
/* size: 72, cachelines: 2, members: 4 */
/* last cacheline: 8 bytes */
};
};
Unikanie false sharing - GCC
struct Shared {
struct producer prod;
/* -- nowa linijka cache -- */
struct consumer cons
__attribute__((aligned(64)));
} ;
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 */
Alternatywy dla malloc() - pula
wolne
◌
●
●
●
●
Stały rozmiar obiektów
Minimalny czas alokacji/zwalniania
Bezpieczne dla wielu wątków
Oparte na tablicach! (cyklicznych)
zajęte
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
Podsumowanie
● Jeśli nie wiadomo o co chodzi….
Podsumowanie
● Jeśli nie wiadomo o co chodzi….
○ to chodzi o cache
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?
Do poduchy
● Urlich Depper: “What every programmer
should know about memory”
● “Learn more about CUDA” http://www.nvidia.
com/object/cudau_ucdavis
Pytania?
Dziękuję!
[email protected]