Zawsze zastanawiałem się, dlaczego procesory zatrzymały się przy 32 rejestrach. To zdecydowanie najszybszy element maszyny, dlaczego nie stworzyć większych procesorów z większą liczbą rejestrów? Czy nie oznaczałoby to mniejszego korzystania z pamięci RAM?
computer-architecture
Matt Capone
źródło
źródło
Odpowiedzi:
Po pierwsze, nie wszystkie architektury procesorów zatrzymały się przy 32 rejestrach. Prawie wszystkie architektury RISC, które mają 32 rejestry ujawnione w zestawie instrukcji, faktycznie mają 32 rejestry liczb całkowitych i 32 więcej rejestrów zmiennoprzecinkowych (czyli 64). (Zmienny punkt „dodaj” używa innych rejestrów niż liczba całkowita „dodaj”.) Architektura SPARC ma okna rejestrów. Na SPARC można uzyskać dostęp tylko do 32 rejestrów całkowitych naraz, ale rejestry działają jak stos i można przesuwać i wyskakiwać nowe rejestry 16 jednocześnie. Architektura Itanium HP / Intel miała 128 liczb całkowitych i 128 rejestrów zmiennoprzecinkowych ujawnionych w zestawie instrukcji. Nowoczesne procesory graficzne NVidia, AMD, Intel, ARM i Imagination Technologies ujawniają ogromną liczbę rejestrów w swoich plikach rejestrów. (Wiem, że tak jest w przypadku architektur NVidia i Intel, nie znam się dobrze na zestawach instrukcji AMD, ARM i Imagination, ale myślę, że pliki rejestrów też są tam duże).
Po drugie, większość współczesnych mikroprocesorów implementuje zmianę nazw rejestrów, aby wyeliminować niepotrzebną serializację spowodowaną koniecznością ponownego wykorzystania zasobów, więc podstawowe pliki rejestrów fizycznych mogą być większe (96, 128 lub 192 rejestrów na niektórych komputerach). To (i dynamiczne planowanie) eliminuje niektóre z potrzeba, aby kompilator wygenerował tak wiele unikalnych nazw rejestrów, jednocześnie zapewniając większy harmonogram dla harmonogramu.
Istnieją dwa powody, dla których może być trudno zwiększyć liczbę rejestrów ujawnionych w zestawie instrukcji. Po pierwsze, musisz być w stanie określić identyfikatory rejestru w każdej instrukcji. 32 rejestry wymagają 5-bitowego specyfikatora rejestru, więc instrukcje 3-adresowe (wspólne w architekturach RISC) wydają 15 z 32 bitów instrukcji tylko na określenie rejestrów. Jeśli zwiększysz to do 6 lub 7 bitów, będziesz miał mniej miejsca na określenie kodów i stałych. Procesory graficzne i Itanium mają znacznie większe instrukcje. Większe instrukcje mają swoją cenę: musisz użyć więcej pamięci instrukcji, więc zachowanie pamięci podręcznej instrukcji jest mniej idealne.
Drugim powodem jest czas dostępu. Im większa jest pamięć, tym wolniejszy jest dostęp do danych z niej. (Po prostu z podstaw fizyki: dane są przechowywane w przestrzeni dwuwymiarowej, więc jeśli przechowujesz bitów, średnia odległość do określonego bitu wynosi .) Plik rejestru jest tylko mała pamięć wieloportowa, a jednym z ograniczeń zwiększania jej jest to, że w końcu trzeba będzie zacząć wolniej taktować maszynę, aby pomieścić większy plik rejestru. Zwykle pod względem całkowitej wydajności jest to strata.n O(n−−√)
źródło
Jeszcze tylko dwa powody ograniczenia liczby rejestrów:
źródło
Dużo kodu ma wiele dostępów do pamięci (30% to typowa liczba). Poza tym zwykle około 2/3 dostępu to odczyt, a 1/3 dostępu to dostęp do zapisu. Nie dzieje się tak z powodu wyczerpania rejestrów, ale dostępu do tablic, dostępu do zmiennych elementów obiektu itp.
Trzeba to zrobić w pamięci (lub w pamięci podręcznej danych) ze względu na sposób tworzenia C / C ++ (wszystko, co można uzyskać, musi mieć adres, który musi być potencjalnie przechowywany w pamięci). Jeśli kompilator zgadnie, że nie będziesz chciał pisać do zmiennych za pomocą szalonych sztuczek pośrednich, umieści je w rejestrach, i działa to świetnie w przypadku zmiennych funkcyjnych, ale nie w przypadku globalnie dostępnych (ogólnie wszystko, co pochodzi z malloc ()), ponieważ nie można zgadnąć, jak zmieni się stan globalny.
Z tego powodu nie jest powszechne, że kompilator będzie w stanie zrobić wszystko z ponad 16 rejestrami ogólnego zastosowania. Dlatego wszyscy popularni architekci mają ich tak wiele (ARM ma 16).
MIPS i inne RISC mają zwykle 32, ponieważ nie jest tak trudno mieć tyle rejestrów - koszt jest wystarczająco niski, więc jest to trochę „dlaczego nie?”. Ponad 32 jest w większości bezużyteczne i ma wadę polegającą na tym, że dostęp do pliku rejestru jest dłuższy (każdy podwojenie liczby rejestrów potencjalnie dodaje dodatkową warstwę multiplekserów, co dodaje nieco więcej opóźnienia ...). Średnio wydłuża również instrukcje - co oznacza, że podczas uruchamiania programów zależnych od przepustowości pamięci instrukcji dodatkowe rejestry spowalniają cię!
Jeśli twój procesor jest w porządku i nie zmienia nazwy rejestru i próbujesz wykonać wiele operacji na cykl (więcej niż 3), to teoretycznie potrzebujesz więcej rejestrów, gdy liczba operacji na cykl rośnie. Właśnie dlatego Itanium ma tak wiele rejestrów! Ale w praktyce, oprócz kodu zmiennoprzecinkowego lub kodu zorientowanego na SIMD (w którym Itanium był naprawdę dobry), większość kodów będzie miała wiele odczytów / zapisów i skoków pamięci, co uniemożliwi realizację tego marzenia o ponad 3 operacjach na cykl (szczególnie w oprogramowaniu serwerowym, takim jak bazy danych, kompilatory, wykonywanie języka wysokiego poziomu, takie jak javascript, emulacja itp.). Właśnie to zatopiło Itanium.
Wszystko sprowadza się do różnicy między obliczeniami a wykonywaniem!
źródło
Kto ci mówi, że procesor ma zawsze 32 rejestry? x86 ma 8, ARM 32-bit i x86_64 ma 16, IA-64 ma 128 i wiele innych liczb. Możesz zajrzeć tutaj . Nawet MIPS, PPC lub dowolna architektura, która ma 32 rejestry ogólnego przeznaczenia w zestawie instrukcji, liczba ta jest znacznie większa niż 32, ponieważ zawsze istnieją rejestry flag (jeśli istnieją), rejestry kontrolne ... bez rejestrów o zmienionej nazwie i rejestrów sprzętowych
Wszystko ma swoją cenę. Im większa liczba rejestrów, tym więcej pracy wykonujesz podczas przełączania zadań, tym więcej miejsca potrzebujesz na kodowanie instrukcji. Jeśli masz mniej rejestrów, nie musisz dużo zapisywać i przywracać podczas wywoływania i powracania z funkcji lub przełączania zadań z kompromisem braku rejestrów w niektórych kodach obszernych obliczeniowo
Co więcej, im większy plik rejestru, tym będzie on droższy i bardziej złożony. SRAM to najszybsza i najdroższa pamięć RAM, więc jest używana tylko w pamięci podręcznej procesora. Ale wciąż jest znacznie tańszy i zajmuje mniej miejsca niż plik rejestru o tej samej pojemności.
źródło
Na przykład typowy procesor Intel ma „oficjalnie” 16 rejestrów liczb całkowitych i 16 wektorów. Ale w rzeczywistości jest o wiele więcej: procesor używa „zmiany nazwy rejestru”. Jeśli masz instrukcję reg3 = reg1 + reg2, miałbyś problem, gdyby inna instrukcja korzystająca z reg3 jeszcze się nie zakończyła - nie możesz wykonać nowej instrukcji, jeśli zastąpi ona reg3, zanim zostanie odczytana przez poprzednią instrukcję.
Dlatego istnieje około 160 rzeczywistych rejestrów. Tak więc powyższa prosta instrukcja została zmieniona na „regX = reg1 + reg2 i pamiętaj, że regX zawiera reg3”. Bez rejestrów zmian nazw, wykonywanie poza kolejnością byłoby absolutnie martwe w wodzie.
źródło
Nie jestem inżynierem elektrykiem, ale myślę, że inną przyczyną z powodu ograniczenia liczby rejestrów jest routing. Liczba jednostek arytmetycznych jest ograniczona i muszą one być w stanie pobierać dane z każdego rejestru i wyprowadzać dane do każdego rejestru. Jest to szczególnie prawdziwe, gdy masz programy potokowe, które mogą wykonywać wiele instrukcji na cykl.
Prosta wersja tego miałaby złożoność, uniemożliwiając skalowanie rejestrów, lub w inny sposób wymagałaby przeprojektowania routingu do czegoś o wiele bardziej skomplikowanego, aby trasować wszystko z większą złożonością.O(n2)
Pomysł na tę odpowiedź przyszedł mi po obejrzeniu niektórych wypowiedzi Iwana Godarda na temat procesora Mill. Częścią innowacji Mill CPU jest to, że nie można wyprowadzać danych do dowolnych rejestrów - wszystkie wyjścia są wypychane na stos rejestru lub „pas”, co zmniejsza problemy z routingiem, ponieważ zawsze wiadomo, dokąd pójdzie wyjście. Zauważ, że nadal mają problem z routingiem w celu uzyskania rejestrów wejściowych do jednostek arytmetycznych.
Zobacz The Mill CPU Architecture - the Belt (2 of 9), aby znaleźć opis problemu i rozwiązanie Mill.
źródło
Jeśli chodzi o MIPS ISA, Hennessy and Patterson, Computer Organisation and Design 4th edition str. 176, odpowiada bezpośrednio na to konkretne pytanie:
źródło