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]