6

Я использую Windows 10 (1607) на процессоре Intel Xeon E3-1231v3 (Haswell, 4 физических ядра, 8 логических ядер).

Когда я впервые установил Windows 7 на эту машину, я заметил, что четыре из восьми логических ядер были припаркованы, пока приложению не потребовалось более 4 потоков. С помощью монитора ресурсов Windows можно проверить, припаркованы ли ядра или нет (пример). Насколько я понимаю, это важная техника для поддержания баланса потоков между физическими ядрами, как объясняется на веб-сайте Microsoft: « Алгоритм и инфраструктура парковки ядра также используются для балансировки производительности процессора между логическими процессорами в клиентских системах Windows 7 с помощью процессоры с технологией Intel Hyper-Threading ».

Однако после обновления до Windows 10 я заметил, что нет базовой парковки. Все логические ядра активны все время, и когда вы запускаете приложение, используя менее четырех потоков, вы можете увидеть, как планировщик равномерно распределяет их по всем логическим ядрам процессора. Сотрудники Microsoft подтвердили, что базовая парковка отключена в Windows 10.

Но мне интересно, почему? Какова была причина этого? Есть ли замена и если да, то как это выглядит? Разработала ли Microsoft новую стратегию планировщика, которая сделала парковку ядра устаревшей?


Приложение:

Вот пример того, как базовая парковка, представленная в Windows 7, может повысить производительность (по сравнению с Vista, у которой пока нет базовой парковки). Вы можете видеть, что в Vista HT (Hyper Threading) снижает производительность, а в Windows 7 - нет:

(источник)

Я попытался включить Core Parking, как упоминалось здесь, но я заметил, что алгоритм Core Parking больше не поддерживает технологию Hyper Threading. Он припарковал ядра 4,5,6,7, в то время как он должен был припарковать ядра 1,3,5,7, чтобы избежать назначения потоков одному и тому же физическому ядру. Windows перечисляет ядра таким образом, что два последовательных индекса принадлежат одному физическому ядру. Очень странно. Кажется, Microsoft все испортила в корне. И никто не заметил ...

Кроме того, я сделал несколько тестов процессора, используя ровно 4 потока.

Сродство к процессору установлено для всех ядер (Windows defualt):

Среднее время работы: 17.094498, стандартное отклонение: 2.472625

Привязка к ЦП устанавливается для каждого другого ядра (чтобы оно работало на разных физических ядрах, наилучшее планирование):

Среднее время работы: 15.014045, стандартное отклонение: 1.302473

Привязка ЦП установлена на худшее из возможных расписаний (четыре логических ядра на двух физических ядрах):

Среднее время работы: 20.811493, стандартное отклонение: 1.405621

Так что есть разница в производительности. И вы можете видеть, что планирование по умолчанию в Windows ранжируется между лучшим и наихудшим возможным планированием, как мы ожидаем, что это произойдет с планировщиком, не поддерживающим гиперпоточность. Однако, как указано в комментариях, могут быть и другие причины, такие как меньшее количество переключений контекста, логический вывод приложений и т.д. Таким образом, мы до сих пор не имеем однозначного ответа.

Исходный код для моего теста:

#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;
}

1 ответ1

-1

Да, я мог бы рассказать вам историю, но вы будете ненавидеть это, и я буду ненавидеть писать это :-)

Короткая версия - Win10 испортил все, что мог, и находится в постоянном состоянии голодающих ядер из-за системной проблемы, известной как переподписка процессора (слишком много потоков, никто не может их обслуживать, что-то задыхается в любой точке, навсегда). Вот почему они отчаянно нуждаются в этих поддельных процессорах, сокращают базовый таймер планировщика до 1 мс и не могут позволить вам парковаться. Это просто опалило бы систему. Откройте Process Explorer и добавьте количество потоков, теперь сделайте математику :-)

Был представлен API-интерфейс CPU Sets, чтобы дать хотя бы некоторый шанс для борьбы тем, кто знает и имеет время написать код для борьбы со зверем. Вы можете де-факто парковать поддельные процессоры, помещая их в набор процессоров, который вы никому не дадите, и создав набор по умолчанию для передачи его пираньям. Но вы не можете сделать это на клиентских sku-s (технически это может быть просто невозможно), так как ядро перейдет в состояние паники и либо полностью проигнорирует наборы процессоров, либо некоторые другие вещи начнут падать. Он должен защищать целостность системы любой ценой.

Все положение вещей в целом является табу, так как для этого потребуются серьезные переписки, и каждый выберет несерьезные темы и признает, что они все испортили. Гиперпотоки на самом деле должны быть постоянно отключены (они нагревают ядра при реальной нагрузке, ухудшают производительность и дестабилизируют HTM - основная причина, по которой он никогда не стал массовым). Большие магазины SQL Server делают это в качестве первого шага установки, как и Azure. Нет, они запускают серверы с де-факто настройкой клиента, так как им нужно было бы гораздо больше ядер, чтобы осмелиться переключиться. Проблема просочилась в Server 2016.

SQL Server является единственным реальным пользователем наборов ЦП (как обычно :-), 99% продвинутых возможностей Win всегда выполнялись только для SQL Server, начиная с суперэффективной обработки файлов с отображением в памяти, которая убивает людей, пришедших из Linux с тех пор они предполагают различную семантику).

Чтобы безопасно играть с этим, вам понадобится минимум 16 ядер для клиентского компьютера, 32 для сервера (что на самом деле делает что-то реальное :-) Вы должны установить как минимум 4 ядра по умолчанию, чтобы ядро и системные службы едва дышали. но это все равно всего лишь двухъядерный эквивалент ноутбука (у вас все еще есть постоянный удушье), что означает 6-8, чтобы позволить системе дышать правильно.

Win10 нужно 4 ядра и 16 ГБ, чтобы едва дышать. Ноутбуки обходятся без 2-х ядерных и 2-х фальшивых "процессоров", если не нужно ничего делать, так как их обычное распределение работы таково, что всегда есть достаточно вещей, которые все равно нужно ждать (длинная очередь на memaloc "очень помогает" :-),

Это все равно не поможет вам с OpenMP (или каким-либо автоматическим распараллеливанием), если у вас нет способа явно указать ему использовать ваш набор ЦП (отдельные потоки должны быть назначены для набора ЦП) и ничего больше. Вам все еще нужно установить соответствие процессов, это предварительное условие для наборов процессоров.

Сервер 2k8 был последним хорошим (да, это также означает и Win7 :-). Люди массово загружали ТБ за 10 минут им и SQL Server. Теперь люди хвастаются, что могут загрузить его за один час - под Linux :-) Так что, скорее всего, положение "не там" тоже намного лучше. У Linux были CPU Sets задолго до Win.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .