Podwójne, a w przyszłości zwielokrotnione jądro, to rozwiązanie lansowane od pewnego czasu jako środek zwiększania wydajności procesorów - praktycznie jedyny wobec zahamowania przez fizykę możliwości przyspieszania zegarów i wyczerpania możliwości rozwoju mikroarchitektury układów. Wyczerpania? Conroe/Merom/Woodcrest udowadnia, że lansowany za czasów Pentium 4 pogląd o wyczerpaniu możliwości rozwoju był całkowicie błędny.
Podwójność pozorowana
Zostawmy na później mikroarchitekturę i na początek prześledźmy różne koncepcje realizacji podwójnego jądra w dotychczasowych procesorach Intela. Podstawą tych koncepcji jest architektura SMP - Symmetrical MultiProcessing - w której wszystkie procesory mają jednakowy dostęp do pozostałych zasobów komputera. Od tej koncepcji wyszedł Intel w swojej pierwszej konstrukcji dwurdzeniowej.
Podwójne jądro procesorów Smithfield to w rzeczywistości klasyczna konfiguracja SMP, złożona z dwóch niezależnych procesorów na jednym chipie - złośliwi mówią, że to po prostu dwa sąsiadujące ze sobą na waflu Prescotty, wycięte jako jeden kawałek.
SMP na jednym chipie sprawdziło się zadowalająco, ale... im większy jest chip, tym mniejszy procentowy uzysk sprawnych chipów z jednego wafla, więc w następnej konstrukcji "dwurdzeniowej", o kodowej nazwie Presler, Intel zrezygnował z pozorowania podwójnego jądra.
Presler to dwa całkiem osobne procesory Cedar Mill, umieszczone na wspólnej płytce podłoża. Zarówno w układzie Smithfield jak i w Preslerze dwa procesory, wchodzące w skład konstrukcji, połączone są ze sobą wspólna szyną FSB. Za jej pośrednictwem odbywa się rozwiązywanie podstawowego problemu architektur wieloprocesorowych, jakim jest uzgadnianie spójności cache. O co tu chodzi?
Problem spójności cache
Współczesne procesory wykonują operacje przede wszystkim na danych zawartych w systemie pamięci podręcznych cache. Co prawda w zestawach instrukcji SSE przewidziano możliwość operacji z pominięciem cache, jednak w praktyce są one bardzo rzadko stosowane. Wyobraźmy sobie sytuację, w której jeden z procesorów zmodyfikował dane, na których dalsze operacje ma wykonywać drugi - w jego pamięci cache dane te nie są zmodyfikowane! W układach przewidzianych do stosowania w konfiguracjach wieloprocesorowych stosuje się więc systemy zachowania spójności cache (cache coherency). W sytuacji takiej jak wyżej opisana odwołanie do zmodyfikowanych przez inny procesor danych wymaga przesłania ich z pamięci cache procesora - autora modyfikacji - do pamięci cache procesora podejmującego dalszą obróbkę. W większości procesorów przy uzgadnianiu spójności cache przesyłana jest zawartość całego wiersza - 64 bajty. Transmisja taka blokuje dostęp do szyny FSB, a procesor, który ma dalej obrabiać dane, traci całkiem sporo czasu oczekując na jej zakończenie. W procesorach Intela strata ta jest minimalizowana przez dużą szybkość szyny FSB, jednak mimo to jest znacząca - szesnaście cykli transmisyjnych szyny, potrzebne do przesłania 64 bajtów, to stracone kilkadziesiąt cykli zegara procesora. Jeśli do tego dodamy czas tracony na przesłanie informacji o modyfikacjach i czas potrzebny do nawiązania transmisji, widzimy wyraźnie słabe strony SMP. Praktycznie mierzony czas komunikacji cache L2-cache L2 w architekturach SMP Smithfield i Presler wynosi około 200 nanosekund. Problem spójności dotyczy nie tylko cache L2, ale także pamięci podręcznej pierwszego poziomu dla danych. Pamięć ta jest jednak w intelowskich architekturach niewielka, więc problem spójności występuje relatywnie rzadziej.
SMP również w K8
Architektura K8 od początku projektowana była z myślą o podwójnym rdzeniu. W praktyce jednak K8 z dwoma rdzeniami to dwa osobne procesory, wyposażone we wspólny zestaw interfejsów dostępny za pośrednictwem przełącznika krzyżowego. Ta swoista forma architektury SMP, bo trudno to inaczej określić, ma nad klasyczną SMP zasadniczą przewagę - dzięki komunikacji przez przełącznik krzyżowy transmisja danych przy uzgadnianiu spójności cache odbywa się z szybkością taktowania zegara procesora. Czas trwania tego procesu jest dzięki temu znacznie krótszy niż przy klasycznej architekturze SMP, jednak cała procedura też trochę trwa. Warto zauważyć, że architektura systemu pamięci cache w K8, nazwana exclusive cache, eliminuje problem spójności L1 - uzgodnienie danych obejmuje całość podsystemu, równocześnie L1 i L2. Mierzony praktycznie czas komunikacji L2-L2 w procesorze Athlon 64 to 110 nanosekund. Znacznie krócej, niż w przypadku Pentium D, jednak - podobnie jak przy połączeniu SMP na poziomie szyny FSB transmisja blokowała szynę, tak przy połączeniu na poziomie przełącznika krzyżowego transmisja zajmuje ten przełącznik, odcinając na pewien czas obydwa jądra od możliwości komunikacji z otoczeniem. Jedyną korzyścią jest krótszy czas oczekiwania przez procesor przejmujący dane - tym zresztą tłumaczy się fakt, że procesory Athlon 64 X2 zyskują na podwójnym jądrze więcej wydajności niż układy Pentium D. Ale problem spójności cache można rozwiązać w bardzo prosty sposób...
Spójność cache? Nie ma problemu!
W jaki sposób najprościej można wyeliminować problem spójności danych w cache L2? Rozwiązanie jest bajecznie proste - wystarczy, że pamięć ta będzie wspólna dla obydwu jąder. I po problemie! A przy okazji uzyskuje się wiele korzyści.
Najbardziej widoczną z nich jest to, że każde z jąder ma dostęp do całej przestrzeni cache, dzięki czemu uzyskuje się lepsze wykorzystanie pojemności. Rozwiązanie to sprawdziło się już pod nazwą Advanced Smart Cache w architekturze procesorów "Yonah", czyli Intel Core Duo. W Core 2 (aka Conroe), wyposażonym w cache L2 o pojemności 4 MB, możliwe jest wykorzystywanie przez jedno z jąder pamięci większej od 2 MB, jeśli nie jest ona używana przez drugie jądro.
Ale wspólną pamięć cache L2 wykorzystano również do mało rzucającego się w oczy, natomiast, jak się przekonamy przy dalszej analizie mikroarchitektury Conroe, bardzo istotnego usprawnienia. Szyna, przez którą jądro komunikuje się z cache L1 i L2, ma szerokość 256 bitów. Uzyskiwana dzięki temu przepływność rekompensuje niedogodność polegającą na niemożności równoczesnego dostępu obydwu jąder do cache L2. Jaka jest waga tej niemożności? Praktycznie - znikoma. Co prawda operacje pobrań i zapisów stanowią blisko jedną trzecią typowego kodu x86, jednak prawdopodobieństwo konfliktu jest niewielkie - właśnie dzięki "nadmiarowej" szerokości szyny. Nawet w trybie 64-bitowym jedno pobranie obejmuje cztery kolejne słowa danych, co sprawia, że odwołania do cache przy operacjach Load i Store stają się znacznie rzadsze - w trybie 32-bitowym jednorazowo pobierane jest aż 8 słów.
256-bitowa komunikacja jądra z pamięciami cache występuje również przy pobraniach instrukcji. Instrukcje kodu x86 mają zróżnicowaną długość - od 16 do 128 bitów. Można założyć, że w przypadku typowego kodu jednorazowo pobieranych jest od czterech do nawet dziesięciu kolejnych instrukcji. Jaki z tego pożytek?
Dwa razy dwa jest cztery
Kod binarny programu stanowi sekwencję kolejnych instrukcji. Instrukcje x86 są przez dekoder instrukcji przekształcane w tak zwane mikrooperacje, które możemy traktować jako instrukcje wewnętrznego procesora RISC, jakim jest w rzeczywistości potok wykonawczy wszystkich współczesnych procesorów x86. Jednak wcale nie zawsze instrukcje muszą być wykonywane ściśle w tej kolejności, w jakiej są zapisane. Zauważmy, że na przykład wykonanie operacji logicznej na danych zawartych w rejestrach procesora wcale nie przeszkadza w równoczesnym obliczaniu adresu następującego po tej operacji skoku (np. do początku pętli), czy też w wykonaniu instrukcji pobrania kolejnej danej. Dekoder instrukcji w Conroe wybiera więc z pobranego fragmentu kodu te instrukcje, których równoczesne wykonanie jest możliwe bez żadnych dodatkowych zabiegów i wprowadza obydwie równocześnie do tej samej fazy potoku wykonawczego, w której traktowane są jako jedna mikrooperacja. Intel nadał tej technice nazwę Macro Operation Fusion.
Ale makrofuzja to nie wszystko. Mikrooperacje, podobnie jak instrukcje x86, często również nie wymagają zachowania kolejności wykonywania. W Conroe zaimplementowano więc tryb pracy z niekolejnym wykonywaniem mikrooperacji - Out Of Order Execution, co umożliwiło realizację kolejnej fuzji. Micro Ops Fusion, jak nazwał tę technikę Intel, pozwala na łączenie w jednej fazie potoku dwóch mikrooperacji, z których każda może zawierać dwie instrukcje x86 (tylko nieliczne, rzadko używane instrukcje kodu x86 wymagają ciągu mikrooperacji, zdecydowana większość instrukcji wchodzących w skład typowego kodu jest przekodowywana na pojedyncze µops). Dwa razy dwa jest cztery i tyle właśnie instrukcji trafia równocześnie do kolejnych faz potoku wykonawczego.
Nic nowego, ale...
Łączenie w jedna fazę potoku instrukcji, które mogą być wykonane równolegle, nie jest niczym nowym. W procesorach x86 technikę taką zastosowano po raz pierwszy w procesorze NextGen, którego architektura stała się następnie podstawą do konstrukcji AMD K6. W tym procesorze, podobnie jak później w K7, możliwe było "upchnięcie" w jednej fazie potoku nawet trzech instrukcji x86. Trzy instrukcje są również pakowane przez kompilator w przeznaczoną do równoległego wykonania "paczkę" w przypadku kodu dla procesorów Itanium. Sama idea łączenia instrukcji jest jednak dużo, dużo starsza, liczy sobie przeszło 40 lat - po raz pierwszy zastosował taką technikę Seymour Cray, projektując w latach sześćdziesiątych ubiegłego stulecia superkomputer CDC6600.
Zostawmy jednak w spokoju historię. Jakie praktyczne znaczenie ma liczba równocześnie wykonywanych instrukcji, czyli współczynnik IPC (Instructions Per Cycle)? Ogromne - zauważmy, że
wydajność = IPC * częstotliwość zegara
co oznacza, że Conroe może być nawet o 1/3 wydajniejszy od pracującego z taka samą częstotliwością zegara AMD K8. Ponadto trzeba jeszcze wziąć pod uwagę istotną różnicę - o ile w przypadku K8 trudno liczyć na to, by w każdym cyklu udało się połączyć trzy instrukcje, to zastosowany w Conroe podział procesu fuzji pomiędzy makro- i mikrooperacje sprawia, że prawdopodobieństwo pełnego wykorzystania możliwości łączenia znacznie wzrasta. Praktycznie możemy oczekiwać dla Conroe wartości współczynnika IPC pomiędzy 3,5 a 4, podczas gdy dla K8 wynosi ona poniżej 2,5, więc przewaga wydajności zapowiada się imponująco.
Cztery naraz - kto to wykona?
Koncepcja intensywnego łączenia instrukcji i mikrooperacji postawiła przed konstruktorami Conroe dwa problemy. Pierwszym z nich było zapewnienie takiej liczby jednostek wykonawczych, by mikrooperacje przewidziane do wykonania nie musiały oczekiwać na wolną jednostkę. Najczęściej wykonywanymi operacjami są proste instrukcje arytmetyczno-logiczne, Conroe otrzymał więc aż trzy jednostki ALU. Z kolei operacje zmiennoprzecinkowe i SIMD z reguły nie zawierają wzajemnych relacji, co pozwala na ich równoczesne wykonywanie bez dodatkowych zabiegów - logiczne jest więc, że Conroe otrzymał trzy jednostki SIMD+FP. Połączenie jednostki zmiennoprzecinkowej z jednostką SIMD jest uzasadnione przede wszystkim tym, że większość instrukcji SIMD w zestawie SSE/SSE2/SSE3 operuje na danych zmiennoprzecinkowych, a w nowocześnie pisanych aplikacjach instrukcje zmiennoprzecinkowe x87 zastępowane są coraz częściej instrukcjami SSE, pozwalającymi na wykonanie tych samych działań znacznie szybciej (model x87 ma architekture stosową, dopasowaną do popularnej kiedyś "odwrotnej notacji polskiej", podczas gdy instrukcje SSE operują w sposób jawny na rejestrach, co pozwala na wykonanie operacji w jednym cyklu - ta sama operacja wykonywana w trybie x87 wymagałaby trzech cykli procesora).
Scheduler to układ, którego zadaniem jest wydawanie instrukcji do poszczególnych jednostek wykonawczych. Scheduler w Conroe jest oczywiście czterodrogowy - do równoczesnego wykonania mogą być kierowane cztery instrukcje dla jednostek wykonawczych. Przydział zadań dla wolnych jednostek wykonawczych jet sprawą stosunkowo prostą. W odróżnieniu od większości typowych rozwiązań (K8, NetBurst), w których scheduler był dzielony na dwie części - osobną dla operacji ALU i osobną dla operacji FP/MMX, scheduler Conroe jest zunifikowany w postaci Reservation Station, z możliwością wyboru pomiędzy 32 kolejnymi oczekującymi na wykonanie mikrooperacjami. Jak widać, spośród 32 operacji nietrudno wybrać te cztery. które można wykonać równolegle. Jest jeszcze inny problem - gdzie je wykonać?
Mało rejestrów? Udajmy, że jest dużo!
Model programowy ISA (Instruction Set Architecture) x86 zawiera niewielką liczbę rejestrów, a możliwości ich wykorzystywania są dodatkowo ograniczone przez przypisanie większości rejestrów konkretnych funkcji. No cóż - wtedy, kiedy powstawał model x86, wszystkie operacje wykonywane były na rejestrze-akumulatorze, nikt więc nie pomyślał o zestawie rejestrów ogólnego przeznaczenia, który mógłby być wykorzystywany przez "wbudowany RISC" zgodnie z zasadą tej architektury, ograniczającą zakres działania instrukcji do operacji Load-Execution-Store. W rezultacie przy próbach równoległego wykonania więcej niż jednej instrukcji napotykamy problem - kilka instrukcji może zamierzać przeprowadzić niezależne operacje na tym samym rejestrze docelowym. Aby uniknąć takiego problemu stosuje się operację zwaną przemianowywaniem rejestrów - rolę zajętego rejestru x86 przejmuje jeden z kilkudziesięciu rejestrów pomocniczych. W Conroe (Core 2) bufor przemianowywania i przeporządkowania (to ostatnie jest konieczne przy pracy w trybie Out Of Order Execution, czyli niekolejnego wykonywania instrukcji) liczy sobie aż 96 pozycji. Większy był jedynie w przypadku architektury NetBurst, w której liczył sobie aż 126 pozycji, natomiast najbliższy konkurent Conroe, czyli AMD K8, może się pochwalić zaledwie 72-pozycyjnym buforem. Wielkość bufora jest ważna - im większy, tym większe są możliwości wyboru instrukcji przydzielanych do wykonania, a tym samym wyższy praktyczny współczynnik IPC, który, jak już wiemy, stanowi podstawowy czynnik wydajności.
Niemożliwe? Nie ma takiego słowa!
Zestaw jednostek wykonawczych Conroe uzupełniają jednostki pobrań i zapisów - Load i Store. Dlaczego są to osobne jednostki, skoro obydwa typy operacji odbywają się za pośrednictwem tej samej szyny, więc teoretycznie nie mogą być wykonywane równocześnie? Przecież w trakcie pobrania z pamięci danych czy instrukcji nie da się do niej zapisać i procesor powinien czekać... Pomysłową technikę, eliminującą takie sytuacje, Intel ochrzcił mianem Memory Disambiguation. Nie będziemy próbować tego tłumaczyć na polski... a rzecz sprowadza się do tego, że również operacje na pamięci sa przekolejkowywane. Niby żadna nowość - już w P6 i Pentium M mieliśmy do czynienia z przekolejkowywaniem operacji Load. A jednak nowość i to poważna - w Core 2 przekolejkowywane mogą być również operacje Store. A to daje, z wyjątkiem niektórych szczególnych przypadków, bardzo dużą elastyczność dostępu do pamięci i optymalne wykorzystanie szyny FSB - nic nie przeszkadza w tym, by operacje pobrania i zapisu wykonywane były "równocześnie" z punktu widzenia jądra procesora - ich fizyczne wykonanie zostanie przez procesor tak zoptymalizowane, by nie przeszkadzały sobie wzajemnie. W tym punkcie architektura Conroe ma zdecydowaną przewagę nad K8, pomimo znacznie sprawniejszego dostępu do pamięci RAM w tym ostatnim.
Dostęp do pamięci to nie tylko możliwość sprawnego zapisu i odczytu. To także kwestia czasu - przypomnijmy, że cykl zegara pamięci to kilka cykli zegara procesora... Na każde z pobrań procesor musiałby oczekiwać? Nie!
Pobrania na zapas
Systemy pobrań wyprzedzających, pozwalające na umieszczenie w pamięci cache danych, które będą potrzebne dopiero za chwilę, zaimplementowane są we wszystkich współczesnych procesorach. Podobnie jest z systemami predykcji (przewidywania) rozgałęzień kodu. Jednak skuteczność tych systemów jest bardzo zróżnicowana. Spośród wcześniejszych konstrukcji niedoścignionym ideałem był system predykcji stosowany przez AMD w procesorach K6. Niestety, w K7 i K8 zastosowano znacznie prostszy i mniej skuteczny system predykcji. Tymczasem Intel został zmuszony, na skutek długiego potoku wykonawczego architektury NetBurst, do opracowania dla tej architektury maksymalnie skutecznego systemu predykcji i pobrań wyprzedzających. Mogłoby się wydawać, że lepiej niż w Pentium 4 już się tego zrobić nie da i Conroe otrzyma ten sam system predykcji. Tymczasem w Conroe znajdujemy system pobrań wyprzedzających, który "stawia na baczność" każdego orientującego się w architekturze procesorów. Każde z jąder dysponuje trzema układami pobrań wyprzedzających, obsługującymi cache L1 - dwoma dla danych i jednym dla instrukcji. Pamięć cache L2 ma własny, dwudrogowy system pobrań. Szanse na to, by potrzebne dane nie znalazły się na czas w pamięci cache, zmuszając procesor do oczekiwania, są praktycznie zerowe.
Po co szybsza szyna?
Szyna FSB w Conroe taktowana jest częstotliwością 1066 MHz, która w Pentium 4 zarezerwowana była dla układów Extreme Edition. Przewidywane jest także jej przyspieszenie aż do 1,33 GHz. Po co, skoro architektura Conroe nie jest tak bardzo zależna od szybkości szyny, jak miało to miejsce w architekturze NetBurst? Rozwiązanie daje do myślenia tym bardziej, że im szybciej jest taktowana szyna, tym lepszej jakości musi być płyta główna. Wyjaśnienie znajdujemy w dalszych planach Intela. Na rok 2007 zaplanowano konstrukcję o nazwie Kentsfield - umieszczone na wspólnym podłożu dwa układy Conroe, połączone ze sobą w SMP. Oczywiście połączone na poziomie szyny FSB. Powrót SMP to oczywiście powrót do problemu spójności cache i jego obsługi na poziomie szyny FSB, a im szybsza szyna, tym mniejsza będzie strata czasu przy uzgadnianiu danych. Szyna procesorów Kentsfield będzie więc taktowana częstotliwością 1,33 GHz. Możemy co najwyżej współczuć producentom płyt głównych...
O ile lepszy?
Przyglądając się architekturze Conroe widzimy wyraźnie, że procesor ten powinien mieć znaczną przewagę wydajności zarówno nad układami NetBurst, jak i nad swoim najgroźniejszym rywalem, czyli AMD K8. Jak wielka będzie ta różnica? Athlon 64 ma przewagę tylko w jednym punkcie - pod względem sprawności dostępu do pamięci RAM, obsługiwanego przez wbudowany kontroler. Ale wielka, czteromegabajtowa pamięć cache Conroe, współpracująca z systemem pobrań wyprzedzających, całkowicie niweluje tę przewagę, tym bardziej że system cache w Conroe jest prawie dwukrotnie szybszy niż w K8 - czasy dostępu do danych w cache są krótsze, a szyna komunikacyjna dwukrotnie szersza. Na poziomie cache Conroe zyskuje więc sporą przewagę, która praktycznie ujawni się przy wykonywaniu zadań, których kod i dane mieszczą się w systemie cache - straty czasu na skoki i rozgałęzienia okażą się krótsze niż w K8. Ale podsystem cache przynosi Conroe mimo wszystko dość drobne zyski. Najistotniejszym dla finalnej wydajności elementem zawartym w Conroe jest system makro- i mikrofuzji. Jak już wcześniej wyjaśniliśmy, w Conroe możemy oczekiwać współczynnika IPC na poziomie 3,5, podczas gdy Athlon 64 może się poszczycić wartością IPC mniejszą niż 2,5. I co najmniej tak właśnie ułoży się praktyczna różnica wydajności - w zadaniach arytmetyczno-logicznych przewaga Conroe nad K8 przy pracy z tą samą częstotliwością zegara wyniesie co najmniej 40%. Nie koniec na tym - dzięki trzem jednostkom SSE, pracującym w jednym cyklu, Conroe zyskuje nad K8 co najmniej 30% przewagi w tym typie operacji. Zauważmy, że instrukcje SSE są najczęściej wykorzystywane przede wszystkim w grach - K8 straci więc ewidentnie pozycję procesora dla graczy. Na jak długo? AMD przygotowuje obecnie ripostę w postaci układu K8L. Jak skuteczna będzie? Niedługo i o tym napiszemy.
Autor od wielu lat publikuje swoje artykuły na łamach magazynu | www.enter.pl |