Korzystam z systemu Windows 10 (1607) na procesorze Intel Xeon E3-1231v3 (Haswell, 4 rdzenie fizyczne, 8 rdzeni logicznych ).
Kiedy po raz pierwszy zainstalowałem system Windows 7 na tym komputerze, zauważyłem, że cztery z ośmiu rdzeni logicznych były zaparkowane, dopóki aplikacja nie wymagała więcej niż 4 wątków. Za pomocą monitora zasobów Windows można sprawdzić, czy rdzenie są zaparkowane, czy nie ( przykład ). O ile rozumiem, jest to ważna technika utrzymywania równowagi wątków w rdzeniach fizycznych, jak wyjaśniono na stronie internetowej Microsoft : „ Algorytm Core Parking i infrastruktura są również wykorzystywane do równoważenia wydajności procesorów między procesorami logicznymi w systemach klienckich Windows 7 z procesory, które zawierają technologię Intel Hyper-Threading ”.
Jednak po uaktualnieniu do systemu Windows 10 zauważyłem, że nie ma parkingu podstawowego. Wszystkie rdzenie logiczne są aktywne przez cały czas, a po uruchomieniu aplikacji przy użyciu mniej niż czterech wątków można zobaczyć, jak program planujący równo rozdziela je na wszystkie logiczne rdzenie procesora. Pracownicy Microsoft potwierdzili, że Core Parking jest wyłączony w Windows 10 .
Ale zastanawiam się dlaczego? Jaki był tego powód? Czy jest zamiennik, a jeśli tak, jak to wygląda? Czy Microsoft wdrożył nową strategię planowania, która sprawiła, że parkowanie rdzeni stało się przestarzałe?
Dodatek:
Oto przykład, w jaki sposób Core Core Parking wprowadzony w Windows 7 może poprawić wydajność (w porównaniu do Visty, która nie miała jeszcze funkcji Core Parking). Widać, że w systemie Vista HT (Hyper Threading) szkodzi wydajności, podczas gdy w systemie Windows 7 nie:
( źródło )
Próbowałem włączyć Core Parking, jak wspomniano tutaj , ale zauważyłem, że algorytm Core Parking nie jest już świadomy Hyper Threading. Zaparkował rdzenie 4,5,6,7, podczas gdy powinien mieć zaparkowany rdzeń 1,3,5,7, aby uniknąć przypisania wątków do tego samego rdzenia fizycznego. Windows wylicza rdzenie w taki sposób, że dwa kolejne wskaźniki należą do tego samego rdzenia fizycznego. Bardzo dziwny. Wygląda na to, że Microsoft całkowicie to popsuł. I nikt nie zauważył ...
Ponadto wykonałem testy wydajności procesora, używając dokładnie 4 wątków.
Powinowactwo procesora ustawione na wszystkie rdzenie (Windows defualt):
Średni czas pracy: 17.094498, odchylenie standardowe: 2.472625
Powinowactwo procesora ustawione na każdym innym rdzeniu (aby działało na różnych rdzeniach fizycznych, najlepsze możliwe planowanie):
Średni czas pracy: 15.014045, odchylenie standardowe: 1.302473
Powinowactwo procesora ustawione na najgorsze możliwe planowanie (cztery rdzenie logiczne na dwóch rdzeniach fizycznych):
Średni czas pracy: 20,811493, odchylenie standardowe: 1,405621
Więc nie jest różnica wydajności. I możesz zobaczyć, że planowanie deficytu w systemie Windows plasuje się pomiędzy najlepszym i najgorszym możliwym, ponieważ spodziewalibyśmy się, że stanie się tak w przypadku harmonogramu świadomego bez hipertekstu. Jednak, jak wskazano w komentarzach, mogą być za to odpowiedzialne inne przyczyny, takie jak mniejsza liczba przełączeń kontekstu, wnioskowanie przez aplikacje monitorujące itp. Więc nadal nie mamy ostatecznej odpowiedzi.
Kod źródłowy mojego testu porównawczego:
#include <stdlib.h>
#include <Windows.h>
#include <math.h>
double runBenchmark(int num_cores) {
int size = 1000;
double** source = new double*[size];
for (int x = 0; x < size; x++) {
source[x] = new double[size];
}
double** target = new double*[size * 2];
for (int x = 0; x < size * 2; x++) {
target[x] = new double[size * 2];
}
#pragma omp parallel for num_threads(num_cores)
for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) {
source[y][x] = rand();
}
}
#pragma omp parallel for num_threads(num_cores)
for (int x = 0; x < size-1; x++) {
for (int y = 0; y < size-1; y++) {
target[x * 2][y * 2] = 0.25 * (source[x][y] + source[x + 1][y] + source[x][y + 1] + source[x + 1][y + 1]);
}
}
double result = target[rand() % size][rand() % size];
for (int x = 0; x < size * 2; x++) delete[] target[x];
for (int x = 0; x < size; x++) delete[] source[x];
delete[] target;
delete[] source;
return result;
}
int main(int argc, char** argv)
{
int num_cores = 4;
system("pause"); // So we can set cpu affinity before the benchmark starts
const int iters = 1000;
double avgElapsedTime = 0.0;
double elapsedTimes[iters];
for (int i = 0; i < iters; i++) {
LARGE_INTEGER frequency;
LARGE_INTEGER t1, t2;
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&t1);
runBenchmark(num_cores);
QueryPerformanceCounter(&t2);
elapsedTimes[i] = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
avgElapsedTime += elapsedTimes[i];
}
avgElapsedTime = avgElapsedTime / iters;
double variance = 0;
for (int i = 0; i < iters; i++) {
variance += (elapsedTimes[i] - avgElapsedTime) * (elapsedTimes[i] - avgElapsedTime);
}
variance = sqrt(variance / iters);
printf("Average running time: %f, standard deviation: %f", avgElapsedTime, variance);
return 0;
}
Odpowiedzi:
Huh, mógłbym opowiedzieć ci historię, ale nienawidzisz jej, a ja nienawidzę pisać :-)
Krótka wersja - Win10 spieprzył wszystko, co mógł, i jest w ciągłym stanie głodujących rdzeni z powodu problemu systemowego znanego jako nadmierna subskrypcja procesora (zbyt wiele wątków, nikt nigdy nie może ich serwisować, coś dusi się w dowolnym momencie, na zawsze). Dlatego desperacko potrzebuje tych fałszywych procesorów, skraca podstawowy zegar harmonogramu do 1 ms i nie może pozwolić ci nic parkować. Spaliłoby to system. Otwórz Process Explorer i dodaj liczbę wątków, teraz zrób matematykę :-)
Interfejs API zestawów procesorów został wprowadzony, aby dać przynajmniej szansę walki tym, którzy znają i mają czas na napisanie kodu do walki z bestią. Możesz de facto zaparkować fałszywe procesory, umieszczając je w zestawie procesorów, którego nikomu nie dasz, i utwórz domyślny zestaw, aby wyrzucić go do piranii. Ale nie możesz tego zrobić na skryptach klienta (technicznie rzecz biorąc, nie będzie to honorowane), ponieważ jądro przejdzie w stan paniki i albo całkowicie zignoruje zestawy procesorów, albo niektóre inne rzeczy zaczną się zawieszać. Musi bronić integralności systemu za wszelką cenę.
Cały ten stan rzeczy jest z reguły tabu, ponieważ wymagałoby to poważnych przeróbek i unicestwienia liczby niepoważnych wątków i przyznania się do pomyłki. Hyperthreads faktycznie muszą zostać trwale wyłączone (nagrzewają rdzenie pod rzeczywistym obciążeniem, obniżają wydajność i destabilizują HTM - główny powód, dla którego nigdy nie stał się głównym nurtem). Duże sklepy SQL Server robią to jako pierwszy krok konfiguracji, podobnie jak Azure. Bing nie jest, działają serwery z de facto konfiguracją klienta, ponieważ będą potrzebować znacznie więcej rdzeni, aby odważyć się na zmianę. Problem dotyczył serwera 2016.
SQL Server jest jedynym prawdziwym użytkownikiem zestawów procesorów (jak zwykle :-), 99% doskonałych rzeczy w Win zawsze było zrobionych tylko dla SQL Server, zaczynając od super wydajnej obsługi plików mapowanych w pamięci, które zabijają ludzi pochodzących z Linuksa od czasu przyjmują inną semantykę).
Aby grać z tym bezpiecznie, potrzebujesz 16 rdzeni min dla skrzynki klienta, 32 dla serwera (to faktycznie robi coś prawdziwego :-) Musisz ustawić co najmniej 4 rdzenie w zestawie domyślnym, aby jądro i usługi systemowe ledwo mogły oddychać ale nadal jest to tylko dwurdzeniowy odpowiednik laptopa (wciąż masz wieczne duszenie), co oznacza 6-8, aby system mógł oddychać poprawnie.
Win10 potrzebuje 4 rdzeni i 16 GB, aby ledwo oddychać. Laptopy uciekają z 2 rdzeniami i 2 fałszywymi „procesorami”, jeśli nie ma nic do zrobienia, ponieważ ich zwykła dystrybucja pracy jest taka, że zawsze jest wystarczająco dużo rzeczy, które muszą czekać (długa kolejka na memaloc „bardzo pomaga” :-) .
To nadal nie pomoże ci w OpenMP (ani w żadnej automatycznej równoległości), chyba że masz sposób na to, aby wyraźnie użyć zestawu procesorów (poszczególne wątki należy przypisać do zestawu procesorów) i nic więcej. Nadal potrzebujesz również zestawu koligacji procesów, jest to warunek wstępny dla zestawów procesorów.
Serwer 2k8 był ostatnim dobrym (tak, to znaczy także Win7 :-). Ludzie ładowali masowo TB w 10 minut wraz z nim i SQL Server. Teraz ludzie chwalą się, czy potrafią załadować go w ciągu godziny - pod Linuksem :-) Tak więc są szanse, że stan rzeczy nie jest o wiele lepszy „tam”. Linux miał zestawy procesorów na długo przed Win.
źródło