Korzystanie z wielu rdzeni wymaga jawnego ujawnienia równoległości poziomu wątków w systemie operacyjnym, co zwykle wymaga od programisty napisania programu wielowątkowego. (Lub aby uruchomić program jednowątkowy wiele razy na różnych wejściach, takich jak kompilacja make -j4
)
Kompilatory dla niektórych języków obsługują jednak automatyczną równoległość. Na przykład C lub C ++ z OpenMP może skompilować zwykłą for()
pętlę do programu, który uruchamia wiele wątków.
#pragma omp parallel for
for(int i = 0; i < 1000000; ++i)
{
A[i] = B[i] * constant + C[i];
}
Ale i tak musi się to zdarzyć, gdy napisałeś lub skompilowałeś program. Obecny sprzęt i systemy operacyjne nie mogą używać wielu rdzeni w celu przyspieszenia programu jednowątkowego.
Powiązane: W jaki sposób pojedynczy wątek działa na wielu rdzeniach? : odpowiedź: nie. Istnieją jednak inne rodzaje paralelizmu, takie jak paralelizm na poziomie instrukcji, który pojedynczy rdzeń procesora znajduje i wykorzystuje do uruchomienia jednego wątku szybciej niż jednej instrukcji na raz.
Moja odpowiedź na to pytanie dotyczy niektórych szczegółów, w jaki sposób współczesne procesory znajdują i wykorzystują drobnoziarnisty paralelizm na poziomie instrukcji. (Głównie koncentruje się na x86). To tylko część tego, jak działają normalne procesory, mając wiele instrukcji w locie, i nie jest to coś, co musisz specjalnie włączyć. (Istnieją liczniki wydajności, które pozwalają zobaczyć, ile instrukcji na zegar procesor udało się uruchomić podczas wykonywania programu lub innych środków.)
Należy pamiętać, że RPi3 używa rdzeni procesora ARM Cortex-A53 . Każdy rdzeń jest superskalarny o szerokości 2 (2 instrukcje na zegar, jak pozwala ILP), ale nie może zmienić kolejności instrukcji, aby znaleźć więcej równoległości na poziomie instrukcji i ukryć opóźnienia.
Mimo to procesor jest przetwarzany potokowo, więc łączna liczba instrukcji w locie (od pobierania i dekodowania aż do etapu zapisu zwrotnego na końcu potoku) jest znacząca. Gdy zależności danych nie ograniczają rzeczy, na każdym etapie potoku, na którym pracuje procesor, mogą znajdować się 2 instrukcje, z przepustowością 2 instrukcji na zegar. (To właśnie oznacza 2-szeroki.)
Nie może wykonywać instrukcji poza kolejnością, ale przy starannym porządkowaniu instrukcji (zwykle przez kompilator) nadal może ukryć opóźnienie instrukcji, która wymaga wielu cykli, aby jej wyjście było gotowe. (np. obciążenie, nawet jeśli trafi do pamięci podręcznej lub zwielokrotnienie zajmie wiele cykli, w porównaniu z dodawaniem gotowym do następnego cyklu). Sztuką jest uporządkowanie instrukcji asm, aby istniało wiele niezależnych instrukcji między tą, która daje wynik, a tą, która go wykorzystuje.
Posiadanie statycznego harmonogramu oprogramowania (kompilatora) jest bardziej kruche niż posiadanie sprzętu, który może wewnętrznie zmieniać kolejność, zachowując złudzenie działania w kolejności programów. Kompilatorom bardzo trudno jest wykonać tak dobrą robotę, jak nawet małe okno poza kolejnością do zamawiania instrukcji, ponieważ błędy w pamięci podręcznej są nieprzewidywalne i trudno analizować łańcuchy zależności między wywołaniami funkcji w czasie kompilacji. Liczba rejestrów jest ograniczona bez sprzętowej zmiany nazw rejestrów.
Wszystko to zapewnia niewielki komfort, gdy Twój kod działa wolniej niż chcesz. Pewnie, że pod maską jest dużo fajnych rzeczy w Cortex-A53, ale jest więcej fajnych rzeczy pod maską w Cortex-A57 (jak wykonanie poza kolejnością do 3 instrukcji na zegar), a nawet więcej w duży procesor x86, taki jak Skylake (nie wspominając o różnicach prędkości zegara).
Cortex-A53 jest dość fantastyczny w porównaniu do https://en.wikipedia.org/wiki/Classic_RISC_pipeline jak oryginalne MIPS, o których dowiesz się w klasie architektury komputerowej, ale według współczesnych standardów jest dość niskiej klasy.