Multicore + Hyperthreading - как распределяются потоки? - PullRequest
25 голосов
/ 11 декабря 2008

Я читал обзор нового Intel Atom 330, где они отметили, что диспетчер задач показывает 4 ядра - два физических ядра, плюс еще два, смоделированные Hyperthreading.

Предположим, у вас есть программа с двумя потоками. Предположим также, что это единственные потоки, выполняющие какую-либо работу на ПК, все остальное бездействует. Какова вероятность того, что ОС поместит оба потока в одно и то же ядро? Это имеет огромное значение для пропускной способности программы.

Если ответом является что-то отличное от 0%, существуют ли какие-либо стратегии смягчения, кроме создания дополнительных потоков?

Я ожидаю, что будут разные ответы для Windows, Linux и Mac OS X.


Используя ответ sk в качестве фуража Google, а затем по ссылкам я нашел функцию GetLogicalProcessorInformation в Windows. В нем говорится о «логических процессорах, которые совместно используют ресурсы. Примером такого типа совместного использования ресурсов могут быть сценарии гиперпоточности». Это означает, что jalf является правильным, но это не совсем точный ответ.

Ответы [ 8 ]

8 голосов
/ 11 декабря 2008

В Linux достаточно сложный планировщик потоков, поддерживающий HT. Некоторые из его стратегий включают в себя:

Пассивная балансировка нагрузки: если на физическом процессоре выполняется более одной задачи, планировщик попытается запустить любые новые задачи на втором физическом процессоре.

Активная балансировка нагрузки: если есть 3 задачи, 2 на одном физическом процессоре и 1 на другом, когда второй физический процессор не работает, планировщик попытается перенести на него одну из задач.

Это делается при попытке сохранить сходство потоков, поскольку при переходе потока на другой физический процессор ему придется заново заполнять все уровни кэша из основной памяти, что приводит к остановке задачи.

Итак, чтобы ответить на ваш вопрос (по крайней мере, в Linux); при наличии двух потоков на двухъядерном гиперпоточном компьютере каждый поток будет работать на собственном физическом ядре.

5 голосов
/ 29 июля 2010

Я искал ответы на вопросы о планировании потоков в Windows, и у меня есть эмпирическая информация, которую я опубликую здесь для всех, кто может наткнуться на этот пост в будущем.

Я написал простую программу на C #, которая запускает два потока. На моей четырехъядерной Windows 7 я увидел удивительные результаты.

Когда я не принудительно устанавливал сходство, Windows распределяла рабочую нагрузку двух потоков по всем четырем ядрам. Есть две строки кода, которые закомментированы - одна, которая связывает поток с процессором, и другая, которая предлагает идеальный процессор. Это предложение, похоже, не дало никакого эффекта, но установка соответствия потоков заставила Windows запускать каждый поток на их собственном ядре.

Чтобы лучше увидеть результаты, скомпилируйте этот код с помощью свободно доступного компилятора csc.exe, поставляемого с клиентом .NET Framework 4.0, и запустите его на компьютере с несколькими ядрами. С закомментированной линией соответствия процессоров диспетчер задач показал, что потоки распределены по всем четырем ядрам, каждое из которых работает на 50%. При установленном сродстве два потока максимизировали два ядра до 100%, а два других бездействующих (что я ожидал увидеть до запуска этого теста).

EDIT: Первоначально я обнаружил некоторые различия в производительности с этими двумя конфигурациями. Однако я не смог воспроизвести их, поэтому отредактировал этот пост, чтобы отразить это. Я все еще находил интересным сродство к нитям, поскольку это было не то, что я ожидал.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

class Program
{
    [DllImport("kernel32")]
    static extern int GetCurrentThreadId();

    static void Main(string[] args)
    {
        Task task1 = Task.Factory.StartNew(() => ThreadFunc(1));
        Task task2 = Task.Factory.StartNew(() => ThreadFunc(2));
        Stopwatch time = Stopwatch.StartNew();
        Task.WaitAll(task1, task2);
        Console.WriteLine(time.Elapsed);
    }

    static void ThreadFunc(int cpu)
    {
        int cur = GetCurrentThreadId();
        var me = Process.GetCurrentProcess().Threads.Cast<ProcessThread>().Where(t => t.Id == cur).Single();
        //me.ProcessorAffinity = (IntPtr)cpu;     //using this line of code binds a thread to each core
        //me.IdealProcessor = cpu;                //seems to have no effect

        //do some CPU / memory bound work
        List<int> ls = new List<int>();
        ls.Add(10);
        for (int j = 1; j != 30000; ++j)
        {
            ls.Add((int)ls.Average());
        }
    }
}
5 голосов
/ 11 декабря 2008

Разумная ОС будет пытаться планировать вычислительно сложные задачи на своих собственных ядрах, но проблемы возникают, когда вы начинаете их переключать контекст. Современные ОС по-прежнему имеют тенденцию планировать вещи на ядрах, где нет времени на планирование, но это может привести к тому, что процессы в параллельных приложениях будут довольно свободно переключаться с ядра на ядро. Для параллельных приложений вы этого не хотите, потому что вы теряете данные, которые процесс мог использовать в кешах своего ядра. Для этого люди используют привязку к процессору, но в Linux семантика sched_affinity () может сильно различаться в зависимости от дистрибутива / ядра / поставщика и т. Д.

Если вы работаете в Linux, вы можете контролировать управление процессорами с помощью Portable Linux Processor Affinity Library (PLPA) . Это то, что OpenMPI использует для внутренних целей, чтобы убедиться, что процессы запланированы на их собственные ядра в многоядерных и многосетевых системах; они только что выделили модуль как самостоятельный проект. OpenMPI используется в Лос-Аламосе среди ряда других мест, так что это хорошо проверенный код. Я не уверен, что эквивалент под Windows.

3 голосов
/ 26 ноября 2010

Это очень хороший и актуальный вопрос. Как мы все знаем, гиперпоточное ядро ​​не является реальным процессором / ядром. Вместо этого это виртуальный процессор / ядро ​​(отныне я скажу ядро). Предполагается, что планировщик ЦП Windows, начиная с Windows XP, способен отличать сверхпоточные (виртуальные) ядра от реальных ядер. Тогда вы можете себе представить, что в этом совершенном мире он обращается с ними «просто правильно», и это не проблема. Вы были бы неправы.

Собственная рекомендация Microsoft по оптимизации сервера Windows 2008 BizTalk рекомендует отключить HyperThreading. Для меня это говорит о том, что обработка гиперпоточных ядер не идеальна, и иногда потоки получают временной интервал на гиперпоточном ядре и получают штраф (доля производительности реального ядра, 10% I '). Догадаюсь, а Microsoft догадается на 20-30%).

Ссылка на статью Microsoft, где предлагается отключить HyperThreading для повышения эффективности сервера: http://msdn.microsoft.com/en-us/library/cc615012(BTS.10).aspx

Это ВТОРАЯ рекомендация после обновления BIOS, поэтому они считают это важным. Они говорят:

ИЗ MICROSOFT:

" Отключить гиперпоточность на BizTalk Серверные и SQL Server компьютеры

Это критическая гиперпоточность выключен для BizTalk Server компьютеры. Это настройка BIOS, обычно встречается в процессоре настройки настройки BIOS. Гиперпоточность делает сервер кажется, есть больше процессоры / процессорные ядра, чем это на самом деле делает; Однако гипер-резьба Процессоры обычно обеспечивают между 20 и 30% производительности физический процессор / процессорное ядро. Когда BizTalk Server считает число процессоров, чтобы настроить его алгоритмы самонастройки; гиперпоточные процессоры вызывают эти корректировки должны быть перекошены, что является вредно для общей производительности. «

Теперь они говорят, что это происходит из-за того, что они отбрасывают алгоритмы самонастройки, но затем продолжают упоминать о проблемах конкуренции (предполагая, что это большая проблема планирования, по крайней мере для меня). Прочитайте это как хотите, но я думаю, что это говорит само за себя. HyperThreading была хорошей идеей, когда работали с однопроцессорными системами, но сейчас это просто сложность, которая может снизить производительность в этом многоядерном мире.

Вместо того, чтобы полностью отключить HyperThreading, вы можете использовать такие программы, как Process Lasso (бесплатно), чтобы устанавливать сродства ЦП по умолчанию для критических процессов, чтобы их потоки никогда не выделялись виртуальным ЦП.

Итак ... Я не думаю, что кто-то действительно знает, насколько хорошо Windows CPU Scheduler обрабатывает виртуальные процессоры, но я могу с уверенностью сказать, что XP справляется с этим хуже, и с тех пор они постепенно улучшают его , но это все еще не идеально. На самом деле, он НИКОГДА не может быть идеальным, потому что ОС не знает, какие потоки лучше всего разместить на этих более медленных виртуальных ядрах. В этом может быть проблема и почему Microsoft рекомендует отключить HyperThreading в серверных средах.

Также помните, что даже БЕЗ HyperThreading, существует проблема «перегиба ядра». Если вы можете сохранить поток в одном ядре, это хорошо, так как уменьшает штрафы за изменение ядра.

3 голосов
/ 11 декабря 2008

Вероятность того, что ОС не будет использовать столько физических ядер, сколько возможно, равна 0%. Ваша ОС не глупая. Его работа состоит в том, чтобы планировать все, и он прекрасно знает, какие ядра он имеет в наличии. Если он увидит два потока, интенсивно использующих процессор, он удостоверится, что они работают на двух физических ядрах.

Редактировать Просто чтобы немного проработать, для высокопроизводительных вещей, как только вы попадаете в MPI или другие серьезные структуры параллелизации, вы определенно хотите контролировать то, что работает на каждом ядре.

ОС предпримет своего рода попытку сделать все возможное для использования всех ядер, но у нее нет долгосрочной информации о том, что «этот поток будет работать очень долго», или что "у нас будет так много потоков, выполняющихся параллельно". Таким образом, он не может принимать правильные решения, что означает, что ваш поток будет время от времени назначаться новому ядру, что означает, что вы столкнетесь с промахами в кэше и тому подобным, что стоит немного времени. Для большинства целей это достаточно хорошо, и вы даже не заметите разницу в производительности. И это также играет хорошо с остальной системой, если это имеет значение. (В чьей-то настольной системе это, вероятно, довольно важно. В сетке с несколькими тысячами процессоров, выделенных для этой задачи, вы не особенно хотите играть хорошо, вы просто хотите использовать каждый доступный тактовый цикл).

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

2 голосов
/ 11 декабря 2008

Вы можете убедиться, что оба потока запланированы для одних и тех же исполнительных блоков, предоставив им привязку к процессору. Это можно сделать либо в Windows, либо в Unix, либо через API (чтобы программа могла запрашивать его), либо через административные интерфейсы (чтобы администратор мог установить это). Например. в WinXP вы можете использовать диспетчер задач, чтобы ограничить, на каких логических процессорах процесс может выполняться.

В противном случае планирование будет по существу случайным, и вы можете ожидать 25% использования на каждом логическом процессоре.

1 голос
/ 11 декабря 2008

Я не знаю о других платформах, но в случае с Intel, они публикуют много информации о потоке в своей Intel Software Network . У них также есть бесплатная новостная рассылка (Intel Software Dispatch), на которую можно подписаться по электронной почте, и в последнее время таких статей было много.

0 голосов
/ 07 января 2014

Вероятность того, что ОС отправит 2 активных потока на одно и то же ядро, составляет ноль , если только потоки не были привязаны к конкретному ядру (сходство потоков).

Причины этого в основном связаны с HW:

  • ОС (и ЦП) хотят использовать как можно меньше энергии, чтобы максимально эффективно выполнять задачи для перехода в состояние низкого энергопотребления как можно скорее.
  • Запуск всего на одном и том же ядре заставит его нагреваться намного быстрее. При патологических состояниях процессор может перегреться и снизить тактовую частоту охлаждения. Чрезмерное тепло также приводит к тому, что вентиляторы ЦП вращаются быстрее (например, ноутбуки) и создают больше шума.
  • Система на самом деле никогда не простаивает. ISR и DPC запускаются каждую мс (в большинстве современных ОС).
  • Снижение производительности из-за скачкообразного изменения потоков от ядра к ядру незначительно в 99,99% рабочих нагрузок.
  • Во всех современных процессорах кэш последнего уровня используется совместно, поэтому переключение ядер не так уж и плохо.
  • В системах с несколькими сокетами (Numa) ОС минимизирует переход от сокета к сокету, поэтому процесс остается «рядом» с контроллером памяти. Это сложная область при оптимизации для таких систем (десятки / сотни ядер).

Кстати, ОС знает топологию ЦП через ACPI - интерфейс, предоставляемый BIOS.

Подводя итог, все сводится к соображениям энергопотребления системы (срок службы батареи, счет за электроэнергию, шум от решения охлаждения).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...