Multicore + Hyperthreading - как распределяются потоки?

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

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

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

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


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

11.12.2008 18:07:22
Я просто хотел бы прокомментировать, что оптимальной политикой не всегда является запуск двух задач на разных ядрах; например, если у вас есть две задачи, которые совместно используют память и выполняют много непересекающихся операций, запуск их на одном и том же ядре может обеспечить более высокую производительность, поскольку сокращение кеш-памяти компенсирует немного более медленное время выполнения из-за необходимости иногда использовать процессор совместно (помните, в этом сценарии оба потока обычно работают параллельно даже на одном ядре, потому что они используют разные логические блоки).
Borealid 28.07.2010 22:47:21
Точно так же, как к сведению: если вы ищете грубую производительность, вы можете отключить гиперпоточность. Если, конечно, Intel наконец-то не сделала это хорошо. В прошлом (последнее, что я измерял, было на 2x процессоре P4 Xeon с гиперпоточностью (в результате чего 4 логических процессора для ОС), чистая производительность запуска 4 вычислительно интенсивных потоков с включенной гиперпоточностью приводила к более низкой чистой производительности, чем работа 2 потоков с гиперпоточностью. отключено. Очевидно, вы захотите проверить это сами с новейшим оборудованием - это может быть уже не так. Но, имейте в виду ...
Nathan Ernst 28.07.2010 23:06:17
Запуск потоков на одном и том же ядре именно то, что вы хотите, иногда. Например, если вы используете структуры данных без блокировки; когда у вас есть потоки на отдельных физических ядрах, обмен строкой кэша между ядрами снижает производительность.
user82238 27.04.2011 10:29:29
8 ОТВЕТОВ

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

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

2
11.12.2008 18:14:01
Хотя я никогда не любил оставлять вещи на усмотрение ОС, установка маски сходства потоков может отрицательно сказаться на производительности, если что-то будет загружено. Будет ли SetThreadIdealProcessor () лучшим вариантом?
NTDLS 21.02.2009 05:02:49

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

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

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

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

3
11.12.2008 20:18:30
Мне бы тоже хотелось в это верить, но немного доказательств было бы полезно.
Mark Ransom 11.12.2008 18:34:03
Доказательства чего? Создайте программу, которая запускает два потока в бесконечном цикле, и проверьте загрузку процессора. Вы обнаружите, что любая нормальная ОС назначает поток каждому ядру. Как вы думаете, это проблема, которую дизайнеры ОС не рассматривали? Конечно, нет. Это фундаментальная проблема, с которой должна справиться ОС .
jalf 11.12.2008 18:43:32
У меня нет такой системы для тестирования, иначе это неплохое предложение.
Mark Ransom 11.12.2008 18:51:18
jaff: все еще есть проблемы с производительностью, когда эти вещи переключаются и меняются контекстом. Мы видим это в национальных лабораториях, и все среды выполнения на параллельных машинах устанавливают сходство, чтобы процессы оставались на своих ядрах. Смотрите open-mpi.org/projects/plpa и мой ответ ниже.
Todd Gamblin 11.12.2008 19:26:51
@Jalf: вариант использования, который я имел в виду для «чрезвычайно», был структурами данных без блокировки. Вы видите, что производительность падает с обрыва, как только вы начинаете работать на отдельных физических ядрах - все строки кэша меняются, так как каждая запись CAS делает недействительной строку кэша для каждого другого физического ядра. Переключение контекста не проблема.
user82238 27.04.2011 11:27:28

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

1
11.12.2008 19:33:43

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

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

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

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

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

8
11.12.2008 19:04:10
Я не вижу, что происходит на моей машине. Бег stress -c 2на моем i5-2520M, это иногда графики (и сохраняет) два потока на HT сердечников 1 и 2, которые переводят в то же физическое ядро. Даже если система простаивает в противном случае. (Я нашел HT-> физическое ядро ​​с назначением egrep "processor|physical id|core id" /proc/cpuinfo | sed 's/^processor/\nprocessor/g'.)
nh2 2.04.2015 18:16:44
Я сделал эту проблему более конкретной с этим вопросом .
nh2 2.04.2015 20:41:06

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

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

5
11.12.2008 19:30:33

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

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

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

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

РЕДАКТИРОВАТЬ: я первоначально обнаружил некоторые различия в производительности с этими двумя конфигурациями. Однако я не смог их воспроизвести, поэтому отредактировал этот пост, чтобы отразить это. Я все еще находил интерес к нити интересным, поскольку это было не то, что я ожидал.

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
2.08.2010 22:32:27
Вы должны знать, что если вы используете диспетчер задач, чтобы посмотреть на использование, сам диспетчер задач может быть очень разрушительным для системы, потому что он обычно работает с повышенным приоритетом. Попробуйте настроить диспетчер задач на низкий приоритет и посмотрите, изменится ли шаблон.
Zan Lynx 28.07.2010 22:31:01
Можете ли вы поделиться временем выполнения в разных конфигурациях?
Mark Ransom 29.07.2010 00:31:43

Это очень хороший и актуальный вопрос. Как мы все знаем, гиперпоточное ядро ​​не является реальным процессором / ядром. Вместо этого это виртуальный процессор / ядро ​​(отныне я скажу ядро). Предполагается, что планировщик ЦП 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 Server и SQL Server

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

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

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

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

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

3
27.04.2011 10:19:24

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

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

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

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

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

0
6.01.2014 22:39:49
Я не спрашивал список причин, почему это не должно быть , я думаю, что мы все можем согласиться с этим. Я спрашивал, достаточно ли у ОС информации, чтобы предотвратить это, и достаточно ли умны планировщики, чтобы использовать эту информацию. Единственная часть вашего ответа, относящаяся к этому, - это упоминание ACPI.
Mark Ransom 6.01.2014 23:12:27
В моем ответе указывалось, почему планировщики «почему» и «как» ведут себя так же, как они, а также имеют ли они эту информацию. Вы ищете фрагменты кода из ядра в качестве ответа? Если так, то ядра Linux и Darwin имеют открытый исходный код ...
egur 7.01.2014 08:53:10