Как связать потоки с ядрами с заранее определенными объектами пула памяти? (80-ядерная архитектура Nehalem 2Tb RAM)
Я столкнулся с незначительной проблемой HPC после запуска некоторых тестов в архитектуре nehalem 80core (160HT) с DRAM 2Tb:
Сервер с более чем двумя сокетами начинает много останавливаться (задержка), так как каждый поток начинает запрашивать информацию об объектах в "неправильном" сокете, то есть запросы идут из потока, который работает с некоторыми объектами в одном сокете для получения информации, которая на самом деле находится в DRAM на другом сокете.
Ядро появляется на 100%, хотя я знаю, что они ждут, когда удаленный сокет вернет запрос.
Поскольку большая часть кода выполняется асинхронно, гораздо проще переписать код, поэтому я могу просто анализировать сообщения из потоков на одном сокете, чтобы потоки были другими (без блокировки ожидания).
Кроме того, я хочу блокировать каждый поток в пулах памяти, поэтому я могу обновлять объекты, а не тратить время (~ 30%) на сборщик мусора.
Следовательно, вопрос:
Как связать потоки с ядрами с предопределенными объектами пула памяти в Python?
Немного больше контекста:
У Python нет проблем с запуском multicore, когда вы ставите ZeroMQ посередине и создаете искусство из передачи сообщений между пулом памяти, управляемым каждым ZMQworker. На ZMQ 8M msg/second это внутреннее обновление объектов занимает больше времени, чем трубопровод может быть заполнен. Все это описано здесь: http://zguide.zeromq.org/page:all#Chapter-Sockets-and-Patterns
Итак, с небольшим упрощением, я запускаю 80 ZMQworkerprocesses и 1 ZMQrouter и загружаю контекст с большим роем объектов (на самом деле 584 миллиона объектов).
Из этой "начальной точки" объекты должны взаимодействовать для завершения вычисления.
Это идея:
- Если "объект X" должен взаимодействовать с "объектом Y" и доступен в
локальный пул памяти в python-потоке, то взаимодействие
следует делать напрямую.
- Если "Объект Y" НЕ доступен в одном пуле, то я хочу, чтобы он
отправьте сообщение через ZMQrouter и позвольте маршрутизатору возвращать
ответ в какой-то более поздний момент времени. Моя архитектура не блокирует, так что то, что происходит в конкретном потоке python, продолжается, не дожидаясь ответа zmqRouters. Даже для объектов в одном и том же сокете, но в другом ядре, я предпочел бы НЕ взаимодействовать, поскольку я предпочитаю иметь чистые обмены сообщениями вместо того, чтобы иметь 2 потока, управляющих одним и тем же объектом памяти.
Для этого мне нужно знать:
- Как определить, какой сокет - данный процесс python (thread)
продолжается.
- как назначить пул памяти на этом конкретном сокете процессу python (некоторый предел malloc или аналогичный, чтобы сумма пулов памяти не пустила пул памяти из одного сокета в другой).
- Вещи, о которых я не думал.
Но я не могу найти ссылки в документах python о том, как это сделать и на google. Я должен искать неправильную вещь.
Update:
В отношении вопроса "зачем использовать ZeroMQ для архитектуры MPI?", пожалуйста, прочитайте поток: Распространение против MPI vs zeromq?, поскольку приложение, над которым я работаю, предназначенный для распределенного развертывания, хотя он протестирован на архитектуре, где MPI более подходит.
Обновление 2:
Относительно вопроса:
"Как связать потоки с ядрами с предопределенными пулами памяти в Python (3)" ответ находится в psutils:
>>> import psutil
>>> psutil.cpu_count()
4
>>> p = psutil.Process()
>>> p.cpu_affinity() # get
[0, 1, 2, 3]
>>> p.cpu_affinity([0]) # set; from now on, this process will run on CPU #0 only
>>> p.cpu_affinity()
[0]
>>>
>>> # reset affinity against all CPUs
>>> all_cpus = list(range(psutil.cpu_count()))
>>> p.cpu_affinity(all_cpus)
>>>
Работник может быть привязан к ядру, в котором NUMA может быть эффективно использована (найдите свой тип процессора, чтобы убедиться, что это NUMA-архитектура!)
Второй элемент - это определение пула памяти. Это можно сделать с помощью psutils или библиотека ресурсов:
Ответы
Ответ 1
Вы можете недооценить проблему, нет супер-простого способа выполнить то, что вы хотите. В качестве общего руководства вам необходимо работать на уровне операционной системы, чтобы настроить все так, как вы хотите. Вы хотите работать с так называемой "близостью к процессору" и "сродством к памяти", и вам нужно много думать о своей системной архитектуре, а также о вашей архитектуре программного обеспечения, чтобы все было в порядке. В реальном HPC названные "сродства" обычно обрабатываются библиотекой MPI, такой как Open MPI. Возможно, вы захотите рассмотреть возможность использования одного и позволить вашим различным процессам обрабатывать эту библиотеку MPI. Интерфейс между операционной системой, библиотекой MPI и Python может быть предоставлен пакетом mpi4py.
Вам также необходимо получить свою концепцию потоков и процессов и настройку ОС прямо. В то время как для планировщика времени процессора поток является задачей, которая должна быть запланирована, и поэтому теоретически может иметь индивидуальную близость, я знаю только маски близости для целых процессов, то есть для всех потоков в рамках одного процесса. Для управления доступом к памяти NUMA (неравномерный доступ к памяти) является ключевым словом справа, и вы можете захотеть просмотреть http://linuxmanpages.com/man8/numactl.8.php
В любом случае вам нужно прочитать статьи о теме сродства и, возможно, захотите начать чтение в Часто задаваемых вопросах о MPI в Open MPI:
http://www.open-mpi.de/faq/?category=tuning#paffinity-defs
Если вы хотите достичь своей цели, не используя библиотеку MPI, изучите пакеты util-linux
или schedutils
и numactl
вашего дистрибутива Linux, чтобы получить полезные инструменты командной строки, такие как taskset
, которые вы можете, например, вызов из Python, чтобы установить маски соответствия для определенных идентификаторов процесса.
В этой статье ярко описывается, как библиотека MPI может быть полезной с вашей проблемой:
http://blogs.cisco.com/performance/open-mpi-v1-5-processor-affinity-options/
Этот ответ SO описывает, как вы делите свою аппаратную архитектуру: fooobar.com/questions/446030/...
В общем, мне интересно, является ли машина, на которую вы подаете заявку, правильной для задачи или если вы, возможно, оптимизируетесь не на том конце. Если вы отправляете сообщения внутри на одном компьютере и нажимаете ограничения пропускной способности памяти, я не уверен, что ZMQ (через TCP/IP, правильно?) Является правильным инструментом для выполнения обмена сообщениями. Возвращаясь к MPI, интерфейс передачи сообщений для приложений HPC...
Ответ 2
Просто интересно, не может ли это быть связано с использованием удаленных объектов python - это может стоить исследования, но, к сожалению, у меня нет доступа к такому оборудованию.
Как объясняется в документации, в то время как pyro часто используется для распространения работы на нескольких компьютерах в сети, он также может использоваться для обмена обработкой между ядра на одной машине.
На более низком уровне Pyro - это всего лишь форма межпроцессного общения. Поэтому везде, где вы могли бы использовать более примитивную форму IPC (например, простые сокеты TCP/IP) между компонентами Python, вы могли бы вместо этого использовать Pyro.
В то время как pyro может добавить некоторые накладные расходы, он может ускорить работу и сделать вещи более удобными.