0
Opublikowano 19 marca 2012 w Portal komputerowy » Sprzęt komputerowy » Old school » Przyszłość procesorów wielordzeniowych
 
 

Przyszłość procesorów wielordzeniowych


Chociaż nie miałem takiego obowiązku, napisałem zakończenie! Nikomu się nie chciało, więc stwierdziłem, że ja to zrobię. Na przyszłość jednak wolałbym, aby to użytkownicy Dzikiego sami napisali jakieś zakończenie/a. Uran tworzy dla Was, nie dla siebie. Pamiętajcie o tym kiedy po raz kolejny skieruje do Was jakąś małą prośbę. Tyle tytułem wstępu do tego… zakończenia! Tekst artykułu pt.: „Nowe szaty króla” autorstwa URANA dostępny jest tutaj. ARTYKUŁ ARCHIWALNY.

Niemal wszystkie powyższe rozważania to nadal czysta fantazja. Intel chwali się różnymi zabawkami, a gdy przychodzi do pokazania jak to działa następuje wielki zgrzyt i zatykanie uszu. Rzecz jasna, dodam nieco od siebie, tworząc kolejny wirtualny model CPU. Puściłem przy tym wodze fantazji, ale co mi tam? Ja po prostu chciałbym mieć taki procesor. Mamy kilka dróg rozwoju (tych powszechnie znanych):

  • zwiększanie częstotliwości rdzenia
  • zmiana standardów pamięci
  • zabawa w interface-y procesorów
  • wielordzeniowość
  • HT
  • eksperymenty z nowymi materiałami (rozciągany krzem, nanorurki węglowe, DNA…)
  • itd. itp.

Co zrobią Intel i AMD? W najbliższej przyszłości spróbują pobawić się, a nawet już się bawią w procesory 2-rdzeniowe, potem 4-rdzeniowe, a jaki będzie kolejny krok? To się okaże, wiemy, że idziemy w kierunku multi-core, więc trzymajmy się tego co jest, wydaje się, być pewne.

Dopóki procesor miał jeden rdzeń poruszaliśmy się w sferze schematów. Komu, jeszcze 2-3 lata temu, śniły się dwa procesory w jednej obudowie? Zapewne nieliczni podnieśli rękę. Przede wszystkim musimy zapomnieć o schemacie CPU = x*jednostka stałoprzecinkowa + x*jednostka zmiennoprzecinkowa + cache L1 + cache L2 + … Po co się ograniczać. Skoro mamy dzielić zadania na dwa, dzielmy je na 4, 8, 10, 16. Tak 10! To nie pomyłka. Dlaczego struktury procesorów przyszłości mają być parzyste? Procesory graficzne radzą sobie świetnie niezależnie od tego, czy mają 4, 5, 6 jednostek vertex shader. Mając prawdziwy procesor multi-core, możemy znacznie uprościć architekturę całego układu. Nie będzie np. potrzeby tworzenia kilku modułów cache L2 (zapewne również L3).

Wyobraźmy sobie 12 procesorów pomocniczych APU (Aid Processor Unit), z których 8 zajmuje się obliczeniami stałoprzecinkowymi, a 4 operacjami zmiennoprzecinkowymi. Współpracują one z 3 innymi wysoko wyspecjalizowanymi jednostkami, zajmującymi się organizacją pracy wszystkich elementów całego CPU. Dlaczego zbiory jednostek, a nie zwykłe CPU? Bo po co nam pełna architektura CPU, skoro interesuje nas moc jednostek wykonawczych? Całą resztą niech zajmą się 3 jednostki specjalistyczne. Pierwsza operuje na wszystkich potokach zmiennoprzecinkowych, druga na stałoprzecinkowych. Rozdzielają one zadania i odbierają gotowe wyniki. Cały czas dbają, aby pełna moc układów obliczeniowych była zawsze wykorzystywana. Potoki nie są oczywiście jednakowej długości, bo i po co? Nie są taktowane również takim samym zegarem, bo i po co? W jednych zastosowaniach, lepiej sprawdzą się długie potoki i wyższy zegar (Pentium 4), w innych krótsze potoki (Athlon). Owe jednostki powinny też mieć nieco inaczej rozłożone potoki. W klasycznej architekturze Athlon XP mamy 3 potoki po 3 ALU (jednostki stałoprzecinkowe). Wymarzone cacko, może mieć konstrukcję 4*2, 2*4, 8*1, 2*3 + 2*1. Koniec ze schematami. Jednostki zarządzające poszczególnymi zbiorami jednostek powinny zmieniać schematy według potrzeb chwili. Wewnętrzne, sprzętowe programowanie potoków wykonawczych = potencjalnie nieprawdopodobny wzrost mocy obliczeniowej. Trzeba tym tylko odpowiednio zarządzać. AMD kiedyś przebąkiwało, o nierównomiernym rozłożeniu ALU w Athlonach. Co z tego wyjdzie, okaże się za jakiś czas. Ostatnia jednostka tego potwora, to bardzo mocny układ, w stylu Cell-a, który ma zarządzać dostępem do pamięci cache, ale skonstruowanej na nieco innych zasadach niż obecnie. Winien on stanowić rodzaj zewnętrznej powłoki dla połączonych kilku procesorów. Zewnętrznie jest widziany jeden procesor, wewnętrznie jest ich kilka.

Małe przypomnienie jak działa procesor (bardzo uproszczony schemat). Na żądanie CPU odpowiednie dane są kopiowane z RAM do L2. Stąd instrukcje i dane + adresy wirtualne danych są ładowane do L1. Kiedy następuje zmiana wątku zawartość L1 jest usuwana i napełniana od początku. Jest to całkowicie uzasadnione, ponieważ adresy wirtualne jednego wątku są inne niż adresy drugiego wątku.

Moje wyśnione cacko ma cache L1 o pojemności min. 2 MB, na początek oczywiście, z czasem o wiele więcej. Po co tyle L1, teraz procesory mają 32-128 KB? Gdy „zwykły” procesor przełącza wątki, których pod systemem operacyjnym działa z reguły 200-400, zawartość L1 jest kasowana. Przetwarzany jest zupełnie nowy rejon pamięci wirtualnej i inne instrukcje (kopia L1 w L2 pozostaje). Dlatego m.in. do tej pory mamy CPU z 64 kB L1. Jeżeli dużym L1 będzie zarządzał sprzętowy układ, który dynamicznie przeznaczy odpowiednią jej część dla bardziej obciążających zadań uzyskamy olbrzymi przyrost wydajności. Dla przykładu gramy w „grę X” (lub zestaw aplikacji, które mocno obciążą nawet procesor wielordzeniowy), która operuje na skryptach, do których cały czas się odwołuje. Kiedy system przełącza wątek tracimy adresy stron pamięci wirtualnej skryptów, które system przechowywał w L1.

Kiedy nadchodzi kolej wątku/ów gry, bufor L1 jest ponownie napełniany. Trochę to mało ekonomiczne skoro nasza gra/zestaw programów wykorzystuje 90% mocy procesora. Nasza nowa jednostka zarządzająca przeznaczy dla gry powiedzmy 1,5 MB L1 nie na adresy stron, ale całe strony pamięci z wynikami już wcześniej wielokrotnie powtórzonych operacji, a pozostałe 0.5 MB przeznaczy na adresy stron i instrukcje nie tylko dla „gry”, ale i dla innych wątków. Odpowiednie algorytmy dadzą duży przyrost mocy aplikacjom, które przetwarzają w kółko te same dane. Nie bawimy się tu w żadne sztywne schematy, jednostka zarządzająca ma cały czas monitorować przetwarzane właśnie informacje i w razie potrzeby zmieniać proporcje. Po co takie manewry z dzieleniem cache L1? Oczywiście, żeby było o wiele szybciej. Haczyk tkwi w tym, aby ten wielki bufor odpowiednio wykorzystać. Dlaczego ma on zajmować się tylko jednym wątkiem (jak robi to tradycyjny procesor jednordzeniowy), skoro mamy tak dużo jednostek wykonawczych. Niech przechowuje w pamięci dane i instrukcje dla kilku wątków! Przetwarzanie wielowątkowe to jest to czego nam trzeba! Nie zapominajmy o sprawdzonym już w działaniu Trace cache Intela, w którym przechowywana są rozkodowane instrukcje w liczbie 12.000. Mój procesor też musi mieć takie coś, tylko lepsze. Wszystko musi mieć większe i lepsze (cokolwiek by to znaczyło), to się nazywa postęp. Liczy się moc obliczeniowa, a nie wielkość rdzeni.

Kto się trochę zna na działaniu pamięci wirtualnej zapewne kręci teraz nieco nosem. Dzisiejsze konstrukcje nie mają szans na przetwarzanie kilku wątków bez zastosowania pełnych kilku konstrukcji tradycyjnego CPU. Ale my mamy poganiaczy. Do 32-bitowego adresu dodajemy 8-bitowy offset i… możemy obsłużyć 256 wątków jednocześnie. Offsety dodaje główny układ zarządzający, pomniejsi zarządzacze pracują na 40-bitowych adresach, ale jednostki wykonawcze dostają do przetworzenia 32-bitowe. Po prostu układy zarządzające działają na 40-bitowych adresach, a jednostki wykonawcze tego nie widzą, bo offsety są „chowane” w specjalnych buforach. Gdy jednostki wykonawcze skończą obliczenia, offset jest dodawany do wyniku operacji i wyniki mogą wrócić do głównego układu zarządzającego, który zdejmie offset. Windows, Linux i spółka nawet nie zauważą co się stało. Oczywiście bez jakiejś łatki się nie obejdzie. Łatka musi sprawić, aby OS-y nie ograniczały się do wydawania jednego procesu/wątku na jeden procesor, tylko, żeby bombardowały go nieustannie nowymi wątkami. Dzisiejsze procesory szybko by wymiękły. Ten nawet nie poczuje. W końcu założeniem jest ciągła praca na pełnym obciążeniu.

URAN dobrze mówi, cache jest o wiele szybszy niż RAM. Dajmy przykład:

  • DDR-II 800 MHz = dual DDR 400 = 6400 MB/s

Teoretycznie oczywiście, bo mamy tu do czynienia ze znacznym spadkiem wydajności związanym z ogromnymi opóYnieniami. Co nam z takiego przepływu danych, skoro procesor musi je dostać do swoich buforów (najpierw do L2, potem kopiuje odpowiedni fragment do L1), a to trwa długo, zdecydowanie za długo! Cache L1 zawsze działa z pełną częstotliwością procesora, L2 jest czasami wolniejszy, ale mój hipotetyczny CPU nie ma tego ograniczenia. Co prawda w L2 wciąż pozostaje kopia L1, nawet po skasowaniu jej zawartości, ale nie zawsze możemy liczyć na to, że najbardziej obciążająca aplikacja zachowa swoje „wpisy” w L2, zanim znów nadejdzie jej kolei na przetwarzanie przez procesor. Większy cache L2 częściowo rozwiąże ten problem, więcej informacji może w niej pozostać.

Skoro mamy duży L1, to musimy mieć wielki L2, a nawet warto pomyśleć o L3. Cache L2… dajmy na to 12 MB i L3 4 MB. Znowu coś dziwnie napisałem? L3 mniejsze od L2, toż to herezja. Tak, ale nie do końca… wystarczy zmienić podejście do tworzenia CPU. Nie ma mowy, aby 2 MB L1 były każdorazowo kopiowane do L2. Miejsca zabraknie bardzo szybko. Dlatego, po pierwsze, układ zarządzający musi dokładnie wyliczyć ile adresów, instrukcji i ile stron może tam umieścić, a z których ma zrezygnować i wczytywać je z wolniejszego RAM-u. Aplikacje, które „zgarniają” większość mocy obliczeniowej zostaną potraktowane inaczej niż, dajmy na to, pasjans. Właściwie, po co ograniczać cache L3 do tylko jednej aplikacji? Jeżeli ogólny wzrost wydajności przyniesie rozdzielenie L3 na 2, 3, a może nawet więcej części. Układ zarządzający zamiast pozostawiać kopię L1 w L2, robi kopię w L3. Kiedy nadejdzie kolej „gry” pochłaniającej niemal całą moc procesora, układ skopiuje jej dane z L3 do L1, zanim system się o nie upomni. To co nie zmieści się w L3 może zostać w L2. Wydaje się przekombinowane? Otóż wcale nie, L3 ma zagwarantować, aby jednostki wykonawcze zawsze miały pod ręką dużą część informacji potrzebnych bardziej zasobożernym aplikacjom. Gdyby zostały one w L2 mogłyby zostać stamtąd usunięte. Z czasem w L2 zbierze się taka ilość informacji, że najważniejsze w danej chwili wątki mogłyby częściowo tracić swoje dane i instrukcje, L3 zapobiega temu zjawisku. Wzrost wydajności będzie zauważalny, bardzo zauważalny…

Te wszystkie wyliczenia musi wykonać jednostka zarządzająca. Jej moc musi więc być ogromna, musi ona nieustannie sprawdzać, czy nie pojawi się jakiś nowy wątek i zmieniać procentowe rozłożenie wszystkich poziomów cache. Zadanie karkołomne, ale coś w stylu Cell bez problemu da radę. Wielki zarządca powinien mieć odpowiednio szybki dostęp do pamięci, a zatem zapomnijmy na chwilę o dual RAM, aby pomarzyć o octal Ram (8*DDR). I niech to będzie DDR500 (32 GB/s!), albo wyżej, a nie DDR-II, które ma wciąż za długie opóYnienia. W ten sposób procesor dostanie prawdziwy potok danych na przemiał, a timingi pozostaną na, nazwijmy to, dopuszczalnym poziomie.

Pozostałe dwa układy zarządzające biorą na siebie rozkładanie zadań dla jednostek wykonawczych, oczywiście nie traktowanych jako zbiory np. 8*jednostka zmiennoprzecinkowa, ale w razie potrzeby każdą z osobna lub jako znane z GPU quady. Będą miały również sporo roboty z wyliczeniem, ile zadań muszą wykonywać poszczególne jednostki (różne zegary i konstrukcja potoków). W zależności od zadania więcej muszą wziąć na siebie potoki długie lub krótkie, a pozostałe będą przeliczać tyle, na ile pozwoli im architektura. Jak można się łatwo domyślić odpowiednie wątki będą przydzielane przede wszystkim jednostkom, które lepiej sobie z nimi poradzą.

Ci dwaj poganiacze są w stałym kontakcie z głównym poganiaczem. Wymieniają miedzy sobą GB-y informacji poprzez wewnętrzną min. 512-bitową, wielopasmową magistralę (coś w stylu HTT Athlona 64, ale o wiele lepsze) i wspólnie zarządzają rozbuchanymi megahercami. No właśnie iloma megahercami? Dajmy skromne 2000, a ta rakieta, dzięki ilości jednostek wykonawczych, a przede wszystkim zupełnie nowemu, o wiele sprawniejszemu zarządzaniu ich mocą, zmiecie z powierzchni ziemi wszelkie rekordy jakie ustanowią klastry złożone z ośmiu Opteronów. Poganiacze dostają wyższe zegary, chociażby po to, aby poradzić sobie z szybszymi zegarami niektórych potoków wykonawczych. Poza tym muszą między sobą współpracować tak szybko, aby nie ograniczać w najmniejszym stopniu wydajności jednostek wykonawczych. Nie obejdzie się zapewne bez mechanizmów przewidywania, ale to musi zostać wliczone w koszta.

Ile watów? Dużo, ale czy to ważne? Z pewnością nie tyle, żeby nie dało się tego schłodzić za jakieś rozsądne pieniądze (100 złotych?). Kiedy taki procesor trafi pod strzechy w wymiarze powiedzmy… 45 nm., taka złożoność układu scalonego nie będzie stanowić większego problemu. Z pewnością jego budowa jest o wiele prostsza niż 8 połączonych oddzielnych procesorów.

Taki procesor bez problemu wykorzysta moc drzemiącą w kartach o wiele szybszych niż Geforce 7800 GTX, a nawet zapowiadany na przyszły rok R600. Poza kontrolerem pamięci wbudowanym w „centralny układ zarządzający” niezbędny stanie się specjalny kontroler odpowiedzialny za przyspieszenie komunikacji na drodze CPU-GPU. Co ciekawe AMD ma już kontroler pamięci i zapowiedziało już kontroler CPU-PCI-Express. Czyżby firma miała szczwany plan? Czy K9 (K10 jak wolą niektórzy) może wyglądać jak na powyższym
schemacie? Nie jest to wykluczone, ale zdrowy rozsądek podpowiada, że chyba jeszcze za wcześnie o kilka lat na taki eksperyment.

Przypomnienie. Aplikacja = 1/kilka procesów. Proces = 1/kilka
wątków.

Żeby to wszystko zadziałało jak należy trzeba jeszcze znaleźć odpowiednie oprogramowanie. Problem polega na tym, że większość danych musi zostać najpierw przetworzona, aby można wykonać kolejne operacje. Próba rozdzielenia zadania na kilka części staje się bardzo trudna, kiedy mamy obliczyć działanie typu E=C+D, a jeszcze nie znamy C i D, bo C=2A-B a D=A+B. Co możemy z tym fantem zrobić? Wbrew pozorom możemy niemało. Taki procesor mógłby nawet bez optymalizacji oprogramowania przetworzyć o wiele więcej danych niż potrzebuje jedna aplikacja. Co w związku z tym trzeba zrobić? Przetwarzać wątki równocześnie, czyli coś w stylu HT, ale znacznie skuteczniejsze. Nie tylko dlatego, że mamy 12 zestawów jednostek wykonawczych. Po pierwsze, mamy tu zarządców, którzy puszczą w ruch dokładnie tyle jednostek wykonawczych, aby można było przetwarzać nawet tyle wątków ile jest jednostek wykonawczych, czyli 80 (8*8 + 4*4). W praktyce bierzemy wątki (jak się da, to nawet całe procesy), które w niewielkim stopniu obciążają procesor i przetwarzamy je na wszystkich jednostkach wykonawczych, jakie mamy pod ręką. Jeżeli jakaś jednostka nudzi się, zarządca albo każe jej wspomóc inne jednostki przetwarzające dany wątek, albo zacząć przetwarzać kolejny wątek. Zamiast czekać na wyniki C i D, żeby obliczyć E, jednostka wykonawcza zajmie się innym wątkiem, zadba o to zarządca. Z resztą wcale nie jest powiedziane, że ta sama jednostka musi przetwarzać ten sam wątek, jeżeli inna jest szybciej gotowa do skończenia obliczeń. Kiedy nie będzie trzeba czekać, wątek będzie przetwarzać przez tyle jednostek, ile tylko będzie potrzebne, aby działał z najwyższą szybkością. Po drugie, mamy cache L3 magazynujący to, co procesor potrzebuje do szybszego przetwarzania tych wątków/procesów/aplikacji, które wymagają naprawdę wielkiej mocy obliczeniowej.

Reasumując, jeżeli nie da się przetwarzać równocześnie kilku wątków w całym układzie (12 zbiorów jednostek), jednostki dostają do przetworzenia zupełnie inne wątki (jakoś trzeba wykorzystać bufory zarządców). W praktyce nie jesteśmy ograniczeni do przeliczania 12 wątków jednocześnie, co jest bardzo miłą perspektywą.

Najmilsze w tym schemacie jest to, że na jego podstawie można skonstruować procesor w architekturze x86 RISC, czyli w tej jaką wykorzystuje Athlon X2 i P4 D. Trzeba tylko chcieć, a systemy nawet nie zauważą, że dostały zupełnie nowy procesor. Co na to Bill G.? A kogo to obchodzi? Jego XP, Vista i 2003 Server, będą korzystać z procesora na dotychczasowych zasadach. Przypuszczam nawet, że Bill bardzo by się ucieszył. Cały czas próbuję zaznaczyć, że architektura takiego CPU jest bardzo elastyczna. Elastyczna do tego stopnia, że można ją łatwo programować! Bez problemu można wyznaczyć „na sztywno” ilość jednostek wykonawczych, jakie mają zostać przyporządkowane jakiemuś procesowi. W praktyce oznacza to, że cały zbiór jednostek może zostać przeznaczony tylko dla systemu. Nie ma wymogu, aby wątek czekał na swoją kolej. Skoro przetwarzamy wątki po 10-20 jednocześnie, nie ma kłopotu, aby kilka z nich było przetwarzanych cały czas. Czyli mamy kolejny wzrost mocy obliczeniowej. Dosyć prymitywne dzielenie zasobów za pomocą priorytetów odeszłoby w niepamięć. Bill mógłby zorganizować service packi i zmienić sposób zarządzania mocą procesora. Nie byłaby to bułka z masłem, ale zadanie całkowicie wykonalne. Nawet gdyby tego nie zrobił, procesor „sam” będzie dzielił swą moc według własnego uznania (algorytmów).

Użytkownicy również byliby bardzo szczęśliwi. Taki potwór i jeszcze na dodatek, można go konfigurować. Część programistów i entuzjastów ruszyłaby do wyścigu, kto zrobi najszybszy program. Dla maszyny opartej o taki procesor, warto chwilę posiedzieć nad zaszyciem wielowątkowości w oprogramowaniu. Leniwi programiści również byliby szczęśliwi, bo zawsze mogliby powiedzieć,
że nie trzeba nic robić, skoro procesor radzi sobie ze wszystkim sam. Główny zarządca na zewnątrz będzie widziany jako jeden procesor, a wewnętrznie za pomocą dwóch młodszych zarządców będzie miał do dyspozycji jednostki wykonawcze 8 procesorów. To właśnie jest prawdziwa wielordzeniowość, czyli trzy potwory i spółka.

Nieszczęśliwi będą tylko inżynierowie Intel i AMD, którym przyjdzie to wszystko wprowadzić w życie, bo „mam taką fantazję”. A kiedy już będziemy mieli takie cacka w naszych domach, możemy zacząć myśleć o większych projektach, ale już nie x86

Spis treści: Przyszłość procesorów wielordzeniowych

Słowa kluczowe: przyszłość procesorów

Click to rate this post!
[Total: 1 Average: 3]

Marcin Kluczek