Причина непроизвольного переключения контекста

Я пытаюсь профилировать многопоточную программу, которую я написал, на довольно большой машине (32 ядра, 256 ГБ ОЗУ). Я заметил, что между запусками производительность программы может сильно различаться (70-80%). Кажется, я не могу найти причину этого гигантского отклонения в производительности программы, но, анализируя результат использования утилиты «время» на большом количестве запусков, я заметил, что число непроизвольных переключений контекста сильно коррелирует с производительность программы (очевидно, что меньшее количество переключений контекста приводит к повышению производительности и наоборот).

Есть ли хороший способ определить, что вызывает это переключение контекста? Если я смогу обнаружить виновника, то, возможно, я попытаюсь решить проблему. Однако у меня есть несколько особых ограничений на инструменты, которые я могу использовать. Во-первых, у меня нет привилегий root на этой машине, поэтому все инструменты, требующие таких привилегий, отсутствуют. Во-вторых, это довольно старое ядро ​​(RHEL5, ядро ​​2.6.18), поэтому некоторые стандартные вещи для perf-event могут отсутствовать. Во всяком случае, любые предложения о том, как глубже изучить причину такого переключения контекста, будут с благодарностью.

Обновить: Я решил протестировать свою программу на другом (и меньшем) компьютере. Другая машина представляет собой 4-ядерный (с гипертхедом) модуль linux с 8 ГБ ОЗУ и гораздо более новое ядро ​​- 3.2.0 против 2.6.18 на другой машине. На новой машине я не могу воспроизвести бимодальный профиль производительности. Это приводит меня к мысли, что проблема связана либо с аппаратной проблемой (как было предложено в комментариях), либо с особенно патологическим случаем на уровне ядра, который с тех пор был исправлен. Моя текущая лучшая гипотеза заключается в том, что это может быть результатом того, что на новой машине есть ядро ​​с полностью честным планировщиком (CFS), а на старой машине нет. Есть ли способ проверить эту гипотезу (сказать новой машине использовать другой / более старый планировщик) без необходимости перекомпилировать древнюю версию ядра для новой машины?

9

Решение

Вы упомянули, что есть 32 ядра, но каково точное расположение оборудования? Например. сколько пакетов у машины, сколько ядер, как кеш распределяется и т. д. Для обмена такого рода информацией мне лично нравится делиться выводом likwid-topology -g,

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

Для закрепления (a.k.a. сродство) вы можете использовать явные вызовы Pthread или попробовать другой инструмент из набора Likwid под названием likwid-pin — увидеть Вот.

Если это не дает согласованных результатов, запустите хороший профилировщик (например, Intel VTune) для своей рабочей нагрузки, чтобы убедиться, что вы выполняете более быстрый и медленный прогон, а затем сравниваете результаты. В VTune вы можете использовать функцию сравнения, которая показывает два профиля рядом.

6

Другие решения

Я считаю, что ваша проблема на самом деле является вопросом планирования.

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

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

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

Я бы посоветовал вам спросить вашего администратора, с какими инструментами вы можете рассчитывать, чтобы вы могли правильно профилировать и назначать планирование потоков.

1

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

Проблема в том, что в системе Linux слишком много факторов (любого ядра, независимо от используемого планировщика), которые влияют на производительность приложения. Он начинается с рандомизации адресов и заканчивается микроскопическими различиями во времени, что приводит к огромным задержкам переключения контекста между процессами.

Linux не является системой реального времени. Он просто пытается быть максимально эффективным в среднем случае.

Существует несколько способов минимизировать разницу в производительности:

Уменьшите количество потоков до необходимого минимума. Не разбивайте различные аспекты вашей проблемы на потоки. Просто разделите на потоки, когда это действительно необходимо, например, для загрузки процессоров с независимыми (!) Заданиями по обработке чисел. Постарайтесь выполнить как можно больше причинно-следственной работы в одном потоке. Ваши темы должны требовать как можно меньше общения друг с другом. В частности, у вас не должно быть шаблонов запросов / ответов между потоками, в которых задержка складывается.

Предположим, ваша ОС может делать только около 1000 переключений контекста между потоками / процессами в секунду. Это означает пару 100 транзакций запрос / ответ в секунду. Если вы выполняете тестирование в Linux и обнаруживаете, что можете сделать гораздо больше, игнорируйте это.

Попробуйте уменьшить объем памяти важных данных. Распределенные данные имеют тенденцию разрушать кэш с очень тонким и трудно объяснимым влиянием на производительность.

1

Вы можете отследить источник переключений контекста в ядре, используя ftrace (используя трассировщик sched_switch). Кроме того, используя перфорация может помочь вам сузить другие показатели (ошибки в кэше и т. д.).

Как меняется изменчивость производительности при увеличении вашей программы с 1 потока до 32 (и, возможно, даже выше)?

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

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

Вы можете захотеть использовать профилировщик, например, gprof. Это может дать вам представление о (потенциальном) узком месте. Например, если вы ожидаете системный вызов write или что-то в этом роде.

Вот несколько статей, которые могут помочь вызвать идею или две:

http://halobates.de/lk09-scalability.pdf

http://pdos.csail.mit.edu/papers/linux:osdi10.pdf

Дополнительный источник: Почему одно невольное переключение контекста в секунду?

1

В многопоточной программе присоедините поток к определенному номеру ЦП и проверьте, видите ли вы улучшение производительности.

0

Лучше всего делать ставку на перепланирование, используя Kernel Profiler / logger. Ftrace. Это должно показать вам, какие потоки вытесняются другими потоками. К сожалению, обработчики прерываний в нижней половине не помечены должным образом, поэтому может быть трудно их расшифровать.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector