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.
Koszt quiz(n) dla 1 <= n < 16 czas (ms) step
Koszt quiz(n) dla 1 <= n < 16 czas (ms) 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. 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
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. 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
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. 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
Dostęp sekwencyjny Czas odczytu (ns) Ilość bajtów * 3 gen Corei-7 2.20GHz
Dostęp sekwencyjny Czas odczytu (ns) 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 Load 0x80 Load 0xC0... 0x0... 0x40 0x80... 0xC0
Lmbench - par_mem Ilość równoległych operacji Ilość bajtów * 3 gen Corei-7 2.20GHz
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
Wiele wątków na raz - false sharing Czas odczytu (ns) Ilość bajtów * 3 gen Corei-7 2.20GHz
Wiele wątków na raz - false sharing Czas odczytu (ns) 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. 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
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; /* 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 */ };
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 */ /* 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 */ };
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ę! mjc@semihalf.com