Instrukcje łatające rzeczywistość
Aby wyprodukować mikroelektronikę możliwie tanio trzeba to robić masowo. Masowo w tym wypadku oznacza użycie jak największego wafla do naświetlania. Im większy wafel tym większe różnice kątowe (wiem, że z punktu widzenia człowieka minimalne, ale walczymy tu z gąbką, gdzie atomy można policzyć co było w poprzednim tekście). Dlatego im większy wafel (średnica) tym słabszy yield. Dlatego wiele procesów zostawia się na etapie “działa – nie psuj” bo yield na poziomie 40% w przypadku niektórych (dawniej złożonych produktów) przy rozsypującej się technice co prawda na komerchę się nie nadaje, ale Pan Pancerny takiego klocka ciągle eksploatuje i ma być.
//Część trzyliterowych terminów i działanie samych modułów jest w innym tekście, tylko jeszcze go nie ma na głównej; Więc jak się jakieś PMU trafi to na razie przyjmujcie że jest i działa, chyba że wiecie co to i jak działa;
Najfajniej byłoby robić tylko chip w środku wafla – wtedy jest on najlepszy jak się da, ten klocek z reguły trafia na odrębną półkę i ma maksymalne parametry nominalne. Numeruje się go jako zerówkę i trafia do specyficznego klienta w pierwszej kolejności, a później do klienta który nie pilnuje portfela. Ten specyficzny klient to najczęściej badania własne i aeroszpej. W nowoczesnych procesach aeroszpej już tak nie wymaga, ponieważ dla nich są robione stare serie o szerokich ścieżkach długoterminowo odporne na powstające w ich specyficznych warunkach problemy z jonizacją.
Statystyka wskazuje, że im dalej od zerówki tym większe problemy z kątem naświetlania i rozprowadzaniem ciepła. Z tego wynikają defekty krystaliczne i inkluzje. Na środku yield jest powyżej 90%, ku krawędzi może spaść poniżej 70%, więc średnio na jeża (ze względu na geometrię większość produktu jest bliżej krawędzi niż centrum) jeśli proces daje 75% (edge die yield loss) to jest o czym rozmawiać. Jak się go dopieści to dojdzie do 85-90% i wtedy kombinuje się z większym waflem (spadek kosztów od połowy do ćwiartki).
Po wycięciu z wafla (obecnie warstwy testuje się też w trakcie między warstwami bez cięcia) każdy element idzie na testy przewodzenia po ścieżkach. To zautomatyzowany proces mierzący oporności, maksymalne napięcia, wydolność dla wybranych częstotliwości i wynikające z tego rozprowadzanie ciepła. Pierwsze co się może zje… to wywalone flipflopy i trzeba je sprzętowo wyłączać przez fusebit (laserem się je grzeje i wyłącza, to takie zworki, niektóre można zamknąć, otworzyć wyłączając pewne funkcje klocka bez zaburzania jego zdolności do pracy, po prostu nie uruchomi wszystkich modułów lub na pełnej petardzie). Na potrzeby tej operacji w płytce są ścieżki, które tylko do tego służą – do włączania/wyłączania części układu. Przyczyn projektowych jest multum. Czasem klientom tego nie potrzeba, czasem są to placeholdery pod kolejne wersje rozwojowe, kiedy problemy zostaną rozwiązane. A czasem robi się to metodycznie, ponieważ klient zamawia pod konkretną funkcjonalność, pasują mu zewnętrzne klocki, które byłyby i tak słabe, a klient potrzebuje ich i tak w ograniczonej funkcjonalności, więc tam można wyłączać w ciemno – i tak w najlepszym razie ca 20% miałoby pełną funkcjonalność. Oczywiście się je sortuje i dobiera z różnych wafli te odpowiednio zje… to zautomatyzowany proces. Z nowych klocków dobrym przykładem są Ryzen5, które są po prostu Ryzen9 z wyłączonymi rdzeniami. To jest dokładnie ten sam klocek. Kiedy w GPU wali się streaming to RTX3060 jest 3080 z wyłączonymi SM (odpowiednik rdzenia). Na klocku są też zapasowe klony tego samego układu i dokładnie tym samym laserkiem, jeśli klon się udał, a oryginał nie to można fusnąć rerouting.
Odnośnie rdzeni – jeśli coś pójdzie nie tak już u użyszkodnika (na przykład overclocking zaszkodził, ale nie zabił) to bios/uefi (hypervisor dla chmurek) sam sobie poprzełącza flipflopy załączające rdzenie. Gdybyście wybili dziurę w bezpieczeństwie (będzie w następnym tekście, który jest starszy od poprzedniego i ma już hopsztylion stron) to możecie się do tego dobrać, ale nie polecam – read żeby zobaczyć jest ok, jak chcecie tam write to sami się prosicie. Jeśli zaś macie coś bardziej skomplikowanego (zastosowania serwerowe) to wpięte tam są jeszcze kontrolery (normalne FPGA), które w locie zrobią dynamiczną rekonfigurację nieszczególnie zaburzając pracę, ale dostęp do nich występuje z ich zewnętrznej konsoli (ona może być podpięta do serwera, ale to jest fizyczny hipervisor więc podpięcie go do serwera jest decyzją typa, który to skonfigurował).
Więc z jednego wafla produkuje się czipy o różnej konfiguracji, tak żeby zamiast obniżać yield obniżać specyfikację. W praktyce, gdybyście chcieli uzyskać tylko czipy najwyższej jakości yield optymistycznie dojdzie 40% na małym waflu. Ten problem istniał kiedy byłem mały i tłumaczyli mi starsi, ale dość szybko go rozwiązali (ówcześnie to był problem na litografii RAM/ROM) po prostu wyłączając sektory i sprzedając czipy o różnych pojemnościach (tak, że użytkownik nie widział, że pamięci jest tam tyle samo wszędzie, tylko część nie wyszła i ją wyłączyli). Robiło się to malutkimi zgrzewarkami bo szerokość ścieżek wtedy pozwalał, dziś jest to laser. Wyłączania modułów logicznych jeszcze wtedy nie było, nie było jeszcze masek z duplikatami ponieważ ścieżki były dość szerokie i klocek ledwo się mieścił.
Zapewne dla czytelników może być interesujące to, że dla aeroszpeja wytwarza się klocki prawie identyczne, tylko inaczej sfusowane. Na przykład klocek ma oficjalnie takie parametry jak najsłabszy w serii (powiedzmy macie 6 rdzeni w maksie, albo 12, albo ile tam chcecie). I ich klocek ze środka wafla wychodzi idealnie. Ale… zamiast sześciu rdzeni dostają dwa. Ponieważ na wejściu/wyjściu klocka ścieżka jest prowadzona przez TMR (macie go w klocku, tylko jest nieaktywny – nie wpięto go bo to trzeba w produkcji, ale na masce jest, czasem zostaje tylko po nim miejsce bo się go przesłania i w ogóle nie świeci). Ten trypel (taka zaraza Triple Modular Redundancy) ma podpięcie do PMU, ale w tych klockach jest tylko tryb płaski (żadnych manipulacji na taktowaniu – ma działać ujowo, ale stabilnie) i zabiera prąd aby puścić przez trzy rdzenie ten sam sygnał, a na wyjściu jest wyborca (voter^^), który na bazie majority vote logic stwierdza jaki wynik jest dobry. I dodaje flagę, jeśli ma trzy różne co jest dalej w procesie potrzebne, bo inne klocki (zazwyczaj parzysta ilość) liczą dokładnie to samo. Jeśli ctr liczący ile razy zeszła “flaga” (dwubitowa liczba kontrolna który rdzeń się nie zgadza), że istniało zdanie odrębne to jeśli ciągle robi to ten sam rdzeń (jest na to sito statystyczne z funkcją) można wnioskować, że coś mu zaszkodziło, wdrażane są testy, jeśli to ląduje to moduł się wymienia i bada, żeby sprawdzić dlaczego (zazwyczaj jonizacja). Jeśli są trzy zdania różne (i taki cntr zejdzie kilka razy) to cały moduł jest wykluczany procesu (on sobie dalej liczy, tylko nikt go nie słucha) i za jakiś czas ma włączany reset i sprawdzenie czy mu pomogło. Ten “jakiś czas” związany jest z tym, żeby zmagazynować schodzące dane, bo takie cuda najczęściej mają miejsce, gdy stało się coś na tyle istotnego, że moduł zostanie ujawniony przez ekipę poszukującą szczątków maszyny.
Przy czym w modułach kontroli ognia triple fail w trakcie oddania strzału nie jest niczym nieoczekiwanym. Dlatego tych urządzeń jest więcej.
Podobna sytuacja jest na pamięci (młotkowanie) takich jak serwerowe (dawniej, teraz to już powszechne), gdzie dane rozprowadzane są i sprawdzane na zgodność par bitów (parzystość żeby się jakaś nazwa przyjęła, ale ta sama nazwa jest też używana dla starszego, prostszego procesu parzystości obecnie używanego w cache). ECC jest sprzętowym rozwiązaniem problemu sprzętowego, ale jeśli macie dostęp do kontrolera to możecie go przeprogramować i uzyskać dwa razy więcej dość zawodnego RAM. Tyle że na danych częstotliwościach sami sobie jesteście winni skutków. Wczesnym, “sofwaerowym” rozwiązaniem tego problemu jest pozostałe w cache parity bits. Oraz sprawdzanie wyrywkowe (też raczej serwery bo trzeba raid konfigurować) – LDPC, choć w NAND też się stosuje. Wcześniej to była sztuczka podobna do trypla (lub dubla zależnie od konfiguracji macierzy dyskowej) i opierała się na pętli programowej sprawdzającej co który sterownik zwrócił z kilku pytanych o to samo. Później pętla poszła do sterownika, a później problem był tak duży, że dostał własny moduł harwaerowy dla działających synchronicznie pamięci/dysków.
BIOS/UEFI podnosząc klocka korzysta z wbudowanego w nią bestii^^ (BIST) która zwraca stan klocka i pozwala przełączać pewne moduły. A choć niektóre technologie niby pochodzą z aeroszpeja (trypel) to ze względu na budowanie coraz mniejszych układów (tak poniżej 10nm) problem nabrał skali i teraz trypel i ecc jest hardwaerowo wstawiany we wszystko. Więc klocek jest duży, ale tylko 1/3 jest potrzebna, reszta wyłącznie powiela tę robotę, żeby na wyjściu się dogadać (voter) co miało być wynikiem.
Kolejny problem wcześniej niewystępujący to przy bardzo małej różnicy potencjałów (na tak takie kabelki oczywiście bardzo duży prąd, no ale względem środowiska to delikatne smyranie – warstwy wyżej na grubszym chodzą) to zakres propagacji przy v < .5 mul c i cyklu zegara 200ps (pikosekund, nie playstation) milimetr “kabla” to ca 10ps nie uwzględniając RC. Dlatego klocek wielkości pokoju się nie uda (odnoszę się do komentarza pod poprzednim tekstem) chyba że zejdziemy z częstotliwością. Cal w tym kontekście to więcej niż nieskończoność. Otóż na milimetrze RC (opór & pojemność) wysyła nas z napełnieniem obwodu “elektronami” (oswobodzeniem ich na tyle, żeby puknęły sygnał do odczytania dalej) idzie w nanosekundę. Czyli już milimetr jest nieskończonością – sygnał nie dotrze nigdy. No ale sygnał zegara też jest rozprowadzany po klocku więc mamy clock skew i jitter co wrzuca nas na zabawę w macierze jak z punktu widzenia klocka wygląda czas na czipie z punktu widzenia każdego kawałka “przewodów”. A że kabelki pokręcone to zapewniam, że jest to wyjątkowo dziwaczna przestrzeń wymagająca czasem robienia fizycznych zygzaków po płytce (labiryntów) aby uzyskać jakieś sensowne synchro na małych odpowiednikach magistral.
Aby tę macierz uprościć (przez dystrybucję) używa się H-tree i grid clock distribution. Htree jak nazwa sama wskazuje to drzewko, tylko takie dla Matematyka więc do góry nogami aby symetrycznie źle (czyli sprawiedliwie wszystkim aby byli równo niezadowoleni) samo sposób generowania sygnału zegara ma wadę (przesunięcie fazowe, na oscyloskopie z taką rozdzielczością widać i czasem trzeba ludziom od pomiarówki tłumaczyć, że wzbudzenie na detektorze to z jego uruchomienia było i jest wyższe od sygnału bo kondensator musiał załapać, żeby się rozładować, a prąd nie jest z wydarzenia tylko z zasilania). Konstrukcja tego zegara (drzewka rozprowadzającego sygnał), aby łatwo było ją nałożyć w masce ma kształt fraktala powtarzanych H tak żeby każda nóżka miała dokładnie tę samą długość, co determinuje (do pewnego stopnia, ale dość rygorystycznie) gdzie na klocku można położyć układy. Jak się to dobrze zrobi to skew macierzy rozprowadzenia jest poniżej 10ps, ale potrzeby a ideał to są dwie różne sprawy, więc zazwyczaj idealnie nie jest. Ale jest dobrze i działa. Niby się dobrze skaluje i nie ma buforów, więc energetycznie jest sprawne, tanie i dobre, ale wymusza taki, a nie inny układ samego klocka, który jednak wejście ma (rejestr uops) i fajnie jakby tam sygnał był odpowiedni wcześniej, ale nie za wcześnie, bo na pewno nie później (całe 200ps jest wtedy skracane o ten delay). I niby wszystko jest pięknie, ale tak to komplikuje layout klocka, że trzeba komisji aby się dogadać co gdzie ma leżeć. A kiedy M0 zacznie się grzać i indukować, i interferować i zacznie crosstalk dawać na zegar to okazuje się, że sygnał zegarowy zostaje zakłócony (zmienia się skew na macierzy sygnału i to zmienia się w sposób trudny/nie do ogarnięcia). Więc trzeba w locie regulować częstotliwość i wpływać na zegar, żeby skutkami własnego pośpiechu nie powodował sobie problemów. Htree jest powodem takiego, a nie innego układu rdzeni w klocku i jeśli macie heterogeniczny blok do poważnych obliczeń (dużo FPU splecionych z dużą liczbą ALU, ale jeden rdzeń) to się zabawa nie uda. Dlatego rdzenie są tak bardzo odchudzone w kwestii FPU i ALU. FPU to jest generalnie sam z siebie rozmiaru klocka bo to początkowo był oddzielny klocek SIMD i wycięto z niego prawie wszystko co się dało (do tego stopnia, że pewne funkcje występują tylko jednostkowo i mimo, że macie dużo FPU to się żadna serializacja nie odpali w rdzeniu, bo akurat ta funkcja ma tylko jedną kopię harwearową).
Obecnie niby FPU zajmuje <20% powierzchni rdzenia, ale… jeśli wywołacie instrukcję legacy x87 na stosie z precyzją 80bitową to zazwyczaj wszystkie FPU rdzenia są podpięte do jednego modułu wykonującego tę antyczną instrukcję, ponieważ kodoklepcy od takich instrukcji odeszli i się na klocku zredukowało liczbę modułów ją wykonujących. Tak, to kodoklepcy ze swoimi zwyczajami decydują o tym w jaką stronę rosną klocki. W drugą stronę to nie działa – jak potrzebują jakiegoś obliczenia i je uparcie emulują na klocku zapychając potok to dość szybko jest to serializowane w klockach, bo najwidoczniej potrzebne. A jak nie używają to się wycina. Więc sama iloś modułów wykonawczych dla modułów wykonawczych jest dostosowywana ewolucyjnie. Pod klienta.
Już w Nehalemie (core2duo, więc antyk) x87 był współdzielony w Hyper-Threading. Więc czy to było takie hyper to ten… było, ale nie do zmiennego przecinka. Bo się po prostu w klocku nie mieściło. Ówczesne x87 FPU były jeszcze w wersji czystej bez mydła, rozmiaru samego klocka x86 obok, więc zanim metodą błędów dobrodoszli co tam w zasadzie się mało przyda i czy aż tyle tego trzeba to kombinowano jak to wszystko razem upchnąć. Ten x87 to jest etap włączania kompa, kiedy z real16 przechodzicie w protected32, obecnie to zajmuje prawie nic, ale oznacza dołączenie czegoś co wcześniej było kooprocem. Teraz to jest niezauważalny etap podpinania reszty kloca przy wstawaniu. Ale jest on niezauważalny ponieważ klocki są szybkie. No i podpiąć tal czy siak trzeba. Ale nie w trybie 32 tylko od razu na pełnej w 64 (tak naprawdę są dwa kroki, najpierw wchodzi 32 i pętla testowa BIST, ale wiadomo, że musi być 64, więc to jest potrzebne tylko do poszerzenia adresowania rejestru; żeby na obecnych Osach odpalić jakieś 32bitowe legacy z instrukcjami kompilatora na 32 to trzeba chcieć – samo nie pójdzie; zazwyczaj wcale nie pójdzie ponieważ z dekoderem trzeba dogadać się przez programowy dekoder instrukcji, więc lepiej to sobie skompilować Żygiem od nowa).
Ale Was pewnie interesują klocki nowe… no więc funkcje transcendentalne (czyli sinusi, kosinusi, tangensi) raczej mają tylko jeden blok i te okrojone FPU rdzenia mimo, że ich kilka to się muszą jednym Matematykiem podzielić i w kolejce czekać. Więc jeśli piszecie rotacje na macierzach to po pierwsze stosujecie obroty infinitesymalne, a po drugie zapomnijcie o serializacji. Jeśli zrobicie po swojemu (full math) to zamulicie kloca na dłużej – lepiej podzielić na kilka rdzeni niż serializować na jednym. No ale jak się bawicie w tensory to zapewne na cpu testujecie czy nie zrobiliście jakiejś grubej głupości, a później przekładacie kod na CUDA i zapominacie o problemach z CePemU. Bo on służy do liczenia, ale bez przesady.
Więcej – w nowych klockach na każde 2-3 FPU w rdzeniu (zależy jak tam akurat pasowało) jest tylko jeden moduł do pierwiastkowania. Oczywiście żaden zdrowy na umyśle kodoklepca nie pierwiastkuje jak nie musi, no ale jak już musi to aptekarsko. Nie dość że operacja w cyklach długa, to jeszcze na tyle odstręczająca w procesie, że kompilator się wysili jak ją przetłumaczyć na “co zrobić aby tego nie musieć robi”, a jak mu tak namieszacie aby nie mógł to się rdzeń będzie na tym mulił, więc tak jak przy trygonometrii – może na różne rdzenie to posłać? I tutaj nawet CUDA nie pomaga – tam też z pierwiastkowaniem jest ból d. Oczywiście moduł jest, ale prosimy o nienadużywanie bo to zajmie. A ponieważ moduł pierwiastkowania jest związany z modułem dzielenie to… polecam mnożyć ułamkiem, a nie dzielić. Kompilator w większości wypadków zrobi to za Was, ale lepiej się pilnować. No chyba, że macie skryptowy interpretowany w locie bez prekompilacji – wtedy nie ma zlituj, Pan chciał głupio to proszę – jest. Więc modułów dzielenia też jest dwa razy mniej niż rdzeni (a pierwiastkowania trzy razy), dobrym przykładem jest Zen2 i 3, a później uznano, że to wcale nie jest głupi pomysł.
A w Skylake operacje wektorowe (dzielenie 512 bit) są ekskluzywami, i jak to trafia ze stosu przez dekoder to się FPU niczym innym nie zajmą. To się robi raz, to jest bardzo ciężka operacja.
Generalnie – jeśli macie polecenie z trybu x87 32bit to zapewne klocek ma to na rdzeniu raz i tylko z grzeczności to zostawili. Najchętniej by wywalili, bo z dużym prawdopodobieństwem ten moduł przez całe życie klocka nie dostanie prądu ani razu. No ale kompatybilność wsteczna.
Jeśli jednak na gyper thread/SMT na rdzeń o dwóch wątkach logicznych (od i7 w górę raczej) wrzucicie takie dziwactwa to uops scheduler zrobi takie kolejkowanie operacji, że będzie działał przemiennie jeden wątek logiczny (zdławi drugi) albo na bezczela (trygonometria) w ogóle przełączy rdzeń na jeden wątek logiczny żeby kolizji nie było.
Więc klocki mamy szybkie, ale kodoklepców tak wybitnych, że potrafią głupimi linijkami kodu wyłączyć całe funkcjonalności cpu sprowadzając go do swojego poziomu i wqrwiając użyszkodników “czemu się to tak muli? gdzie optymalizacja?!”. Wystarczy jedna linijka takich głupot (mat4x4, trygonometria, podzielić liczbą pierwszą taką na naście cyferek, spierwiastkować siedemnastym stopniem) i rdzeń staje dęba na 100-200 cykli, dekoder dostaje cache missy hurtem, drzewo się sypie, semafory czekają i dobrze zorganizowany bałagan wywala nas na 500cykli zwrotnych pytań do RAM o co właściwie chodziło, a po cachu szaleje flush. A jak zrobicie to na GPU na początku potoku pytając o wnioski z końca innego potoku to pocztówki z wojny będą na wyświetlaczu.
Sugestia – używać poleceń nowoczesnych, sexy, z SIMD – do tego modułów jest tyle co napisali, że FPU i ALU w rdzeniu.
Oczywiście precyzja, prostota i dający się strawić limes layaoutu powoduje, że jest to rozwiązanie najczęstsze. Z tych które macie pod ręką.
Ale można wybrać się na Manhatan. Grid Clock rozprowadza sygnał inaczej. W każdym węźle jest inny zegar i flipflop pobiera sobie z niego kiedy ma cykl. Odwrotnie – zegarek mu mówi, że teraz ma i tyle. Każdy z tych zegarów buforowych ma w imieniu zegara centralnego utrzymać porządek na kwadracie. Więc można się wpiąć w zegar w dowolnym fragmencie czipa (można zaprojektować layout w zasadzie dowolnie, no prawie). I kiedy robi się duży układ, a jeszcze nie wiadomo jaki będzie (w NPU jeszcze nie wiadomo co będzie, więc od razu to wdrożono, bo klienci będą wymyślać) albo trzeba robić integrację SoC na jednym klocu (cpu, gpu, fiu bździu mobilka). Oczywiście jest to niesprawne energetycznie (i mobilka^^) i ma spory skew, gwarantowany. Oraz nie da się robić tego poniżej 5nm bo siatka daje taki crosstalk (tym razem w drugą stronę), że cały misternie utkany plan w siwy dym. No ale na mobilkach nikt się nie spina na gigahece, ale kabelki by jednak chciał gęsto upakować. Wstawia się to na “grubych” warstwach (duże M) z mocnym prądem (bo PMU) i dodaje dodatkową logikę (gating) aby odłączać nieużywane w danym cyklu obszary) więc sam dekoder i sterowanie PMU jest dość złożone dla takich klocków, a nadziej a w tym, że wiele funkcji arm potrafi chodzić na residual voltage z działania układu. Aby strefy czasowe synchronizować w takim klocku robi się bramki opóźniające (Delay-Locked Loop – coś jak wizyta w urzędzie) i można utrzymać skew w ryzach 10-50ps. Czyli wyżej od Htree, ale można sobie fantazjować z layoutem. W GPU raczej będzie siata, w kontrolerach przemysłowych wyłącznie Htree. A jak bardzo d boli to się łączy oba rozwiązania (grid to Htree jak w Meteorze czy Zen5) gdzie I/O jest obsługiwane na gridzie (tam się nie spieszy), a logika na drzewo. Choć istnieją też mutacje, gdzie grid jest łączony jeszcze diagonalnie (zbrodnia przeciwko Layoutowi) i rozwiązania sync (NPU). A ja ostatnio widziałem sterowanie cyklem zegarowym przy użyciu “latarki” – gdzie cykl zegarowy rozprowadzany jest laserem, tak żeby latency było dwa razy mniejsze niż w kablu. Ale wsadzenie do klocka świetlików, żeby w klocku tranzystorzy wiedzieli czy spać, czy już dzień i robić trzeba to akrobacja produkcyjna.
Do tego mamy hotspoty wynikłe z nadużywania ścieżek, więc mamy mocniejszy efekt naskórkowy i rosnące RC. Dlatego trzeba przełączać cyklicznie układy, aby miały cykl zegarowy na dystrybucję ciepła. I to też jest “softowo” rozwiązane w zarządzaniu PMU. A skoro mamy rosnące RC z powodu hotspotów na naskórku to coś się z tą “energią” dzieje (znaczy w bok idzie) i w efekcie mamy crostalk (szczególnie jeśli poprzesuwane są opóźnienia sygnału i uzyskujemy interferencje) i się zaczyna w układzie robić więcej szumu niż sygnału.
I dlatego nie robi się dowolnie rozległych rdzeni (tylko wszystkie elementy odwołują się do kilku ALU i FPU w rdzeniu, w kolejce się ustawiając na uops zorganizowanym przez dekoder ciągnący ze stacku) gdyż rdzeń musi przetworzyć wszystko (zakończyć operacje) w jednym cyklu (czyli 200ps dla 5gigahec) i najdłuższy critical path musi zostać w tym czasie domknięty. Choćby akumulatorem danych (flipflop). Więc jeśli klocek poradzi sobie z indukcyjnością to na 100ps przy 10mm (komunikacja wprost, brak tranzystora po drodze) to niby zadziała (zwykle, bo jak się nie udaje to macie w pętlach programowych try/catch i mimo, że debug wskazuje, że dane są i są absolutnie poprawne to catch się odpalił, że coś urwał poszło nie tak, a to po prostu listonosz nie zdążył i został na ulicy numer 7 i 3/4 – timing violation). W serwerach gdzie z definicji jest daleko (bo klocek duży) sygnał po drodze przechodzi do innej strefy czasowej przez flipflopa.
Kiedy się klockowi nazbiera takich timing violations to odpala się clock cycle limit (ctr tvs >> ccl) i dlatego długie ciągi (gpu mają niższe taktowanie, bo i tak się nie uda). Dlatego podział na rdzenie, a nawet kombinowanie z asynkiem zegarów z latency na zmianie stref czasowych takich jak infinity fabric w Zen).
Jak zauważacie jest dużo problemików, ale zazwyczaj wystarczy po prostu odpowiednio podzielić dane między jednostki obliczeniowe, nie pchać w jedną na gigahece tylko rozdzielić robotę. Bo większość roboty obecnie jest do zrealizowania równolegle. I wtedy dla rzadkich operacji można wywieźć robotę do oddzielnego “akceleratora” (w H100 i Gaudim są takie obejścia), wyprowadza się dedyki (SVE i AMX zależnie od architektury), czyli jedno FPU przewidziane w pełnej wersji dla rdzenia do obsługi glupich pomysłów, oraz zestawy tego w chipletach.
Procesor oczywiście sam z siebie nie “wie”, że na przeciążeniu głupoty robi, ale…
Klocek sobie zlicza timing violations, błędy danych, wysilenie z PMU i mają do tego liczydło zarządzające nastawieniem throtlingu (częstotliwość) oraz ustawienia PMU. Czyli w locie, przewidująco zmienia sobie (Static Timing Analysis robione już na etapie projektowania czipa, tu są poustawiane sztywne mikrokody z ROM) ustawienia ile trzeba się spinać do roboty, żeby z tej roboty był pożytek. Zapewne podejrzewacie, że funkcji nadzorczych korygujących i sprawdzających w procku jest dużo, i owszem – sam klocek tej roboty co nam potrzebna to ma 10%-30%, reszta to obsługa samego siebie. Im głupiej napisany program tym mniej z tego będzie. Celem tego throtlingu jest redukcja oczekiwanych (i już istniejących) sprzężeń pojemnościowo-indukcyjnych. Na wyjściu operacji z klocka jest dodatkowa “flaga”, która jest podniesiona i ma podpięte carry (flipflop tam jest). Jeśli sygnał na wyjściu z klocka jest w cyklu zegarowym to zostaje ona rozładowana i flaga opada – zegar ją podnosi. Jeśli podniesie nieopadniętą flagę to trafia sygnał do carry (>1) co inwokuje setup violation. Odwrotnie jeśli sygnał z klocka dotrze do niedponiesionej flagi (lub nie dotrze) i nie uda się stracić prądu na jej podniesienie (czyli została rozładowana interferencją) to inwokowane jest hold violation – znaczy rdzeń stanłą dęba.
Zaletą tych rozwiązań jest to, że klocek z wyprzedzeniem “wie” (funkcję ma) kiedy dla danych uops wyjdzie mu wzrost wzrost oporności, temperatury, napięcia (z PMU) i kiedy trzeba zdusić częstotliwość, a nawet wrzucić kilka NOPów “na stos” (znaczy zapchać sobie kolejkę z dekodera uopsami NOP – nic nie rób). Jeśli sytuacja jest podbramkowa (wysiadło chłodzenie? ocieplenie klimatu?).
W nawiązaniu do poprzedniego tekstu – w Europie nikt nie robi STA. To jest robione “gdzie indziej”. Ale że w kontrolerach i embedach, które się robi trzeba to się robi flipflopy cienia (shadow like), które robią podobny proces. Głowny flipflop pracuje na standardowym zegarze, a shadow na delayu setup time i wynik jest puszczany przez voter (równoległe XOR, bo przecież używa się kilku takich ścieżek) i skutek jest taki sam jak dla działania STA, ale prościej i trzeba to sensownie zaprojektować (dobrze dobrać oporności ścieżki).
Na pamięci ECC robi podobne rzeczy sprzętowo i pilnuje swojego ogródka. Z dużą zwłoką (w kontekście pikosekund) działa jeszcze throtle sprzętowy (czujnik temperatury jest wbudowany w każdy rdzeń), PMU w swoim cyklu bada przekroczenia limitów TDP i też mu wolno dać rozkaz throtle down. A dodatkowo OS (z bardzo dużym opóźnieniem) może zarządzać przez Vtune lub HWMonitor choć to są takie grzeczne prośby z wysokiego pierścienia pozwoleń (chyba że wybijecie dziurę przy wstawaniu systemu) do rozpatrzenia przez harware po spełnieniu warunków. Jest kilka wyjątków do których użyszkodnik raczej nie ma dostępu (crash, kernel panic), które “podnoszą brwi” hardwaru i duszą częstotliwość, ale zazwyczaj macie wtedy inne zmartwienia (w kolorze niebieskim) i walicie guzika, żeby zacząć od nowa. Takie rzeczy dzieją się wyłącznie w sytuacjach kiedy coś poszło bardzo nie tak. Przy czym nawet w Linuxie ondemand możecie częstotliwość obniżyć, podnieść… to jest taka prośba o charakterze sugestii, chyba, że wbijecie się w kloca na etapie startu i przekażecie uprawnienia do rejestrów (które omówiłem w kolejnym tekście^^). Gdzie omówiłem też mechanizm DVFS (Dynamic Voltage and Frequency Scaling) i stany P (częstotliwość/napięcie) i stany T (zadawanie NOPów). A programowo jeszcze macie na pokładzie EIST (lub AMDkowy odpowiednik), który obniża częstotliwość kiedy nic nei robicie (bo poszliście sprawdzić światło w lodówce – o keczu! o czekolada!). No a PMU (XTU) ma jeszcze grubego kija – CPU ma swoje kabelki z prądem, i ma wpisane ile mu wolno pobrać z zasilacza, jak przekroczy to dostanie sankcje na częstotliwość. Tęgą, hardwerową lagą.
Oczywiście ARM mając być oszczędny wyprzedzająco ustawia takie gry i zabawy w “ile prądu zeżremy” AVSem, więc tam 3/4 tych problemów w ogóle nie ma.
Ważna rzecz – jeśli w czasie testów na batchach produkcyjnych spora część klocków da hold violations z powodu crosstalku na równoległych ścieżkach to się obniża maksymalne częstotliwości i jeśli nie pomaga to jest poważny problem – trzeba przeprojektować klocek, ale dopiero po tym jak zmieni się model fizyczny ustawiający ramki co jest dopuszczalne. Bo to oznacza, że badania podstawowe wewnątrz firmy się nie udały. Albo ktoś podjął bardzo kosztowną decyzję, która jest gorsza niż zbrodnia – to błąd. Więc jakbyście się zastanawiali dlaczego branża jest tak konserwatywna, dlaczego tak dużo legacy i bezpieczników to postawcie się w sytuacji typa, który podjął decyzję, w wyniku której można się go zapytać gdzie jest 20miliardów baksów na uruchomianie linii produkcyjnej, z której zeszło coś co nie działa? Oczywiście on nie byłby winny samodzielnie, to trochę dłuższy proces, ale jeśli w Intelu, Nvidia czy AMD macie layoffy po pionach technicznych to nie jest tak, że ktoś nie wqrwił księgowego.
Polecam zastanowić się, ilu z tych procesów na kontynencie nikt nie robił w praktyce (ponieważ nie produkuje się klocków) i ile zajmie czasu odtworzenie tej zdolności. Tak gdyby klocki przestały dojeżdżać.
