Przede wszystkim dostęp do pamięci głównej jest bardzo drogi. Obecnie procesor 2GHz (najwolniejszy raz) ma taktyki (cykle) 2G na sekundę. CPU (obecnie wirtualny rdzeń) może pobierać wartość ze swoich rejestrów raz na takt. Ponieważ wirtualny rdzeń składa się z wielu jednostek przetwarzających (ALU - jednostka arytmetyczno-logiczna, FPU itp.), Może on faktycznie przetwarzać pewne instrukcje równolegle, jeśli to możliwe.
Dostęp do pamięci głównej kosztuje około 70ns do 100ns (DDR4 jest nieco szybszy). Tym razem po prostu wyszukuje pamięć podręczną L1, L2 i L3, a następnie trafia do pamięci (wyślij polecenie do kontrolera pamięci, który wysyła je do banków pamięci), poczekaj na odpowiedź i gotowe.
100ns oznacza około 200 kleszczy. Zasadniczo, jeśli program zawsze pomija pamięci podręczne, do których każdy uzyskuje dostęp do pamięci, procesor spędziłby około 99,5% swojego czasu (jeśli tylko czyta pamięć) bezczynnie, czekając na pamięć.
Aby przyspieszyć działanie, istnieją pamięci podręczne L1, L2, L3. Wykorzystują pamięć umieszczoną bezpośrednio na chipie i wykorzystują różnego rodzaju układy tranzystorowe do przechowywania danych bitów. Zajmuje to więcej miejsca, więcej energii i jest bardziej kosztowne niż pamięć główna, ponieważ procesor jest zwykle wytwarzany przy użyciu bardziej zaawansowanej technologii, a awaria produkcyjna w pamięci L1, L2, L3 może spowodować, że procesor stanie się bezwartościowy (wada), więc duże pamięci podręczne L1, L2, L3 zwiększają współczynnik błędów, co zmniejsza wydajność, co bezpośrednio zmniejsza zwrot z inwestycji. Istnieje więc ogromny kompromis, jeśli chodzi o dostępny rozmiar pamięci podręcznej.
(obecnie tworzy się więcej pamięci podręcznych L1, L2, L3, aby móc dezaktywować pewne części, aby zmniejszyć prawdopodobieństwo, że rzeczywistą wadą produkcyjną są obszary pamięci podręcznej, które renderują defekt procesora jako całości).
Aby dać wyobrażenie o czasie (źródło: koszty dostępu do pamięci podręcznych i pamięci )
- Pamięć podręczna L1: 1ns do 2ns (2-4 cykle)
- Pamięć podręczna L2: od 3ns do 5ns (6-10 cykli)
- Pamięć podręczna L3: 12ns do 20ns (24-40 cykli)
- RAM: 60ns (120 cykli)
Ponieważ mieszamy różne typy procesorów, są to tylko szacunki, ale dają dobre wyobrażenie o tym, co naprawdę się dzieje, gdy wartość pamięci jest pobierana i możemy mieć trafienie lub chybienie w określonej warstwie pamięci podręcznej.
Tak więc pamięć podręczna zasadniczo znacznie przyspiesza dostęp do pamięci (60 ns w porównaniu do 1 ns).
Pobieranie wartości, przechowywanie jej w pamięci podręcznej w celu ponownego odczytania jest dobre dla zmiennych, które są często używane, ale w przypadku operacji kopiowania pamięci byłoby nadal zbyt wolne, ponieważ po prostu czyta się wartość, zapisuje ją gdzieś i nigdy nie czyta wartości znowu ... brak trafień w pamięci podręcznej, śmiertelnie wolne (poza tym może się to zdarzyć równolegle, ponieważ mamy wykonanie poza kolejnością).
Ta kopia pamięci jest tak ważna, że istnieją różne sposoby jej przyspieszenia. We wczesnych latach pamięć często była w stanie kopiować pamięć poza CPU. Był obsługiwany bezpośrednio przez kontroler pamięci, więc operacja kopiowania pamięci nie zanieczyszczała pamięci podręcznych.
Ale oprócz zwykłej kopii pamięci, dość powszechny był inny dostęp szeregowy do pamięci. Przykładem jest analiza szeregu informacji. Posiadanie tablicy liczb całkowitych i obliczanie sumy, średniej, średniej lub nawet prostsze znalezienie określonej wartości (filtr / wyszukiwanie) to kolejna bardzo ważna klasa algorytmów uruchamianych za każdym razem na dowolnym procesorze ogólnego przeznaczenia.
Zatem analizując wzorzec dostępu do pamięci, okazało się, że dane są bardzo często odczytywane sekwencyjnie. Istniało duże prawdopodobieństwo, że jeśli program odczyta wartość pod indeksem i, to program odczyta również wartość i + 1. To prawdopodobieństwo jest nieco większe niż prawdopodobieństwo, że ten sam program odczyta również wartość i + 2 i tak dalej.
Tak więc mając adres pamięci, dobrym pomysłem było (i nadal jest) czytanie z wyprzedzeniem i pobieranie dodatkowych wartości. To jest powód, dla którego istnieje tryb doładowania.
Dostęp do pamięci w trybie boost oznacza, że adres jest wysyłany i wiele wartości jest wysyłanych sekwencyjnie. Każde dodatkowe wysłanie wartości zajmuje tylko około dodatkowych 10ns (lub nawet mniej).
Kolejnym problemem był adres. Wysłanie adresu wymaga czasu. Aby zaadresować dużą część pamięci, należy wysłać duże adresy. Na początku oznaczało to, że magistrala adresowa nie była wystarczająco duża, aby wysłać adres w jednym cyklu (tik) i potrzeba więcej niż jednego cyklu, aby wysłać adres, dodając więcej opóźnienia.
Na przykład wiersz pamięci podręcznej o wielkości 64 bajtów oznacza, że pamięć jest podzielona na odrębne (nie nakładające się) bloki pamięci o rozmiarze 64 bajtów. 64 bajty oznaczają, że adres początkowy każdego bloku ma najniższe sześć bitów adresu, które zawsze są zerami. Zatem wysyłanie tych sześciu bitów zerowych za każdym razem nie jest potrzebne, zwiększając przestrzeń adresową 64 razy dla dowolnej liczby szerokości szyny adresowej (efekt powitalny).
Kolejnym problemem, który rozwiązuje linia pamięci podręcznej (poza czytaniem z wyprzedzeniem i zapisywaniem / zwalnianiem sześciu bitów na szynie adresowej) jest sposób organizacji pamięci podręcznej. Na przykład, jeśli pamięć podręczna byłaby podzielona na 8-bajtowe (64-bitowe) bloki (komórki), należy przechowywać adres komórki pamięci, dla której ta komórka pamięci podręcznej przechowuje wartość wraz z nią. Jeśli adres byłby również 64-bitowy, oznacza to, że połowa rozmiaru pamięci podręcznej jest zużywana przez adres, co powoduje 100% narzut.
Ponieważ linia pamięci podręcznej ma 64 bajty, a procesor może używać 64 bitów - 6 bitów = 58 bitów (nie ma potrzeby przechowywania zerowych bitów zbyt dobrze), oznacza to, że możemy buforować 64 bajty lub 512 bitów z narzutem 58 bitów (11% narzutu). W rzeczywistości przechowywane adresy są jeszcze mniejsze, ale istnieją informacje o statusie (takie jak linia pamięci podręcznej jest ważna i dokładna, brudna i musi zostać zapisana w pamięci RAM itp.).
Innym aspektem jest to, że mamy pamięć podręczną z ustawieniami asocjacji. Nie każda komórka pamięci podręcznej może przechowywać określony adres, ale tylko ich podzbiór. To sprawia, że niezbędne przechowywane bity adresu są jeszcze mniejsze, umożliwia równoległy dostęp do pamięci podręcznej (dostęp do każdego podzbioru można uzyskać tylko raz, ale niezależnie od innych podzbiorów).
Jest to szczególnie ważne, jeśli chodzi o synchronizację dostępu do pamięci podręcznej / pamięci między różnymi wirtualnymi rdzeniami, ich niezależnymi wieloma jednostkami przetwarzającymi na rdzeń i wreszcie wieloma procesorami na jednej płycie głównej (na której znajdują się płyty zawierające aż 48 procesorów i więcej).
To jest w zasadzie obecny pomysł, dlaczego mamy linie pamięci podręcznej. Korzyści z czytania z wyprzedzeniem są bardzo duże, a najgorszy przypadek odczytu pojedynczego bajtu z linii pamięci podręcznej i nigdy ponownego odczytu reszty jest bardzo niewielki, ponieważ prawdopodobieństwo jest bardzo małe.
Rozmiar linii pamięci podręcznej (64) jest mądrze dobranym kompromisem między większymi wierszami pamięci podręcznej, co sprawia, że jest mało prawdopodobne, aby ostatni jej bajt został odczytany również w najbliższej przyszłości, czas potrzebny do pobrania całej linii pamięci podręcznej z pamięci (i zapisywać ją z powrotem), a także narzut w organizacji pamięci podręcznej i równoległości dostępu do pamięci podręcznej i pamięci.